Reordering new API's that have a libctx, propq

Richard Levitte levitte at openssl.org
Sat Sep 5 20:55:48 UTC 2020


Hi,

so...  "importance" quite obviously carries different meaning to
different people.  What I see below is the meaning "having the longest
life span" or possibly "being the biggest and most powerful resource".

I've a different interpretation of "importance".

Looking at EVP_XXX_fetch(), it's primary function is to get the caller
an implementation of an algorithm, so a pretty important input for it
to function is the name of that algorithm.  Of course, it also needs
to know where to go look and under what conditions (i.e. what properties
need to apply), but in terms of importance for this function to work,
I'd rank the algorithm name as the most important, it really can't do
anything of value without it.

With the in mind, the current (libctx, algoname, propq) argument order
is...  odd.
I don't quite see if there was a suggestion to have (libctx, propq,
algoname) as argument order; that's just plain weird in my mind.

Those were late evening thoughts, I'll get back when I'm mulled over
this a bit more.

Cheers,
Richard

On Sat, 05 Sep 2020 12:44:51 +0200,
Nicola Tuveri wrote:
> 
> 
> On Sat, Sep 5, 2020, 12:13 Tim Hudson <tjh at cryptsoft.com> wrote:
> 
>     On Sat, Sep 5, 2020 at 6:38 PM Nicola Tuveri <nic.tuv at gmail.com> wrote:
>    
>         In most (if not all) cases in our functions, both libctx and propquery are optional
>         arguments, as we have global defaults for them based on the loaded config file.
>         As such, explicitly passing non-NULL libctx and propquery, is likely to be an exceptional
>         occurrence rather than the norm.
> 
>     And that is where we have a conceptual difference, the libctx is always used. If it is
>     provided as a NULL parameter then it is a shortcut to make the call to get the default or to
>     get the already set one.
>     Conceptually it is always required for the function to operate.
>    
>     And the conceptual issue is actually important here - all of these functions require the
>     libctx to do their work - if it is not available then they are unable to do their work.
>     We just happen to have a default-if-NULL.
>    
>     If C offered the ability to default a parameter if not provided (and many languages offer
>     that) I would expect we would be using it. 
>     But it doesn't - we are coding in C.
>    
>     So it is really where-is-what-this-function-needs-coming-from that actually is the important
>     thing - the source of the information the function needs to make its choice.
>     It isn't which algorithm is being selected - the critical thing is from which pool of
>     algorithm implementations are we operating. The pool must be specified (this is C code), but
>     we have a default value.
>    
>     And that is why I think the conceptual approach here is getting confused by the arguments
>     appearing to be optional - conceptually they are not - we just have a defaulting mechanism and
>     that isn't the same conceptually as the arguments actually being optional.
>    
>     Clearer?
> 
> It's not yet clear to me the distinction you are trying to make.
> 
> I'll try to spell out what I extrapolated from your answer, and I apologize in advance if I am
> misunderstanding your argument, please be patient and correct me in that case so I can better
> understand your point! 
> 
> It seems to me you are making a conceptual difference between
> - a function that internally requires an instance of foo to work (and has a default if foo is
> given as NULL among the arguments); e.g libctx is necessary for a fetch, if a NULL libctx is given
> a mechanism is in place to retrieve the global default one
> - a function that internally uses an instance of foo only if a non-NULL one is passed as argument;
> e.g. bnctx, if the user provides it this is used by the callee and passed to its callee, if the
> user passes NULL the function creates a fresh one for itself and/or its callees
> 
> But as a consumer of the API that difference is not visible and probably not even interesting, as
> we are programming in C and passing pointers, there are certain arguments that are required and
> must be passed as valid pointers, others that appear optional because as a consumer of that API I
> can pass NULL and let the function internally default to a reasonable behavior (and whatever this
> "reasonable behavior" is — whether the first or the second case from above, or another one I did
> not list —, it's part of the documentation of that API).
> 
> IMHO, in the consumer POV, libctx and propq are optional arguments (even in C where optional or
> default arguments do not technically exist and the caller needs to always specify a value for each
> argument, which are always positional) in the sense that they can pass NULL as a value rather than
> a pointer to a fully instantiated object of the required type.
> Even more so given that, excluding a minority of cases, we can expect consumers of the APIs taking
> libctx and propq as arguments to pass NULL for both of them and rely on the openssl config
> mechanism.
> 
> So while I agree with Tim that sometime it is valuable to make a difference among the consequences
> of passing NULL as arguments in the context of one kind of function and another, I believe the
> place for that is the documentation not its signature.
> The signature of the function should be designed for consumer usability, and the conventional
> pattern there seems to be
> - required args
> - optional args
> - callback+cb_args
> and inside each group the "importance" factor should be the secondary sorting criteria. 
> 
> "importance" is probably going to be affected by the difference you are making (or my
> understanding of it): e.g. if a function took both libctx and bnctx, the fact that a valid
> pre-existing libctx is required to work (and a global already existing one will be retrieved in
> case none is given), while a fresh short-lived bnctx is going to be created only for the lifetime
> of the called function in case none is given seems to indicate that libctx is of vital importance
> for the API functionality, while bnctx is of minor relevance. 
> 
> But... going this way as a generalized approach, would bring us to the "add in the middle"
> scenario that we'd like to avoid. 
> I recognize that this is a point you already made in your original writeup, as the tendency of
> "add to the end" to naturally degrade into "add in the middle".
> 
> So, my question is: if "degradable add to the end" (where "degradable" only happens rarely and for
> good reasons) seems the one that in the end produces signatures matching (IMHO) the conventional
> usability patterns expected by consumers of the API, is it such a dramatic conclusion that we want
> to exclude it?
> 
> Or is your point that we are writing in C, all the arguments are positional, none is ever really
> optional, there is no difference between passing a `(void*) NULL` or a valid `(TYPE*) ptr` as the
> value of a `TYPE *` argument, so "importance" is the only remaining sorting criteria, hence
> (libctx, propq) are always the most important and should go to the beginning of the args list
> (with the exception of the `self/this` kind of argument that always goes first)? 
> 
> Nicola
> 
> 
-- 
Richard Levitte         levitte at openssl.org
OpenSSL Project         http://www.openssl.org/~levitte/


More information about the openssl-project mailing list