On 19.04.20 12:57, Steven D'Aprano wrote:

On Sat, Apr 18, 2020 at 09:13:44PM +0200, Dominik Vilsmeier wrote:

     func(foo, **, bar)          vs.          func(foo, **{bar})

It's still a mode switch, only the beginning and end markers have
changed. Instead of `**,` (or `**mapping,`) we then have `**{` as the
opening marker and instead of `)` (the parenthesis that closes the
function call) we have `}` as the closing marker.
How do you define a mode switch?
I don't have a clear definition, instead my point was to show that there
is no substantial difference between `**` and `**{...}` (though you seem
to think differently).
Is a list display a mode? Is a string a mode? Is a float a mode?
I'd say yes, technically they are. There's a substantial difference
between writing `sys.exit()` and `"sys.exit()"`. Same for 'comment
mode': `# sys.exit()` , and most IDEs have shortcuts for switching it on
and off. However I think a major difference is that all these can exist
in different contexts, also in isolation, and hence we think of them as
self-contained entities. The modal aspect is only relevant to the compiler.
In some sense, maybe, but to me the critical factor is that nobody talks
about "list mode", "string mode", let alone "float mode". Its about the
mental model.

With `func(foo, **, bar, baz, quux)` if I use `**` as a pseudo-argument,
the interpreter switches to "auto-fill" mode and everything that follows
that (until the end of the function call) has to be interpreted
according to the mode.
With your proposal if I use `**{` then the interpreter similarly
switches to auto-fill mode and everything that follows until the next
`}` is affected by that mode. There's no big difference. The idea behind
`**` is that you could also use `**kwargs` instead and `**` is just the
case when you don't have anything to unpack (as an analogy to `*args`
vs. `*` in a function definition when you don't need to consume varargs).
A few people immediately started describing this as a mode, without
prompting. I think it is a very natural way of thinking about it.
I think what obscures the modal aspect of `**{...}` is the fact that it
somehow looks like an expression, but it isn't. It's special syntax that
can only be used in function calls, to tell the compiler that it should
autofill the parameter names. It's a mode in disguise.
And we have no way of turning the mode off. So if there is every a
proposal to allow positional arguments to follow keyword arguments, it
won't be compatible with auto-fill mode.
That is true, it doesn't have an explicit end token. However I'm not
convinced that ruling out the positional-after-keyword-arguments option
is a relevant argument against it.
With `func(foo, **{bar, baz, quux})` the mental model is closer to
ordinary argument or dict unpacking. Nobody refers to this:

     func(spam, *[eggs, cheese, aardvark], hovercraft)

as "list mode" or "argument unpacking mode". It's just "unpacking a
list" or similar. No-one thinks about the interpreter entering a special
"collect list mode" even if that's what the parser actually does, in
some sense. We read the list as an entity, which then gets unpacked.

In this example `*` and `[eggs, cheese, aardvark]` are distinct
entities, the latter can exist without the former and it has the exact
same meaning, independent of context. So we think about it as a list
that gets unpacked (and the list being a concept that can exist in
isolation, without unpacking).

With the proposed syntax we have `**{eggs, cheese, aardvark}` and here
the `**` and `{...}` parts are inseparable. Even though the latter could
exist in isolation but then it means something completely different. In
the `**{...}` listing of names these not only refer to their objects as
usual but also serve the purpose of identifying keyword parameter names.
This unusual extension of identifier meaning is limited by `**{` and `}`
and hence I consider it a mode, just like `**,` and `)`.

Likewise for dict unpacking: nobody thinks of `{'a': expr}` as entering
"dict mode". You just make a dict, then unpack it.

And nobody (I hope...) will think of keyword shortcut as a mode:

     func(foo, **{bar, baz}, quux=1)`

It's just unpacking an autofilled set of parameter names. Not a mode at
all. And notice that there is absolutely no difficulty with some future
enhancement to allow positional arguments after keyword arguments.
"unpacking an autofilled set of parameter names" implies that two
distinct actions take place. First the set of parameter names is
autofilled and converted into something that can be unpacked, and then
it actually gets unpacked. But that's not what is happening, you can't
have `**({bar, baz})`. What you *describe* is another proposal, namely
using e.g. `{:bar, :baz}` to construct the mapping and then `**` to
unpack it; `**({:bar, :baz})` works without problem. So the `**{bar,
baz}` syntax is not actually unpacking anything, it's a hint for the
compiler to treat `bar, baz` as `bar=bar, baz=baz` and hence it's a mode
switch.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/TL3H3MZDUQ4LOA7AECDZLK5ZN2WPHHGR/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to