On Sat, Apr 18, 2020 at 02:13:51PM +0200, Alex Hall wrote:

> My issue with this, and maybe it's what Andrew is also trying to say, is
> that it breaks our usual assumptions about composing expressions. `{u, v}`
> is an expression, it represents a set, and it always represents that
> wherever you put it. Under your proposal, these two programs are both valid
> syntax with different meanings:
> 
>     f(**{u, v})
> 
>     x = {u, v}
>     f(**x)

True, and that does count as a (minor?) point against it. But not one 
that I think should rule it out.


> Is there anything else similar in the language? Obviously there are cases
> where the same text has different meanings in different contexts, but I
> don't think you can ever refactor an expression (or text that looks like an
> expression) into a variable and change its meaning while keeping the
> program runnable.

Of course! There are many ways that this can occur.

    f(a, b, c)

    x = a, b, c
    f(x)

are very different things. Here's another one:

    import name

    x = name
    import x

Here's a third:

    del fe, fi, fo, fum

    x = fe, fi, fo, fum
    del x

Here's an example so obvious (and trivial) that I'm almost embarrassed 
to include it:

    seq[index]

    x = [index]
    seqx

If code is made of composable building blocks, those blocks aren't 
*characters*. What makes a composable block is dependent on context.

To make up for how trivial the previous example was, here's a 
complicated one:

    for item in items:
        if item:
            continue
        do_stuff()

versus:

    def block(item):
        if item:
            continue
        do_stuff()

    for item in items:
        block()

I have often wished I could refactor continue and break into functions, 
but you can't :-(

Although in this case at least you get a syntax error when you try.

Here's an example with sequence unpacking:

    a = [1, 2, *seq]

    x = 2, *seq
    a = [1, x]

Another example:

    class MyClass(metaclass=MyMeta)

    metaclass = MyMeta
    class MyClass(metaclass)

That's just a special case of keyword notation itself:

    func(x=expr)

    x = expr
    func(x)

Those are not the same, unless the first positional argument happens to 
be named `x`.

And one final example:

    class C:
        def method(self):
            pass

versus:

    def method(self):
        pass

    class C:
        method


This is not an exhaustive list, just the first few things that came to 
my mind.


> This proposal makes it harder for beginners to understand how a program is
> interpreted. It breaks the simple mental model where building blocks are
> combined in a consistent fashion into larger parts.

I **LOVE** the ability to reason about code with a simple mental model 
of building blocks. I would consider it a very important property of 
syntax.

But it is not an absolute requirement in all things. I mean, we wouldn't 
want to say that function call syntax `f(x, y, z)` is a disaster 
because it looks like we combined a name with a tuple.

I acknowledge that "cannot compose this" is a point against it, but I 
deny that it should be a flat out disqualification. There are lots of 
things in Python that cannot be trivially composed.


> The example above looks a bit dumb, but maybe users will try:
> 
> ```
> if flag:
>     kwargs = {u, v}
> else:
>     kwargs = {w, x}
> f(**kwargs)
> ```

I think this point will apply to all(?) such syntactic proposals. I 
don't think this scenario is too different from this:

    if flag:
        f(u=expr1, v=expr2)
    else:
        f(w=expr3, x=expr4)

If you want to refactor that, you can't do this:

    f((u=expr1, v=expr2) if flag else (w=expr3, x=expr4))

but you can just use regular dict unpacking:

    d = dict(u=expr1, v=expr2) if flag else dict(w=expr3, x=expr4)
    f(**d)

 
> Which is valid syntax but is wrong. Then they might try changing that to:
> 
>     f(**({u, v} if flag else {w, x}))
> 
> which is suddenly invalid syntax.

Not invalid syntax, but it's still wrong. You'll get a TypeError when 
trying to `**` unpack a set instead of a dict.


> This is a very weird user experience. On
> that note, is this valid?
> 
>     f(**({u, v}))

I would expect that to parse as regular old dict unpacking, and give a 
TypeError at runtime.


-- 
Steven
_______________________________________________
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/2QJGONYHLKTPDTLGIOATG4UJYEM4KBHG/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to