19 comments

[ 9.5 ms ] story [ 71.1 ms ] thread
> Python became the second-most beloved programming language (behind Rust, which is the language people most love telling you they’re learning aspirationally.)

As an aspirational Rust-learner (well, I've read the first chapter of the book) this is spot on. :P

Python has always been sort of an odd language to me. Its syntax has always had a certain strong appeal to a large number of people, but there have always been these underlying performance issues that have been swept under the rug. I was surprised when it started being adopted so much in AI research because of the performance issues (I understand it's really C and other things doing the performing, but at some point you have to do something other than call C, otherwise you might as well just use C).

I do understand the appeal; I think its ergonomics are exemplary and worth being studied by language designers as a success case (if not a perfect or unique one).

Going forward, though, I'd like to see more adoption of languages like Nim, Kotlin, or Julia, that have similar levels of expressiveness but are more performant. The issues discussed in the article aren't really growing pains; they've been there from the beginning.

Many/most AI/quant/data science people aren't exactly the best developers. Often these kinds of people only know one or two different languages and aren't really interested in programming "correctly" in the first place.

In quant finance, for example, once the research quants have developed a strategy (in python or matlab usually), the professional developers have the thankless job of actually implementing it in C++ or whatever.

I think there's a lot of worth using a high level language and integrating with C. It depends on the interface of course, XS (Perl) isn't too user friendly, but actually just using the Python C APIs is straightforward, rather than say Cython for example. I think you get the best of both worlds, but really it depends on what you are trying to achieve. If you want more type safety, then OK maybe not but if you want to interface with some low level components, or want to write a faster algorithm. Basically you can be more focused and granular with the unsafe and more error prone C side and tame it with a higher level language. Anyway, this is just my opinion but I've enjoyed this area very much and it has worked well for me.
Why the downvote? This is just my opinion. I wasn't saying the parent was wrong, this is just my take on it. I'd like to hear some thoughts on people's experience in this area rather than just be downvoted.
> I think there's a lot of worth using a high level language and integrating with C.

I agree.

Python is an awesome high level interface to low level libraries and algorithms. As which it became even more appealing since you can write your low level code in Rust and call it from Python via PyO3 [0].

[0]: https://github.com/PyO3/pyo3

I’ve personally never understood the appeal of Python’s syntax or other language details. The inconsistency over postfix method calls versus builtin or root level functions (like ‘len’) has always been totally inscrutable to me. The weird and unexpected rules about how to interact with multiple kinds of strings (what?). The special self param you are forced to add to method specs so that they don’t match how they are called. And the whitespace rules always struck me as heretical and in practice they just make me feel constantly confused about where to put what. For a long time I thought it was just a matter of working through the learning curve. But I’ve never felt comfortable with it.

All that said, lots of people I deeply respect love the language and I think it ultimately just comes down to some different wiring in our brains about what intuitively makes sense or doesn’t.

> The inconsistency over postfix method calls versus builtin or root level functions (like ‘len’)

Interesting, what inconsistency? My understanding is that the main interfaces the language provides (Sized, Iterable, Container, etc.) are defined in terms of dunder methods that are used by top level functions (len, iter, sorted/reversed). Granted, the python-of-1995 decision that objects like dict or list shouldn't have chainable methods is weird compared to modern ergonomics (like streams), but that decision predates a lot of those practices by decades.

> The special self param you are forced to add to method specs so that they don’t match how they are called.

Is this more, or less magical than a `this` param that is magically accessible in method bodies and references something, though it's not always clear what, especially in the case of nested classes/scopes (Java/JS)?

> The weird and unexpected rules about how to interact with multiple kinds of strings (what?)

Huh? Do you mean unicode/bytes? This isn't really hard. Just use unicode everywhere unless you're dealing with something that is conceptually either a bitstring you're going to do bit-twiddly things to, or an opaque blob of bytes.

E.g. "".upper() vs len("")
Len works on any Sized. Upper only works on strings. There are lots of Sized, there's only one string.
I believe that was a reply to your question:

> Interesting, what inconsistency?

And my point is that there isn't an obvious inconsistency there.

Sized is an interface, exposed via a function. String is a type, which has methods. Now yes, you can make an argument that everything is an interface ("upper-able"). But bleh, and this avoided problems like "is it .length or .length() or .size or .size()" as happened in some other languages.

This appears to be 2 different languages:

"".upper() vs len("")

The first appears to be an object oriented language such as Ruby or Javascript.

The second appears to be some language with plenty of static or built-in functions, such as PHP or C.

This is clearly inconsistent under any definition of inconsistent.

So which would you prefer:

upper([1,2]) (so `upper` is a static builtin) or being unclear on whether its "".len or "".length or "".size or "".size()

Like I said, there is consistency: interfaces are given top level things (builtin functions, operators, language features/keywords), while object methods don't.

To give a recent anecdote, Rust's `x.await`, which is more "consistent", but everyone is complaining because in most languages async interfaces are exposed via something like `await x` instead of an attribute/method-y thing.

> But the other problem, though, is that because Python is (was?) so simple and so ergonomic to use, new developers have been flocking to it, and adopting it for use in building large production systems that might have been better off written in different languages that are much less suited to exploring but more suited to long-term, stable systems.

That statement... first, there isn't any evidence this is true. For the Instagram example, if you're that big, you're going to have scaling issues, but it's an incredible position to be in. I've seen Java GC issues at large scale. That's the price you pay for GC.

That is to say this is a feature, not a bug. CPU is cheap. Productivity is hard. C code can be slow if written badly. Obviously Python isn't without it's trade-offs, but to imply it isn't suited for long-term, stable projects is incorrect.

It takes time for developers to learn a new language. Who's to say they wouldn't have made similar mistakes in other languages?

Again, course there's a trade-off, and Python isn't without it's flaws. But to pretend another language would have solved everything - development doesn't work that way. And scaling issues are a sign of success. You might not have made it that far with another language.

So pick wisely, and build stuff, and remember the choice isn't final.

The part you quoted is not about scalability.
Would you mind being so kind as to explain what it is about then? Saying something is wrong without saying why or how is just noise.
She's talking about Python being a dynamically-typed & interpreted language, making it "simple and so ergonomic to use [for] new developers" and "[suitable] to exploring", but "[less suitable] to long-term, stable systems".

It's not specific to Python. Big projects written in dynamically-typed languages are hard to reason about and maintain. And the lack of compiler makes it harder to catch typos, incorrect types, non-handled null/None values, etc… before runtime.

> And the lack of compiler makes it harder to catch typos, incorrect types, non-handled null/None values, etc… before runtime.

linters exist for a reason. it isn't so clear-cut any more, either, with type hints in python that can now be enforced, although honestly i haven't experimented with that much, since i don't think it's necessary.

> Big projects written in dynamically-typed languages are hard to reason about and maintain.

let's not pretend statically-typed languages are always easier to reason about. throw enough interfaces into a Java project or templates into a C++ project and they're also hard to reason with.

you may have had bad experiences with dynamically-typed stuff, or simply prefer static typing, but these seem more opinions than facts.

and again, i'm happy to argue that it's hard to predict the future. many projects benefit more from the increased velocity dynamically-typed languages offer at the start (the exploration if you will), than trying to build a system for millions of users from the start. that probably makes sense for FAANG projects, but for most it's overkill. so the suitability towards "long-term, stable systems" is half true. hindsight can be powerful, but can also be misleading.