All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, "Jeff King" <peff@peff.net>,
	"Thomas Rast" <tr@thomasrast.ch>, "René Scharfe" <l.s.r@web.de>
Subject: Re: [PATCH 02/10] parse-options.[ch]: consistently use "enum parse_opt_flags"
Date: Wed, 29 Sep 2021 10:53:18 +0200	[thread overview]
Message-ID: <87mtnvvj3c.fsf@evledraar.gmail.com> (raw)
In-Reply-To: <xmqqilykgs2k.fsf@gitster.g>


On Tue, Sep 28 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> Use the "enum parse_opt_flags" instead of an "int flags" as arguments
>> to the various functions in parse-options.c. This will help to catch
>> cases where we're not handling cases in switch statements, and
>
> I am not sure about most part this change, and the claim the second
> sentence makes is certainly dubious.  Let's look at the first hunk:
>
>> diff --git a/parse-options.c b/parse-options.c
>> index 55c5821b08d..9dce8b7f8a8 100644
>> --- a/parse-options.c
>> +++ b/parse-options.c
>> @@ -481,7 +481,8 @@ static void parse_options_check(const struct option *opts)
>
>  static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
>  				  int argc, const char **argv, const char *prefix,
> -				  const struct option *options, int flags)
> +				  const struct option *options,
> +				  enum parse_opt_flags flags)
>  {
>  	ctx->argc = argc;
>  	ctx->argv = argv;
>  	if (!(flags & PARSE_OPT_ONE_SHOT)) {
>  		ctx->argc--;
>  		ctx->argv++;
>  	}
>  	ctx->total = ctx->argc;
>  	ctx->out   = argv;
>  	ctx->prefix = prefix;
>  	ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
>  	ctx->flags = flags;
>  	if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
>  	    (flags & PARSE_OPT_STOP_AT_NON_OPTION) &&
>  	    !(flags & PARSE_OPT_ONE_SHOT))
>  		BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
>  	if ((flags & PARSE_OPT_ONE_SHOT) &&
>  	    (flags & PARSE_OPT_KEEP_ARGV0))
>  		BUG("Can't keep argv0 if you don't have it");
>  	parse_options_check(options);
>  }
>  
> The "flags" parameter does not take a value that is an "enum" in the
> usual "enumeration" sense at all.  Even though parse_opt_flags
> defines 7 distinct "enum" values, each enumerated value is a small
> unsigned integer with only single bit set, the caller can throw a
> value that is not among these 7 by OR'ing them together.  We would
> not sensibly do
>
> 	switch (flags) {
> 	case PARSE_OPT_KEEP_UNKNOWN:
> 		...
>
> In general, I am not all that enthusiastic for such a(n) (ab)use of
> "enum" for bit patterns, much less than "enumerate all possible
> values to make sure compilers would help us catch missing logic".

I agree that it's not as nice as enums where the fields are mutually
exclusive, since those can be checked via "case" arms, and this is
"unchecked" bitfields.

So e.g. the bug I fixed in 01/10 would not be found by a compiler I have
access to (and I don't think one currently exists).

But I think this is perfectly good use of enums, we use this
enums-as-bitfields pattern in various other places,
e.g. builtin/rebase.c's "flags", the "commit_graph_write_flags",
"expire_reflog_flags" & "todo_item_flags", just to name a few from some
quick grepping.

One advantage is that integrates nicely with some wider C
tooling. E.g. before this series, starting "git stash show" under gdb
and inspecting flags:

    (gdb) p flags
    $1 = 9

And after:

    (gdb) p flags
    $1 = (PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN)

So the type information and bitfield-ness are retained.

Although you might argue that it leads you into a trap, as adding:

    flags |= PARSE_OPT_LASTARG_DEFAULT;

Will result in:

    (gdb) p flags
    $2 = (PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_NO_INTERNAL_HELP)

I.e. it decodes the enum based on the int value & its known labels, and
it just so happens that PARSE_OPT_LASTARG_DEFAULT has the same value as
PARSE_OPT_NO_INTERNAL_HELP in an unrelated enum.

> The "parse_opt_result" enum is the "right" kind of enumeration that
> I can stand behind fully.  The hunk related to that enum in this
> patch is quite reasonable and takes advantage of the fact that the
> enum is meant to be the enumeration of all possible values.
>
> Compared to it, parse_opt_flags and parse_opt_option_flags, not
> really.
>
> If we wanted to really clean up the latter two, perhaps we should
> define the bit (which *can* be made to a proper "here are the all
> possible values" enumeration), like this:
>
>     enum parse_opt_flags_bit {
> 	PARSE_OPT_KEEP_DASHDASH_BIT = 0,
>         PARSE_OPT_STOP_AT_NON_OPTION_BIT,
> 	PARSE_OPT_KEEP_ARGV0_BIT,
> 	...
> 	PARSE_OPT_SHELL_EVAL_BIT,
>     };
>
> and then update the users to use (1U << PARSE_OPT_$FLAG$_BIT), or
> drop the pretense that it is a good idea to use enum for bit pattern
> and use the CPP macro, i.e.
>
>     #define PARSE_OPT_KEEP_DASHDASH (1U<<0)
>     #define PARSE_OPT_STOP_AT_NON_OPTION (1U<<1)
>     ...
>     #define PARSE_OPT_SHELL_EVAL (1U<<6)
>
> to make it clear that we do not mean these are "enumeration of
> possible values".

I'm not sure what the former suggestion here buys us, but the latter
will drop the type information as noted above, i.e. you'll get a:

    (gdb) p flags
    $1 = 9

  reply	other threads:[~2021-09-29  9:15 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-28 13:14 [PATCH 00/10] fix bug, use existing enums Ævar Arnfjörð Bjarmason
2021-09-28 13:14 ` [PATCH 01/10] parse-options.h: move PARSE_OPT_SHELL_EVAL between enums Ævar Arnfjörð Bjarmason
2021-09-28 13:14 ` [PATCH 02/10] parse-options.[ch]: consistently use "enum parse_opt_flags" Ævar Arnfjörð Bjarmason
2021-09-29  0:10   ` Junio C Hamano
2021-09-29  8:53     ` Ævar Arnfjörð Bjarmason [this message]
2021-09-29 15:09       ` Junio C Hamano
2021-09-29 16:02   ` Junio C Hamano
2021-09-28 13:14 ` [PATCH 03/10] parse-options.[ch]: consistently use "enum parse_opt_result" Ævar Arnfjörð Bjarmason
2021-09-29  0:12   ` Junio C Hamano
2021-09-28 13:14 ` [PATCH 04/10] parse-options.c: use exhaustive "case" arms for "enum parse_opt_type" Ævar Arnfjörð Bjarmason
2021-09-29  0:20   ` Junio C Hamano
2021-09-29  8:48     ` Ævar Arnfjörð Bjarmason
2021-09-29 15:14       ` Junio C Hamano
2021-09-28 13:14 ` [PATCH 05/10] parse-options.h: make the "flags" in "struct option" an enum Ævar Arnfjörð Bjarmason
2021-09-29  0:22   ` Junio C Hamano
2021-09-28 13:14 ` [PATCH 06/10] parse-options.c: move optname() earlier in the file Ævar Arnfjörð Bjarmason
2021-09-28 13:14 ` [PATCH 07/10] commit-graph: stop using optname() Ævar Arnfjörð Bjarmason
2021-09-29 17:28   ` Taylor Blau
2021-10-01 13:16     ` Ævar Arnfjörð Bjarmason
2021-09-28 13:14 ` [PATCH 08/10] parse-options.[ch]: make opt{bug,name}() "static" Ævar Arnfjörð Bjarmason
2021-09-28 13:14 ` [PATCH 09/10] parse-options tests: test optname() output Ævar Arnfjörð Bjarmason
2021-09-28 13:14 ` [PATCH 10/10] parse-options: change OPT_{SHORT,UNSET} to an enum Ævar Arnfjörð Bjarmason
2021-09-29  0:50   ` Junio C Hamano
2021-10-01 14:29 ` [PATCH v2 00/11] fix bug, use existing enums Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 01/11] parse-options.h: move PARSE_OPT_SHELL_EVAL between enums Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 02/11] parse-options.[ch]: consistently use "enum parse_opt_flags" Ævar Arnfjörð Bjarmason
2021-10-01 21:45     ` Junio C Hamano
2021-10-01 14:29   ` [PATCH v2 03/11] parse-options.[ch]: consistently use "enum parse_opt_result" Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 04/11] parse-options.c: use exhaustive "case" arms for " Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 05/11] parse-options.c: use exhaustive "case" arms for "enum parse_opt_type" Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 06/11] parse-options.h: make the "flags" in "struct option" an enum Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 07/11] parse-options.c: move optname() earlier in the file Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 08/11] commit-graph: stop using optname() Ævar Arnfjörð Bjarmason
2021-10-01 17:12     ` René Scharfe
2021-10-01 14:29   ` [PATCH v2 09/11] parse-options.[ch]: make opt{bug,name}() "static" Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 10/11] parse-options tests: test optname() output Ævar Arnfjörð Bjarmason
2021-10-01 14:29   ` [PATCH v2 11/11] parse-options: change OPT_{SHORT,UNSET} to an enum Ævar Arnfjörð Bjarmason
2021-10-01 21:52   ` [PATCH v2 00/11] fix bug, use existing enums Junio C Hamano
2021-10-01 21:53     ` Junio C Hamano
2021-10-08 19:07   ` [PATCH v3 00/10] fix bug, use more enums Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 01/10] parse-options.h: move PARSE_OPT_SHELL_EVAL between enums Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 02/10] parse-options.[ch]: consistently use "enum parse_opt_flags" Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 03/10] parse-options.[ch]: consistently use "enum parse_opt_result" Ævar Arnfjörð Bjarmason
2021-11-06 19:11       ` SZEDER Gábor
2021-11-06 21:31         ` Ævar Arnfjörð Bjarmason
2021-11-09 11:04           ` [PATCH 0/2] parse-options.[ch]: enum fixup & enum nit Ævar Arnfjörð Bjarmason
2021-11-09 11:04             ` [PATCH 1/2] parse-options.[ch]: revert use of "enum" for parse_options() Ævar Arnfjörð Bjarmason
2021-11-09 17:45               ` Junio C Hamano
2021-11-09 11:04             ` [PATCH 2/2] parse-options.c: use "enum parse_opt_result" for parse_nodash_opt() Ævar Arnfjörð Bjarmason
2021-11-09 17:58               ` Junio C Hamano
2021-11-09 23:18                 ` Ævar Arnfjörð Bjarmason
2021-11-09 23:37                   ` Junio C Hamano
2021-11-10  1:27                   ` [PATCH v2] " Ævar Arnfjörð Bjarmason
2021-11-11  2:01                     ` Junio C Hamano
2021-10-08 19:07     ` [PATCH v3 04/10] parse-options.c: use exhaustive "case" arms for "enum parse_opt_result" Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 05/10] parse-options.h: make the "flags" in "struct option" an enum Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 06/10] parse-options.c: move optname() earlier in the file Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 07/10] commit-graph: stop using optname() Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 08/10] parse-options.[ch]: make opt{bug,name}() "static" Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 09/10] parse-options tests: test optname() output Ævar Arnfjörð Bjarmason
2021-10-08 19:07     ` [PATCH v3 10/10] parse-options: change OPT_{SHORT,UNSET} to an enum Ævar Arnfjörð Bjarmason

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87mtnvvj3c.fsf@evledraar.gmail.com \
    --to=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=l.s.r@web.de \
    --cc=peff@peff.net \
    --cc=tr@thomasrast.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.