On 09/27/22 20:59, Eric Blake wrote:
On Tue, Sep 27, 2022 at 06:24:17PM +0200, Laszlo Ersek wrote:
> Considering "optional list" in particular, I see no
semantic difference
> between vec==NULL and vec[0]==NULL. If an optional list is expected,
> both should be tolerated; if a mandatory (non-empty) list is expected,
> both are invalid.
>
> Once we decided / documented what parameters were valid, I think the
> most practical way to enfoce mandatory parameters (in case they are
> taken by address) and mandatory (non-empty) lists would be with assert().
Your argument of multiplicity is interesting. Extrapolating it a bit
more, I think you are arguing that in Python,
h.connect_command([]) - error, since list must be non-empty
h.connect_command(None) - error should be same as [], rather than
complaining that 'None' is not a list type
h.opt_list_meta_context_queries([], func) - success, since empty list
makes sense
h.opt_list_meta_context_queries(None, func) - same effect (whereas in
my v3 patches, it complains that 'None' is not a list type)
Well, I don't know.
In C, where we represent the string list with a NULL-terminated
(char**), I really feel like there isn't a semantic difference between
vec==NULL and vec[0]==NULL. It's a very rough representation anyway.
But in Python and OCaml, where we can distinguish "None" from "[]",
and
"None" from "Some []" respectively, I'm not so sure myself. Python
and
OCaml seem to imbue the representation with more meaning / type
information than C does.
> (We should also make sure that NDEBUG is never defined -- some
parts of
> libnbd and nbdkit already "#undef NDEBUG"; I'd go farther and just
> forbid building libnbd and nbdkit without assertions. Assertions cost a
> few CPU cycles, and I don't expect nbdkit to be CPU-bound ever.
> Assertions are worth the CPU costs.)
We undef it during unit tests, but I don't know if we have been brave
enough to declare that we mandate that assertions remain live in the
library itself.
I think removing assertions from a library is the more courageous
option! :) Is it better to produce garbage (or to set up a real, but
long-distance crash) than to stop immediately, when we know something
has gone wrong?
I think the only alternative to live assertions is to code up some kind
of recovery in every possible spot. That's a lot of work. (I've heard
this argument wrt. kernel modules -- panicking the whole kernel due to
hardware misbehavior in a driver is frowned upon, to say the least. So
the kernel driver apparently needs to, at the least, disable itself
dynamically, when a device behaves out of spec. That's a lot of work.)
What projects consume libnbd primarily? I think in the context of a
virt-v2v / virt-p2v conversion, it's better for the conversion to crash
early, than to carry on with garbage data (for example).
So far, none of our list arguments have been optional, and none of
our
optional arguments have been lists. The addition of
nbd_opt_list_meta_context_queries, where it is often desirable to pass
an empty list of queries, may be the first case where we do want to
represent the queries as an optional list (in my v3 series, it was a
mandatory argument).
I'm out of ideas. I'd like to ask "can we get away with just modifying
the documentation, and let the user deal with undefined behavior
afterwards?"
But given python and ocaml, I don't think this is a good idea, because
those languages simply don't allow "undefined behavior" (definitely not
to the extent that C does). In other words, python and ocaml promise the
user so much more than C does that the python and ocaml bindings would
have to be *much* thicker (contain much more logic and checking) than
the C binding. I keep returning to my impression that the "thin" (?)
binding generation is a very leaky abstraction.
I apologize, I know that this is not constructive. I'm just out of ideas.
Laszlo