Hacker News new | past | comments | ask | show | jobs | submit login

> Could you give a concrete example of how the walrus operator is worse for the language?

Because it isn't necessary? All you have to do is extend the syntax to now allow the one-and-only assignment operator to function in other places, for example, in an "if" or "for" statement and you are done. Anything else can be taken care of with parenthesis.

For more examples of how I don't see any applicable ambiguity, see my reply below to a different question:

https://news.ycombinator.com/item?id=21426133

I mean, to me this is like adding a wing to the back of a four door family car. It's useless complexity.

We want to reduce complexity, not increase it.

BTW, I read through the entire PEP [0] and still find no way to answer this basic question in favor of the walrus operator:

What's wrong with simply extending the functionality of the existing assignment operator?

I looked through the examples and mentally made the change. I can't see any need for the new operator. Case in point, this is one of the examples given in the PEP:

    Current:

    reductor = dispatch_table.get(cls)
    if reductor:
        rv = reductor(x)
    else:
        reductor = getattr(x, "__reduce_ex__", None)
        if reductor:
            rv = reductor(4)
        else:
            reductor = getattr(x, "__reduce__", None)
            if reductor:
                rv = reductor()
            else:
                raise Error(
                    "un(deep)copyable object of type %s" % cls)



    Improved:

    if reductor := dispatch_table.get(cls):
        rv = reductor(x)
    elif reductor := getattr(x, "__reduce_ex__", None):
        rv = reductor(4)
    elif reductor := getattr(x, "__reduce__", None):
        rv = reductor()
    else:
        raise Error("un(deep)copyable object of type %s" % cls)
  


    My version, after declaring that "=" can now be used this way:

    if reductor = dispatch_table.get(cls):
        rv = reductor(x)
    elif reductor = getattr(x, "__reduce_ex__", None):
        rv = reductor(4)
    elif reductor = getattr(x, "__reduce__", None):
        rv = reductor()
    else:
        raise Error("un(deep)copyable object of type %s" % cls) 

Why do we absolutely need the walrus operator again?

And yet I go back to the "Current" pre-walrus code and have to ask: What is wrong with it? It's clear, very clear. And, nothing whatsoever in this logic is changing at the microprocessor level because of the use of the walrus operator. Even with we do not extend "=" to be able to use it in extended form, there is nothing whatsoever wrong with the original code. This basic structure has been used for decades in myriad languages. Not sure why there's a need to reinvent a wheel for basically zero gain. Extend "=" so it works in a few places, sure, that might clean-up code, but walrus? C'mon.




These two are syntactically equal and in Python there's no way a linter can distinguish between these two:

    if reductor = dispatch_table.get(cls):
    if reductor == dispatch_table.get(cls):
A human being can only distinguish them through careful inspection. The walrus operator not only prevents that problem, but makes the intent unambiguous.

> Not sure why there's a need to reinvent a wheel for basically zero gain.

What's being reinvented? No one claimed this was an original idea. It's just inline assignment with a syntactic tweak to prevent a well known problem.


To add to this, let's take a look at the simplest portion of the above and think about where this ultimately ends-up: As code being executed by a microprocessor; machine language.

    reductor = dispatch_table.get(cls)
    if reductor:
        rv = reductor(x)
versus:

    if reductor := dispatch_table.get(cls):
        rv = reductor(x)
versus (the case of extending "="):

    if reductor = dispatch_table.get(cls):
        rv = reductor(x)
Now let's look at rough machine-level pseudo code.

In the first case:

    - Load address of "cls" into appropriate register
    - Jump to address where "dispatch_table.get()" code is located
    - Upon return, the result, a memory address (pointer) is stored in a register
    - Load the memory address (pointer) to where the "reductor" variable's data is located
    - Store the address that came back from "dispatch_table.get()" at that location
    - Compare this and jump if null
    - If not null we execute the code that follows
Great. What would the pseudocode for the second case (walrus) look like:

    - Load address of "cls" into appropriate register
    - Jump to address where "dispatch_table.get()" code is located
    - Upon return, the result, a memory address (pointer) is stored in a register
    - Load the memory address (pointer) to where the "reductor" variable's data is located
    - Store the address that came back from "dispatch_table.get()" at that location
    - Compare this and jump if null
    - If not null we execute the code that follows
Hmmm, I see a pattern here. What would it look like if we extended the functionality of "=" instead?

    - Load address of "cls" into appropriate register
    - Jump to address where "dispatch_table.get()" code is located
    - Upon return, the result, a memory address (pointer) is stored in a register
    - Load the memory address (pointer) to where the "reductor" variable's data is located
    - Store the address that came back from "dispatch_table.get()" at that location
    - Compare this and jump if null
    - If not null we execute the code that follows
OK. Well, there's the point. If the code has to do exactly the same thing it will ultimately end-up executing exactly the same code on the processor. If it executes any more code than the old approach it will not, by definition, add any functionality, therefore, it is a waste of time. If it does exactly the same thing we should then question why it is necessary in the first place.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: