git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 4/5] config: return an empty list, not NULL

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Sep 27, 2022, 19:18 UTC
Message-ID
<220927.86k05oy5oi.gmgdl@evledraar.gmail.com>
In-Reply-To
<b85d8a43-6640-aa9c-3103-0c3d43c2a479@github.com>
On Tue, Sep 27 2022, Derrick Stolee wrote:
Show 30 quoted lines
> On 9/27/2022 12:21 PM, Ævar Arnfjörð Bjarmason wrote:
>> 
>> On Tue, Sep 27 2022, Derrick Stolee via GitGitGadget wrote:
>
>>>  /**
>>>   * Finds and returns the value list, sorted in order of increasing priority
>>>   * for the configuration variable `key`. When the configuration variable
>>> - * `key` is not found, returns NULL. The caller should not free or modify
>>> - * the returned pointer, as it is owned by the cache.
>>> + * `key` is not found, returns an empty list. The caller should not free or
>>> + * modify the returned pointer, as it is owned by the cache.
>>>   */
>>>  const struct string_list *git_config_get_value_multi(const char *key);
>> 
>> Aside from the "DWIM API" aspect of this (which I don't mind) I think
>> this is really taking the low-level function in the wrong direction, and
>> that we should just add a new simple wrapper instead.
>> 
>> I.e. both the pre-image API docs & this series gloss over the fact that
>> we'd not just return NULL here if the config wasn't there, but also if
>> git_config_parse_key() failed.
>> 
>> So it seems to me that a better direction would be starting with
>> something like the WIP below (which doesn't compile the whole code, I
>> stopped at config.[ch] and pack-bitmap.c). I.e. the same "int" return
>> and "dest" pattern that most other things in the config API have.
>
> Do you have an example where a caller would benefit from this
> distinction? Without such an example, I don't think it is worth
> creating such a huge change for purity's sake alone.

Not initially, I started poking at this because the CL/series/commits says that we don't care about the case of non-existing keys, without being clear as to why we want to conflate that with other errors we might get from this API.

But after some digging I found:
	$ for k in a a.b. "'x.y"; do ./git for-each-repo --config=$k;  echo $?; done
	error: key does not contain a section: a
	0
	error: key does not contain variable name: a.b.
	0
	error: invalid key: 'x.y
	0
	
I.e. the repo_config_get_value_multi() you added in for-each-repo
doesn't distinguish between bad keys and non-existing keys, and returns
0 even though it printed an "error".
Show 7 quoted lines
> I'm pretty happy that the diff for this series is an overall
> reduction in code, while also not being too large in the interim:
>
>  12 files changed, 39 insertions(+), 57 deletions(-)
>
> If all callers that use the *_multi() methods would only use the
> wrapper, then what is the point of doing the low-level manipulations?

I hacked up something that's at least RFC-quality based on this approach, but CI is running etc., so not submitting it now:

	https://github.com/git/git/compare/master...avar:git:avar/have-git_configset_get_value-use-dest-and-int-pattern

I think the resulting diff is more idiomatic API use, i.e. you ended up with:

	        /* submodule.active is set */
	        sl = repo_config_get_value_multi(repo, "submodule.active");
	-       if (sl) {
	+       if (sl && sl->nr) {
But I ended up doing:
	        /* submodule.active is set */
	-       sl = repo_config_get_value_multi(repo, "submodule.active");
	-       if (sl) {
	+       if (!repo_config_get_const_value_multi(repo, "submodule.active", &sl)) {

Note the "const" in the function name, i.e. there's wrappers that handle the case where we have a hardcoded key name, in which case we can BUG() out if we'd return < 0, so all we have left is just "does key exist".

In any case, I'm all for having some simple wrapper for the common cases.

But I didn't find a single case where we actually needed this "never give me a non-NULL list" behavior, it could just be generalized to "let's have the API tell us if the key exist".

If you use the non-"const" API you can distinguish the err < 0 case, so for-each-repo can now error out appropriately:

	$ ./git for-each-repo --config=a; echo $?
	error: key does not contain a section: a
	fatal: got bad config --config=a
	
	usage: git for-each-repo --config=<config> <command-args>
	
	    --config <config>     config key storing a list of repository paths
	
	129
Previous: Derrick StoleeNext: Derrick Stolee
Message 11 of 21 in “[RFC] config API: return empty list, not NULL”
  1. 0/5 [RFC] config API: return empty list, not NULLDerrick Stolee via GitGitGadget, Sep 27, 2022
  2. 1/5 config: relax requirements on multi-value returnDerrick Stolee via GitGitGadget, Sep 27, 2022
  3. Junio C HamanoSep 27, 2022
  4. 3/5 config: add BUG() statement instead of possible segfaultDerrick Stolee via GitGitGadget, Sep 27, 2022
  5. Ævar Arnfjörð BjarmasonSep 27, 2022
  6. Derrick StoleeSep 27, 2022
  7. Ævar Arnfjörð BjarmasonSep 27, 2022
  8. 4/5 config: return an empty list, not NULLDerrick Stolee via GitGitGadget, Sep 27, 2022
  9. Ævar Arnfjörð BjarmasonSep 27, 2022
  10. Derrick StoleeSep 27, 2022
  11. Ævar Arnfjörð BjarmasonSep 27, 2022
  12. Derrick StoleeSep 28, 2022
  13. Ævar Arnfjörð BjarmasonSep 28, 2022
  14. Derrick StoleeSep 28, 2022
  15. Ævar Arnfjörð BjarmasonSep 28, 2022
  16. 2/5 *: relax git_configset_get_value_multi resultDerrick Stolee via GitGitGadget, Sep 27, 2022
  17. Taylor BlauSep 28, 2022
  18. 5/5 *: expect a non-NULL list of config valuesDerrick Stolee via GitGitGadget, Sep 27, 2022
  19. Junio C HamanoSep 28, 2022
  20. Derrick StoleeSep 28, 2022
  21. Ævar Arnfjörð BjarmasonSep 28, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.