<div dir="auto"><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Sat, Sep 5, 2020, 12:13 Tim Hudson <<a href="mailto:tjh@cryptsoft.com">tjh@cryptsoft.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div dir="ltr">On Sat, Sep 5, 2020 at 6:38 PM Nicola Tuveri <<a href="mailto:nic.tuv@gmail.com" target="_blank" rel="noreferrer">nic.tuv@gmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="auto">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.<br></div><div dir="auto">As such, explicitly passing non-NULL libctx and propquery, is likely to be an exceptional occurrence rather than the norm.</div></div></blockquote><div><br></div><div>And that is where we have a conceptual difference, the libctx is <b>always</b> 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.</div><div>Conceptually it is always required for the function to operate.</div><div><br></div><div>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.</div><div>We just happen to have a default-if-NULL.</div><div><br></div><div>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. </div><div>But it doesn't - we are coding in C.</div><div><br></div><div>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.</div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>Clearer?</div></div></div></blockquote></div><div dir="auto"><br></div><div dir="auto">It's not yet clear to me the distinction you are trying to make.</div><div dir="auto"><br></div><div dir="auto">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! </div><div dir="auto"><br></div><div dir="auto">It seems to me you are making a conceptual difference between</div><div dir="auto">- 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</div><div dir="auto">- 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</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">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).</div><div dir="auto"><br></div><div dir="auto">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.</div><div dir="auto">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.</div><div dir="auto"><br></div><div dir="auto">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.</div><div dir="auto">The signature of the function should be designed for consumer usability, and the conventional pattern there seems to be</div><div dir="auto">- required args</div><div dir="auto">- optional args</div><div dir="auto">- callback+cb_args</div><div dir="auto">and inside each group the "importance" factor should be the secondary sorting criteria. </div><div dir="auto"><br></div><div dir="auto">"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. </div><div dir="auto"><br></div><div dir="auto">But... going this way as a generalized approach, would bring us to the "add in the middle" scenario that we'd like to avoid. </div><div dir="auto">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".</div><div dir="auto"><br></div><div dir="auto">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?</div><div dir="auto"><br></div><div dir="auto">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)? </div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">Nicola</div><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
</blockquote></div></div>