6 ms·
> Over time, we’ve had a trend of adding unnecessary, low-payoff complexity to the language. Cumulatively, it has greatly increased the mental load for newcomer
by js2 8y ago
> Over time, we’ve had a trend of adding unnecessary, low-payoff complexity to the language. Cumulatively, it has greatly increased the mental load for newcomers and for occasional users.
I couldn't agree more with this sentiment from Raymond Hettinger. I first learned Python starting with 1.5.2, and coming from a background of C and Perl. One of the things that really attracted me to the language was how compact it was. It took no more than an hour to learn most of the language, a day to read the entire spec, and maybe a second day to read the entire standard library documentation. It suffered from virtually no gotchas... nothing crazy like Perl's scalar vs list context, etc.
I haven't had trouble keeping pace with Python and I even probably agree with most of its changes. But this change really seems superfluous. How does it fit into the zen?
Can a language ever reach a point of being done?
- hangonhn 8y agoI feel the same but about Java. I feel that with Java, however, it is much, much worse because of its enterprise friendliness and thus being much more reluctant about breaking changes to the language. I would love to see certain features getting dropped from languages as new ones are added. I think Python has done an okay job of keeping the language consistent and simple and cleaning up the libraries, etc.
- js2 8y agoFunny enough, I first used Java in 1995 or so. What a nice little language I thought then. I then managed to avoid it through its enterprise madness of the 2000s and finally started using it again around 5 years ago. It's still bureaucratic but I don't find the language itself complex.
- red_hare 8y agoYou're not alone. My goto example of this is the pathlib module added in 3.4. It has this feature for making it easier to concat strings representing file system paths... >>> from pathlib import Path >>> Path("foo/bar") / "baz" PosixPath('foo/bar/baz') Don't get me wrong, the existing solutions until pathlib (os.path.join or string concatenation) left a lot to be desired. And there are certain tricky path-parsing things this module does that are wonderful. But overloading the __div__ operator for a "cute" API just feels... wrong... Of course, after my initial disgust, I now use it everywhere :)
- masklinn 8y agoNote that you don't have to use `/` to do this, you can use Path.joinpath or call Path/PurePath with multiple path segments.
- emidln 8y agoThis is very much TIMTOWTDI. Larry Wall would be proud.
- ben509 8y agoI think part of the reason Wall adopted TIMTOWTDI as a design is because he observed that it's what happens anyway, so you may as well embrace it.
- ken 8y agoThe first time I used Python on a team, I learned that "One Obvious Way" was a lie. In order to achieve OOW, you need really high-level features (assembly language programmers have every possible way to accomplish a task!), but also a very limited set of them (so nobody can pick the 'wrong' one). But as a general-purpose programming language, users also need power and flexibility. It's an unstable tripod where as soon as one starts getting higher, you mess up the others. I can tell they've been trying to slowly raise all three (and deprecate/remove old and lower-level pieces from the bottom), but it's a delicate balancing act, and it's easy to run into other constraints, like complexity.
- okasaki 8y agoI'm not sure why it's wrong? Python isn't Haskell. If you're dealing with path manipulation a lot, it makes for much more readable code.
- ehsankia 8y agoI'm curious, why not override the usual + operator, which is far more idiomatic, instead of trying to get cute by using using an operating which generally implies division. Yes, it's fun once you understand it, but at a first look, it's more confusing than useful, whereas + would be fairly self explanatory.
- masklinn 8y ago> I haven't had trouble keeping pace with Python and I even probably agree with most of its changes. But this change really seems superfluous. How does it fit into the zen? Explicit is better than implicit, Simple is better than complex, Readability counts, I'm sure others would match. Positional-only parameters are useful in general and even necessary to implement / override APIs originally defined in / for C (which has always had access to positional-only parameters). Currently, defining an optional positional-only parameter is: def foo(*args): if len(args) > 1: raise TypeError(f"Expected at most 1 argument, got {len(args)}") if args: arg = args[0] […] * the number (and optionality) of positional parameters is completely invisible and implicit rather than readable and explicit * it requires various non-trivial assertions repeated every time By contrast, with PEP 570 this becomes: def foo(arg=None, /): […] It does require the knowledge of "/" but spells out exactly what the contract is clearly, cleanly, and without requiring additional developer legwork.
- js2 8y agoI read the PEP and understand the argument (no pun intended). I'm just not convinced. I don't find the justifications given in the PEP at all persuasive. Rarely have I ever needed to enforce positional over keyword arguments and the rare times I've needed to, I can use: *args, **kwargs as needed, and again, don't find the PEP's arguments against doing so convincing. Also, I mean, come on, if a function signature is: ord(c) It's pretty damn obvious not to use "c" as a keyword argument. And as hard as it is for programmers to name things, I can't recall ever struggling to name a function parameter. If you need to rename a parameter that it's likely someone might be calling as a keyword, then bite the bullet and break backwards compatibility or just introduce a new function name if backwards compat is truly that important. (And besides, this has to be one of the more trivial checks for a static analyzer to find.) > the number (and optionality) of positional parameters is completely invisible and implicit rather than readable and explicit It's invisible in the function signature, but it should be in the function documentation or as a last resort, read the source. I find myself reading Python library source code not infrequently because it's not unusual to need to understand a function's behavior. Getting the function call correct is like the least hard part? But again, this really feels like an edge case. > it requires various non-trivial assertions repeated every time. In fact, that's a pretty trivial assertion if you ask me. ¯\_(ツ)_/¯. FWIW, I don't find: (arg=None, /) to be a legible syntax for declaring "this function takes a single optional positional argument". And in its full form, this is truly ugly: def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): Seriously, WTF. The library author couldn't make up their mind about pos_or_kwd? Why even allow that? This is no better: def f(pos1, pos2, /, *, kwd1, kwd2): Just no. Maybe I'd be more convinced with a cleaner syntax. I think the Per-Argument Marker option proposed in the PEP is a lot more obvious (not sure about using a '.' though) and think the argument against it is pretty weak: "While this approach may be easier to read, it has been rejected because / as an explicit marker is congruent with ∗∗ for keyword-only arguments and is less error-prone." I note that "less error-prone" is stated without evidence and that "is congruent with ∗∗" is definitely against the zen. But generally, as I said, the entire PEP is not convincing to me. Anyway, I'm sure I'm repeating the arguments against the PEP others have made and Guido has ruled in favor anyway, so I'm just screaming at the ocean.
- username223 8y ago> Can a language ever reach a point of being done? TeX? Yes, I know there are still new releases occasionally, but as far as I know, it's feature-complete, and only occasionally gets bug fixes. I wish the developers of more languages, and software in general, would recognize when their projects were done. Unfortunately, that doesn't seem to be the way things are headed.
- mattbillenstein 8y agoI've asked this question too and what I think what is going on is that the python dev community is still pretty active - and people love to change things, get their code and ideas into the language. I think they've been pretty good about rejecting a lot of the really awful stuff, but not as good maybe at thinking about what is really necessary. And this type of discussion makes me think about Django - it used to be a nice little simple framework, then it got a big community around it and grew every nature of features to such a point that I think nobody should actually use it. The code ends up being pretty awful and I think probably the rise of Flask coincides with Django getting too big and too complex over a period of years.
- rozap 8y agoJose Valim has said that there is no plan for an Elixir 2.0, because he feels it is pretty much "done" in terms of major features. It's a refreshing change.
- jerf 8y agoI've stopped recommending Python as a new language for people. It was my go-to for a long time, but after sitting with a couple of people trying to learn it, I discovered the hard way that it has passed the "easy-to-learn" horizon a long time ago. I am deeply unconvinced the proliferation of features is even remotely necessary or helpful. But then, I admit I've become deeply skeptical of the whole "language as a proliferation of features" model of language development in general. Python is just a particularly frustrating example because it's a clear case of a useful simple language becoming a huge, complex language that isn't really that much more useful. I'm coming around to what doesn't go into a language being more important, because there's always another feature the language needs and always some reason to put it in. If you don't have a clear thesis on why and how you're going to reject things, you won't often enough.
- wDcBKgt66V8WDs 8y agoCan you expand on what you think has become difficult and what you recommend now?
- jerf 8y agoThe big problem is when the beginner first encounters some external code. One particular case was trying to teach a QA automation engineer about what was going on. First of all, I was having trouble tracing back all the definitions involved due to the excessive "cleverness" involved in assembling the API, but we'll put that down to the testing API doing things it shouldn't. The problem I had was that I had to explain "oh, well, this is a generator because of the yield, and the arguments don't show up in the documentation for the function because it's introspecting on the keywords you pass in dynamically, and this here is a generator comprehension with its own syntax, and this is what the decorator on top is doing on this code, which is why this is breaking" and honestly it kept going like that for a while. When it all worked it was fine, but when anything broke, it's become far too easy in Python, and arguably idiomatic Python, to erect a rather intimidating wall of features and automatic rewirings and fancy decorators and suddenly to fix their problem the novice is swallowing all of twenty years of language development in one shot... or they give up and do something else. I don't have a current go-to recommendation, though I've found myself recommending "Go but stay away from any concurrency features for a good long time" a few times. Ignoring all the other controversies that HN likes to indulge in, that's not a half-bad intro to "real programming" for a modern language. It's not the only good choice, of course.
- Animats 8y agoUnchecked type annotations were when change for the sake of change seemed to take over in Python.
- mzs 8y agopython lost the 'only one obvious right way' zen long ago sadly.
- agumonkey 8y agoperl is hard only if you come from a certain point trust me, if you have no apriori regarding what a programming language is, perl will make a lot of sense
- js2 8y agoWell if you want my path it was something like: BASIC, 6502 assembly, Fortran, Pascal, C, C++, Scheme, Perl, shell (sh, tcsh, sed, awk, etc), Java, Python. A bit of PHP in there somewhere. Some TCL and lua and ruby too. I may have the order a bit mixed up. I started with perl 4 and got to be reasonably adept, using it as my primary language from maybe 96-2000. I've used Python as my primary language since 2000. I'm pretty fluent in C, Java, Objective C and shell. Anyway, I had to fix a couple hundred line Perl script the other day and it had me scratching my head for long enough that I was pretty close to rewriting the whole thing in Python. One thing I really love about Python is that it's trivial to test bits and pieces of code via the REPL.
- agumonkey 8y agoyou have a point, perl might give too much linguistic rope for people to hang themselves and future maintainers, but I'd slightly argue that it's because people don't grasp the nature of contexts