7 ms·
For me the walrus operator is an example of how things can take a turn for the worse. It's a bad idea. I have yet to see any example that justifies its existe
by robomartin 7y ago
For me the walrus operator is an example of how things can take a turn for the worse. It's a bad idea. I have yet to see any example that justifies its existence. Put a different way, I have yet to see a reason for not extending "=" to add this behavior. This is how a nice language can be ruined and can become a Tower of Babel scenario. In some ways this is how J is a ruined version of APL, because it completely destroys what the language was about in the first place. Next thing we know we are going to end-up with 23 different assignment operators, one for each chromosome pair.
The other part I don't get is the religious insistence against not implementing something like a "switch" statement. This is one of the most useful constructs in all of computer science and Python rejects it due to what amounts to religious belief. In fact, one of the most powerful tools you get when moving from assembler to C is the "switch()" statement. If you've ever coded and maintained the equivalent in assembler you know exactly what I am talking about.
Because, you know, a pile of "if" statements is somehow better. Ah, OK, with "if" you can use data types other than integer. Sure, because we couldn't define a Python "switch" to work with anything other than integers...like a "switch" that could take a dictionary and route based on key/value matching, etc.
Every single state machine I have written in who knows how many decades --in C, C++, Objective-C, PHP, Verilog, etc.-- has had, at it's core, a single or multi-layer "switch" statement. Can't do that in Python, 'cause.
<rant off>
- zapzupnz 7y agoCould you give a concrete example of how the walrus operator is worse for the language? I know you've admitted that this is a rant but without anything to back it up, it isn't much interesting to read. As for the switch statement, I'm inclined to agree although if we see `switch` as syntactic sugar for a bunch of other conditional statements, then what makes it a more important candidate for inclusion than the walrus operator? Thanks in advance, I'm genuinely curious to know.
- FakeComments 7y agoNot GP, but — What makes if statements and loop statements more useful than goto statements? Switch is a powerful abstraction over chained and/or nested if statements, in much the same way other constructs are abstractions over goto. A programming language is for humans to read — and switch statements greatly enhance comprehension. While other languages use := for assignment, and perhaps there’s arguments that’s better in the face of typos, Python doesn’t in general — and I don’t see the utility in adding a second way to do assignment. The use cases of the walrus operator are useful, but they’re just cases of assignment in many languages; a second sometimes used assignment operator is not.
- marcosdumay 7y agoThe walrus operator has very clear problems once you start to use the assigned variable at the same line it receives a new value. That's not really relevant on practice, since nobody does it, but it moves a language from a philosophy of simple semantics into one where people are ok with undefined behavior or a pile of exceptional cases. This change does smell really bad for people that have seen it before, so those tend to overreact and start complaining that the sky is falling. Specifically on the case of Python, it used to promise simple semantics a long while ago. This changed at some point, and the semantics were already complex before the walrus operator. With the operator added, semantics becomes a bit more complex, but this is not a main feature of the language anymore, so it's not a big change. Yet, pattern matching would have a very small semantic footprint, and would solve the same kinds of problems (despite having a very different nature), but was very vocally rejected without any of the deep analysis that went into the walrus operator. It looks like this happened because they would have a very large syntactic footprint, basically completely changing the appearance of the language, but the process left the people that focused on semantics lost, without understanding what was happening.
- robomartin 7y ago> 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 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.
- joshuamorton 7y agoUsing = for assignment expressions introduces ambiguity in if statements: is if (x = 3): Intended, or not?
- raymondh 7y agoThere is no ambiguity. This example is invalid syntax.
- joshuamorton 7y agoIn Python yes, but the post I responded to asked why they settled on a different assignment syntax for expressions. It was to avoid that ambiguity (or error prone pattern, if you prefer) which is present in, say, C.
- ryl00 7y agoC/C++ compilers (at least, all the ones I know about) squawk about it unless you add an additional set of parentheses around the assignment.
- bluecalm 7y agoThrow a warning? C compilers require additional parentheses of you want to use the value of assignment as a conditional. It's impossible to make a mistake there unless you're dumb on purpose that is disabling or ignoring compiler warnings. That being said I think it matters little if it's a separate operator or not. It solves a real issue I'm the language caused by assignment not being an expression. Better later than never I guess.
- robomartin 7y agoI don't understand, what is wrong with extending "=" such that in the example you gave "if(x=3)" it stores 3 in x and then makes the comparison? More accurately, in Python it would be: if x = 3: # x is assigned 3 and then tested do_something_here() This is different from: if x == 3: # x is compared to 3 do_something_here() Very clear difference between the two statements. What if we want to assign and then compare? if (x = 3) == y: do_something_here() or... if x = 3; x == y: #Python evaluates left to right... do_something_here() In fact, you could... if x = 3; x == y; x = x + 1: #Python evaluates left to right... do_something_here() Not super elegant, but it makes sense. I wouldn't want to write code like that in any language unless it was very well justified. What if we want to compare and then assign? if x == y; x = 3: #Python evaluates left to right... do_something_here() Side note: Why, oh why, don't we have pre and post increment/decrement (++/--) in Python? Another religious decision. I guess I am having trouble seeing where this ambiguity might be. What is ambiguous about usage that is currently not legal and is later defined as a new way to make assignments? In other words, nobody is using it that way today because it doesn't work. Tomorrow we say: From now on, you can make assignments inside of several conditional statements. What's ambiguous about that? This isn't foreign at all, is it? I mean, we have been able to do this in C for decades: int i; for(i=1; i<=3; i++) { printf("%d\n", i); } In fact, you can do this: int i; for(i=1; i<=3; i=i+1) { printf("%d\n", i); } That's TWO assignments, not just one. No special operator or syntax. Last I checked no airplanes have crashed, MRI machines stopped working and nobody died because of this. Forgive me but, I just don't see the ambiguity at all. Once you define the extension of functionality the rest is not a problem. That said, I am eager to learn. I've only been designing hardware and software since about 1982 or so and have programmed in nearly every mainstream language in existence on platforms ranging from embedded to Silicon Graphics supercomputers and even the web. It is quite possible I am confused or just don't understand something. I do have a very pragmatic view of this stuff. By which I mean to say: Simple is usually better and there has to be a very, very good reason to reinvent any wheel.
- thrower123 7y agoIn a world with several good examples of pattern matching implemented in modern high-level languages, a C-style switch statement should probably be shunned going forward.
- robomartin 7y agoThe problem with this idea is very simple: code bloat. Modern software engineers have very little connection to low level code; what actually happens at the processor level. If you are even in a position to interview someone for a software dev position, try this: - Have them write a small program do to something simple; find a sub-string in a long string - Now have them take their program and convert it to pseudo assembly language, explain what goes on in memory, where, how, etc. In other words, it doesn't have to be real assembly from a real processor, yet it has to resemble how things actually work. From my experience most applicants flunk this test. They have no clue whatsoever. And so, we produce tools, languages, libraries, and all manner of "pattern matching in modern high-level languages", they use them without a single clue and the resulting code is bloated and slow, to say the least. Many years ago I wrote a genetic solver as a part of an iOS app that ran on an, at the time, iPhone 3S. It was an absolute dog. Unusable. You simply could not get results anywhere close to real time. An iPhone 3S, in the context of what the code entailed, is a massively fast computing engine. There was only one reason for which this code ran like crap: Objective-C and all the truly unnecessary "modern high-level language" garbage that came with it. I re-coded the genetic solver in C++ with great care to manage the entire process efficiently. It ran THOUSANDS of times faster. In fact, it ran in real time (in the context of what the UI had to do) to the point where there was no lag and the user could interact with it as needed. A lot of this stuff comes at great cost. The problem is modern programmers don't have a clue.
- thrower123 7y agoI agree with you in spirit, but, it's Python, so bare metal speed is a lost cause already. You're already supposed to drop down to C for any performance critical code anyway. In addition, even when people think they know what is going on under the hood, most people are taught how things worked about circa 1992 at best.
- ben509 7y ago> This is one of the most useful constructs in all of computer science and Python rejects it due to what amounts to religious belief. What utter nonsense. There was extensive discussion, and it ran into the limitations of Python's semantics. Here's a related problem, a common mistake for new Python coders: x = [] for a in [1, 2, 3]: x.append(lambda: a) print([f() for f in x]) It prints [3, 3, 3], of course, because people don't realize all the lambdas are closing over the same 'a'. And there's simply no way around this with the way Python's scoping works. Read PEP 3103. Every possible implementation was potentially badly misleading to users: 1. Building the dispatch at compile time would result in mysteriously immutable values. 2. Semantics would likely be different outside a function. 3. Or it would sometimes use dispatch and sometimes use if-else chains, leading to inconsistent performance. 4. Or they'd have to add completely new syntax for static data. If they just made it syntactic sugar for an if-else chain, even that's misleading, because people will invariably be surprised to learn it's not doing a simple dispatch. There's nothing religious going on here, Python is simply constrained by its original design. If various proposals to add new syntax for static data come to fruition, then a switch statement would make perfect sense and have clear semantics, and they will be glad they didn't try to kludge some half-baked crap together like they did with Enum.
- dragonwriter 7y ago> The other part I don't get is the religious insistence against not implementing something like a "switch" statement. Off the top of my head, something like a switch, but more general and a function rather than a statement: def switch(key, opts_dict, *, default): return opts_dict.get(key, default)() or, if key is of a comparable but non-hashable type: def switch(key, opts_list, *, default): return next( (o[1] for o in opts_list if o[0] == key), default )() I can think of other simple variations to do exactly what is wanted in other situations; it's easy enough to code a specific tool for the situation with what Python gives you that, in the situations where a chained set of if/else isn't what is called for, it's trivial to whip up something tailored to the specific need. C doesn't have dicts or iterators or first-class functions in the base language (at least, with convenient syntax), so it needs special syntax to cover a much smaller space than what Python conveniently handles without special syntax dedicated to the problem.
- ldng 7y agoActually, what you want is not a switch, it's pattern matching
- m463 7y agoI used perl almost exclusively before moving to python and it is very easy to use regular expressions. Now I use python and love how it is better at separating the expression from the python language (with perl you were never sure if you had escaped things correctly) but pyython is just... clumsy m = re.match(r'xyz',str) if m: do a else: m = re.match(r'wxy',str) if m: do b else: m = re.match(r'abc', str) if m: do c: else: ... vs: if m := re.match(r'xyz',str): do a elif m := re.match(r'wxy',str) do b elif m := re.match(r'abc',str) do c ...