Parentheses are only needed with infix notation. Pure prefix (like Unlambda) or pure postfix notation (like Forth) are unambiguous without them. Whether the resulting language is easy to understand is a far more complicated question.
> Whether the resulting language is easy to understand is a far more complicated question.
That's why I hate them. A programming language is primarily meant to be read by people. If I see something like
thing noun object
What's going on there? Is thing a function? Is noun? Am I passing two arguments to thing, or am I passing the result of invoking the function noun with the argument object?
Hell, if I have something like
verb action
it certainly looks like I'm calling a function called verb with the argument action, but is the argument I'm giving to verb the actual function action, or the result of evaluating action?
Yes, in any given language there's probably a single answer to all of these, but I bet it varies from language to language, and I'd really, really, really rather not waste calories by having my brain try to figure it out.
This sounds like a bad idea. It creates more ambiguities in the language, and will require people to remember a lot more. It works in ruby because in ruby you can't assign a function to a variable like
A = len
But you can in python.
It seems python is adding more and more implicit stuff in every new release.
I think the day we can import braces from __future__ might not be far away.
Yup, this looks a lot like Tcl! But Tcl lets you compose code at runtime using its string lists. I doubt Python will. So why introduce another redundant syntax?
Looks like forth (uses stack instead of pipes though).
The first line will define add10 (which is assumed to exist in your example already, but I wanted to show how easy it was to create). 123 puts 123 on the stack. add10 adds ten to the number on the stack. "." prints (and removes) the top of the stack. Don't have to convert it to a string in this case.
Take a look at marcel: https://github.com/geophile/marcel. It is a pipe-objects-instead-of-strings shell, implemented in Python. But it is also an API allowing scripting from inside Python, e.g.
for file, size in ls('/home/jao') | map(lambda f: (f, f.size)):
print(f'{file.name}: {size}')
+1! I don't like your suggested syntax, but definitely, something like that would be a great addition to Python. Especially if it could be made to work with lists. Rough idea:
So, is this just a syntax change or is this adding a new statement?
If it's the latter, does that mean that the execution environment is part of the language itself, instead of, for example, C where environmental stuff is only accesible through the standard library and the language per se is little more than a context-free grammar?
So pedantic but I love it. For the GP, what you are looking for is them em dash (—) with no spaces around it, because the dash is its own form of punctuation.
A double-dash is a perfectly valid substitute for an em dash given that most (no?) keyboards have it on a key. Seems like a waste of time to always have to look up an escape code or copy/paste from somewhere when the intent of "--" is clear.
I don't hold random comments on the internet to the highest standard because I am not a monster. However they are not equivalent and the em dash is a sign of extra polish.
These look like brackets, not binary operators. So, that's one style, but a rather unobvious one, and also contradicts PEP8, which says (as the very first thing in the section on inline spaces!) to avoid whitespace immediately inside brackets.
Sorry, but I think this is a poisonous, thought-terminating cliche.
Python has had multiple ways of doing many things for a very long time, and the longer you program in any language, the more you realize there are often many solutions to a problem and the "best" approach either depends on context or you realize there is no one "best" approach and go on preference.
I think the idea should be judged on its own merits without having to consult the Zen. That said, I seriously don't see the point of it. Python 3 already forced everybody to convert all their print statements to look like function calls, and now GVR wants to bring the old style back as an option? It's just parenthesis, what's the point?
If he wants to put that new parser to work, how about taking another look at multi-line lambdas?
The key words are ‘preferably’ and ‘obvious’ (although that way may not be obvious at first unless you're Dutch). It's fine if there are merely multiple ways to do something, as long as you're not actually giving people tough choices.
> Python has had multiple ways of doing many things for a very long time ... the more you realise there are often many solutions to a problem
But "solution" and "ways of doing things" from a language perspective are different. You can one way of doing something in a language, yet provide different implementations of the same solution. The difference is how different a "way" is at some level of abstract (vs "syntactic sugar).
Inventing new sentences is needed everyday, inventing new words much rarely so. "programmable program languages" or those highly dependant on custom frameworks fall prey to this: where code becomes a personal space that is hard to break into. You have to "terminate-thought" at some level, if else everyone "creatively" reinvents the low level (e.g. built-ins) then no collaboration is practical; accept the standard building block, and implement your solution with those.
"There should be one-- and preferably only one --obvious way to do it."
This principle is often repeated for Python, but does it have any bearing on reality today? With every release of Python (and indeed for many other languages), new features give you even more ways of doing things.
Python is 30 years old - it's no longer the small language it may once have been, but is now chock-full of features. Maybe once there was an "obvious way to do it", but I don't thing this is true today.
> Seems to violate "There should be one-- and preferably only one --obvious way to do it."
Just as representing a vector of numbers as a tuple, a list, a dictionary, a numpy matrix or a numpy array. And don't get me started on multidimensional arrays.
OK, so I sort of get it. I love ML style syntax. I love the way that it supports great things like partial application.
What I do not like is TMTOWTDI. And I do not like Python violating its own principles (namely, "explicit is better than implicit"). As far as I am concerned, in Python, which does not have partial application, function application is handled by a special `(...)` operator that explicitly applies whatever function comes before the parens to whatever is inside the parens. Making the parens optional gives you two different ways to apply a function - and, by extension, one more place for people to argue about style - one of which is just an implicit version of the other.
You've got to have a way better reason to do that to a language than just, "Hey, isn't this cool? And also, I miss the Python 2 vs Python 3 wars, so wouldn't it be fun to give that pot another stir for old time's sake?"
I get it, the change from a print statement to a print function caused some pain. But it did bring some practical benefits, and the transition is in the past now, and, to quote the Zen of Python again, "special cases aren't special enough to break the rules."
I'm also going to throw another reference to PEP-20 in the mix here: "There should be one-- and preferably only one --obvious way to do it." This implies either forcing parens everywhere or not using them at all. Paired with "explicit is better than implicit", I'd say that points pretty clearly at using parens everywhere.
Another thought: This would create ambiguities in the language that would harm its readability. Maybe not as far as the computer is concerned, but certainly as far as the humans are concerned. Is
print(1, 2, 3)
supposed to print
1 2 3
or
(1, 2, 3)
?
What about
print (1, 2, 3)
?
Are they the same? Should they be different? I know what the answer is in Python 3.8. A few weeks or months of programming in a Python where parens are optional, though, and I wouldn't be so sure anymore.
By, "Maybe not as far as the computer is concerned, but certainly as far as the humans are concerned.", I meant to invoke the principle that there's more to a good grammar than the computer being able to parse it reliably. It's also got to not be confusing for its wet, squishy readers.
> You've got to have a way better reason to do that to a language than just, "Hey, isn't this cool? And also, I miss the Python 2 vs Python 3 wars, so wouldn't it be fun to give that pot another stir for old time's sake?"
That was my first thought. Why would we turn a simple, binary choice -- "< 3: statement, >= 3: function" into a big old... maybe?
The binary choice hurts, because it dictates changes. Sure. People dislike change, but it's easy to support.
However, there's one thing worse than change, and that's inconsistency and uncertainty. like, in this case, going "zoinks, your change wasn't actually necessary!". Except, now we have both choices. So it'd be even more confusing.
As they say, the road to Perl is paved with good intentions.
There are several languages that people like for this sort of flexibility, but I think Python's relative rigidity has always been one of its strengths.
So what? In the history of Python, there was literally 0 bugs caused by print being a statement. Breaking backwards compatibility for shit like that is amateur hour.
edit: And just to be clear, I'm fine with making print a function for all new code. There were ways that the python community could have accomplished that [and the unicode switch] without breaking the entire language.
Being a statement is less of an issue than the special behavior of the trailing comma, '>>' token, and the inability to augment behavior with named arguments. The lexer shouldn't have to deal with that sort of stuff.
> The lexer shouldn't have to deal with that sort of stuff.
The problem with that is that the entire python ecosystem had to deal with that instead...
I'm going way past rant territory at this point, but there's a reason that Microsoft and Amazon are worth a trillion dollars a piece, and it's not because of beautiful and elegant APIs.
Python 3 literally broke "hello, world". For some vague notion of aesthetics. Or for some even more obscure "inside baseball" reason that 99% of Python users could care less about.
The following still compiles and runs, on the compiler that comes with the latest OpenBSD:
main()
{
printf("hello, world\n");
}
Somehow the C language has managed to survive and thrive without breaking the canonical example program.
It survived and thrived because it did not break the canonical example program. If they had broken printf in say 1995 the situation would be entirely different today. Oh, and they did get it right the first time by making it a function.
SO, you're saying that if Python abandoned quality in favour of aggressive sales and marketing in the channel and cut-throat monopolistic practices against competing program languages, then its core programmers would rise to the ranks of American social elites?
Backwards compatibility is something that you only ditch for extremely good reasons, for instance to deal with a security issue that can not be handled in any other way. Breaking it for reasons of aesthetics is just plain dumb. The python ecosystem is still suffering from these major mistakes many years later and python's image as a reliable and trustworthy tool suffered right along with it. Such changes are fine pre 1.0, but once you ask people to base their production systems on it you maintain backwards compatibility at a cost, even if that means holding your nose occasionally. And my suggested fix would at least allow for the old syntax to live happily along with the new one, which given the price (two stupid brackets) could have easily been dealt with. Focusing on purity vs the responsibility towards people maintaining 100's of millions of lines of code in aggregate (if not another order of magnitude more) means you don't have your priorities straight.
Imagine we'd drop HTTPS for a new protocol because it fixes the 'Referrer' spelling error.
The analogy here is: "Imagine making a new, incompatible protocol and NOT fixing the 'Referrer' spelling error, because the old protocol had that spelling error"
Python 3 is the version with breaking changes from 2.x and while stuff is being broken, they decided to fix the print statement.
Python 3 wasn't invented to fix the print statement.
I don't think having two different syntactic ways to write the the same thing - at a purely syntactic level - is a violation of TMTOWTDI. After all, Python already lets you write:
f(a)
f((a))
(f)(a)
(f)((a))
etc. and those all mean the same thing, and no-one finds this confusing.
If Python wants to come closer to a functional style of programming, then they should allow inline lambda functions which span multiple lines and still follow the normal syntax (i.e., escaping newlines would be cheating).
I really hope they do not do this. In and of itself it is not a problem, Ruby code is perfectly readable when the style is consistent.
Software developers are often stubborn. The main result of this change will be a mess of code which follows a mix of all the styles. That removes one of the greatest beauties of the Python ecosystem, that there is a "right way" to do things.
The Pythonic way to do it is (very) often not my favorite way to do it. But, if I'm working in Python, I'm going to do it that way, anyway. Because social factors matter, and choosing your own convention rarely yields enough benefit to justify choosing not to follow the convention.
But `print 'hi world'` This would really spoil one of the nice consistency things python 3 brought.
Callables without parenthesis to distinguish the arguments. Can you imagine what this is going to do to readability on open source projects?
This was back in June, and probably for the sake of conversation. It got my (and a lot of others) attention, though. If that was the case, mission accomplished.
What is the point? Why is this a desirable thing at all? TFA goes directly into implementation and has not a word about why this is desirable for readability, aesthetics, or any other criterion.
Seems like the sort of faddish syntactic sugar that they love in Swift. Please, not in Python.
> I believe there are some other languages that support a similar grammar
(Ruby? R? Raku?) but I haven't investigated.
Yes you did. And you want to take the good things from ruby. You want no parentheses calls, block syntax instead of lambdas, chainable map/filter/sort/reduce, accessor syntax, you want to extend basic types so you can call methods on literals. You want ruby all over you. Just admit it.
> I believe there are some other languages that support a similar grammar
(Ruby? R? Raku?) but I haven't investigated.
I'm amazed that Guido is not aware of Nim which does precisely this. It works brilliantly too. It would be incredible if Python becomes more like Nim (Nim itself having been inspired a fair bit by Python).
One thing I love about Python is that it's clear when I'm passing a function/method as argument, or aliasing a class, or just generally knowing when I'm calling something vs referencing it.
I do not like this idea. I think it is better to stick to one standard of syntax and do not create several ways of doing same thing without added significant benefit.
I seriously do not see any worthwhile benefit in this, and significant cost.
Benefits:
You can use spaces instead of parenthesis. It's the same number of characters and function arguments won't work with spaces.
Costs:
Python has to support this forever.
Increased complexity.
More difficult to read code, because you could be doing the same thing in multiple ways.
More style guidelines to enforce.
Confusion among new programmers about why they can't use function arguments without parenthesis.
Confusion among new programmers about why they would use spaces instead of parenthesis (or the reverse).
Seriously, I do not see any reason why they would ever want to add this in light of the seemingly obvious costs.
> Missing parentheses in call to 'print'. Did you mean print(1, 2, 3)?
Yes, Python, I meant exactly that! I've never seen this error message in error. Now you know what I mean, please fix it automatically, I know you can do that. Heck, throw a single warning if you really want to enforce this. I can ignore warnings that I don't care about.
I'm not sure whether to take this as an in-joke (knowing the reference is part of the fun) or poor attribution (credits should be given where they're due).
Can't say that I hate it, exactly, but it does make it significantly harder to get into Ruby code when you're not exposed to it daily. Can an amateur woodworker complain their tools are too hard to use if others have no trouble with it and are more productive than with the alternative? Maybe?
So rather than saying that I don't like it, I think what I'd like is some (semi-)objective way of figuring out whether the advantages are worth it. I'm inclined to say it's not worth it, but I don't know.
I don't see any benefits to this, Guido does a good job mentioning many of the negatives .. and, aware of them all, I am surprised he would push on. It seems an unreasonable increase in complexity for no tangible gain.
122 comments
[ 6.0 ms ] story [ 185 ms ] threadsame with `class Foo(object):`
That's still legal, and actually I prefer it even though it's not required in Python 3, because explicit is better than implicit.
But then again, throwing and catching exceptions through arbitrary depths along the call stack is perfectly clear and neat.
That's why I hate them. A programming language is primarily meant to be read by people. If I see something like
What's going on there? Is thing a function? Is noun? Am I passing two arguments to thing, or am I passing the result of invoking the function noun with the argument object?Hell, if I have something like
it certainly looks like I'm calling a function called verb with the argument action, but is the argument I'm giving to verb the actual function action, or the result of evaluating action?Yes, in any given language there's probably a single answer to all of these, but I bet it varies from language to language, and I'd really, really, really rather not waste calories by having my brain try to figure it out.
A = len
But you can in python.
It seems python is adding more and more implicit stuff in every new release.
I think the day we can import braces from __future__ might not be far away.
Behold, bython: https://github.com/mathialo/bython
123 | add10 | str | print
UPD: Some of my workarounds (dont try this at home lol): [twitter thread] https://twitter.com/tandavaya/status/1155925017848242176
If it's the latter, does that mean that the execution environment is part of the language itself, instead of, for example, C where environmental stuff is only accesible through the standard library and the language per se is little more than a context-free grammar?
Yes, that has always be the case with Python in my understanding - there are lots of built-ins...
It's just a syntax change; "print 1 2 3" is still an expression just like "print(1, 2, 3)".
It's an Easter egg.
Python has had multiple ways of doing many things for a very long time, and the longer you program in any language, the more you realize there are often many solutions to a problem and the "best" approach either depends on context or you realize there is no one "best" approach and go on preference.
I think the idea should be judged on its own merits without having to consult the Zen. That said, I seriously don't see the point of it. Python 3 already forced everybody to convert all their print statements to look like function calls, and now GVR wants to bring the old style back as an option? It's just parenthesis, what's the point?
If he wants to put that new parser to work, how about taking another look at multi-line lambdas?
But "solution" and "ways of doing things" from a language perspective are different. You can one way of doing something in a language, yet provide different implementations of the same solution. The difference is how different a "way" is at some level of abstract (vs "syntactic sugar).
Inventing new sentences is needed everyday, inventing new words much rarely so. "programmable program languages" or those highly dependant on custom frameworks fall prey to this: where code becomes a personal space that is hard to break into. You have to "terminate-thought" at some level, if else everyone "creatively" reinvents the low level (e.g. built-ins) then no collaboration is practical; accept the standard building block, and implement your solution with those.
> there is no one "best" approach
but there are "better" approaches
This principle is often repeated for Python, but does it have any bearing on reality today? With every release of Python (and indeed for many other languages), new features give you even more ways of doing things.
Python is 30 years old - it's no longer the small language it may once have been, but is now chock-full of features. Maybe once there was an "obvious way to do it", but I don't thing this is true today.
Just as representing a vector of numbers as a tuple, a list, a dictionary, a numpy matrix or a numpy array. And don't get me started on multidimensional arrays.
So, boo. Hiss.
What I do not like is TMTOWTDI. And I do not like Python violating its own principles (namely, "explicit is better than implicit"). As far as I am concerned, in Python, which does not have partial application, function application is handled by a special `(...)` operator that explicitly applies whatever function comes before the parens to whatever is inside the parens. Making the parens optional gives you two different ways to apply a function - and, by extension, one more place for people to argue about style - one of which is just an implicit version of the other.
You've got to have a way better reason to do that to a language than just, "Hey, isn't this cool? And also, I miss the Python 2 vs Python 3 wars, so wouldn't it be fun to give that pot another stir for old time's sake?"
I get it, the change from a print statement to a print function caused some pain. But it did bring some practical benefits, and the transition is in the past now, and, to quote the Zen of Python again, "special cases aren't special enough to break the rules."
I'm also going to throw another reference to PEP-20 in the mix here: "There should be one-- and preferably only one --obvious way to do it." This implies either forcing parens everywhere or not using them at all. Paired with "explicit is better than implicit", I'd say that points pretty clearly at using parens everywhere.
What about
?Are they the same? Should they be different? I know what the answer is in Python 3.8. A few weeks or months of programming in a Python where parens are optional, though, and I wouldn't be so sure anymore.
To solve the conflict the first parameter cannot start with a paren.
That was my first thought. Why would we turn a simple, binary choice -- "< 3: statement, >= 3: function" into a big old... maybe?
The binary choice hurts, because it dictates changes. Sure. People dislike change, but it's easy to support.
However, there's one thing worse than change, and that's inconsistency and uncertainty. like, in this case, going "zoinks, your change wasn't actually necessary!". Except, now we have both choices. So it'd be even more confusing.
There are several languages that people like for this sort of flexibility, but I think Python's relative rigidity has always been one of its strengths.
edit: And just to be clear, I'm fine with making print a function for all new code. There were ways that the python community could have accomplished that [and the unicode switch] without breaking the entire language.
The problem with that is that the entire python ecosystem had to deal with that instead...
I'm going way past rant territory at this point, but there's a reason that Microsoft and Amazon are worth a trillion dollars a piece, and it's not because of beautiful and elegant APIs.
The following still compiles and runs, on the compiler that comes with the latest OpenBSD:
Somehow the C language has managed to survive and thrive without breaking the canonical example program.Imagine we'd drop HTTPS for a new protocol because it fixes the 'Referrer' spelling error.
Python 3 is the version with breaking changes from 2.x and while stuff is being broken, they decided to fix the print statement.
Python 3 wasn't invented to fix the print statement.
There is no reason to not require parenthesis. No reason.
This is what I hate about Ruby, not having parenthesis gets a bit confusing and adds a couple of gotchas
Print statement is no more. It is gone. It went to meet its maker. Forget about it
Doing away with parenthesis is not syntactic sugar, it's the watermelon seeds that get in the way
Software developers are often stubborn. The main result of this change will be a mess of code which follows a mix of all the styles. That removes one of the greatest beauties of the Python ecosystem, that there is a "right way" to do things.
The Pythonic way to do it is (very) often not my favorite way to do it. But, if I'm working in Python, I'm going to do it that way, anyway. Because social factors matter, and choosing your own convention rarely yields enough benefit to justify choosing not to follow the convention.
Boo, hiss.
The parentheses-less function call is the second biggest obstacle to ruby readability.
But `print 'hi world'` This would really spoil one of the nice consistency things python 3 brought.
Callables without parenthesis to distinguish the arguments. Can you imagine what this is going to do to readability on open source projects?
This was back in June, and probably for the sake of conversation. It got my (and a lot of others) attention, though. If that was the case, mission accomplished.
I'm all for the new parser enabled in Python 3.9 (and switched on by default in 3.10): https://www.python.org/dev/peps/pep-0617/
Seems like the sort of faddish syntactic sugar that they love in Swift. Please, not in Python.
(I fucking hope)
foo (boo, hiss)
should immediately close the issue. What the heck is happening?
Yes you did. And you want to take the good things from ruby. You want no parentheses calls, block syntax instead of lambdas, chainable map/filter/sort/reduce, accessor syntax, you want to extend basic types so you can call methods on literals. You want ruby all over you. Just admit it.
I'm amazed that Guido is not aware of Nim which does precisely this. It works brilliantly too. It would be incredible if Python becomes more like Nim (Nim itself having been inspired a fair bit by Python).
One thing I love about Python is that it's clear when I'm passing a function/method as argument, or aliasing a class, or just generally knowing when I'm calling something vs referencing it.
This is a no-go from the start.
Benefits: You can use spaces instead of parenthesis. It's the same number of characters and function arguments won't work with spaces.
Costs: Python has to support this forever. Increased complexity. More difficult to read code, because you could be doing the same thing in multiple ways. More style guidelines to enforce. Confusion among new programmers about why they can't use function arguments without parenthesis. Confusion among new programmers about why they would use spaces instead of parenthesis (or the reverse).
Seriously, I do not see any reason why they would ever want to add this in light of the seemingly obvious costs.
Yes, Python, I meant exactly that! I've never seen this error message in error. Now you know what I mean, please fix it automatically, I know you can do that. Heck, throw a single warning if you really want to enforce this. I can ignore warnings that I don't care about.
> Python! I learned it last night! Everything is so simple! Hello world is just: print "Hello, world!"
> SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Hello, world!")?
> I dunno... dynamic typing? Whitespace?
> Come join us! Programming is fun again! It's a whole new world up here!
> But how are you flying?
> I just typed: imports antigravity as ag
> TypeError: imports() takes 2 positional arguments but 3 were given
I'm not sure whether to take this as an in-joke (knowing the reference is part of the fun) or poor attribution (credits should be given where they're due).
Parenthesis makes very clear what context you are in.
So rather than saying that I don't like it, I think what I'd like is some (semi-)objective way of figuring out whether the advantages are worth it. I'm inclined to say it's not worth it, but I don't know.