6 ms·
This gives the impression that Python, similar to C++. might have entered a competition between popular languages which one can accumulate the most popular fea
by jnxx 6y ago
This gives the impression that Python, similar to C++. might have entered a competition between popular languages which one can accumulate the most popular features.
Obviously, pattern matching comes from the ML family and functional Lisps like Clojure. What makes it a difficult integration into Python is that in languages such as Rust, OCaml, Haskell, but also Racket and Clojure, almost everything is an expression, and name bindings are, apart from a few exceptions, always scoped. Consequently, pattern matching is an expression, not a statement.
A similar issue is that Python 3 tried to become more "lazy", similar to how Haskell and Clojure are - this is the reason for replacing some list results with generators, which is a subtle breaking change. Lazy evaluation of sequences is nice-to-have on servers but its importance in Haskell and Clojure comes from them being functional languages which are geared towards a "pure" (side-effect-free) style, in which they differ a lot from Python.
My impression is also that over time, Python has really absorbed a huge number of features from functional Lisp dialects. This might seem surprising. Well, here are some things that modern Lisps like SBCL, Schemes and functional languages on the one hand side, and Python 3 do have in common:
* a Read-Eval-Print Loop (REPL)
* strong dynamic typing
* automatic memory management
* memory safety
* exceptions
* a wide choice of built-in data types: lists, strings, vectors, arrays, dictionaries / hash maps, tuples, sets
* keyword arguments and optional arguments in functions
* handling of names in scopes and names spaces
* closures and lambda functions
* list comprehensions
* pattern matching (limited support for tuples and lists in Python)
* Unicode strings
* arbitrarily long integers
* complex numbers
* rational numbers
* number type are part of a hierarchical type hierarchy (numeric tower)
* empty sequences, containers and strings are logically false
* support for threads (but no real parallelism in Python)
* low-level bit operations (a bit limited in Python)
* easy way to call into C code
* type annotations
* if ... else can be used as an expression
* string formatting is a mini language
* hexadecimal, octal and binary literals
* standard functions for functional programming like map and filter
* support for OOP (e.g. by the Common Lisp Object System)
* support for asynchronous execution
What is notably missing from this list is parallelism (as opposed to concurrency); Python simply does not support it in a practical way, while some functional languages do support it extremely well.
The net result of this creeping featuritis appears to be that Python, which is still classified as "beginner friendly", is now actually significantly more complex than a language like Racket or Clojure, perhaps because these features are often not integrated that well. I even think that Rust, while clearly being targeted at a very different domain, is more streamlined and well-composed than Python.
What is also worth mentioning is that these functional languages have seen steady improvements in compilers and performance of generated code, with the result that Rust code is now frequently at least as fast as C code, SBCL is within arms reach of C, and Clojure and Racket are about in the same league as Java - while Python code in comparison continues to be extremely slow:
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/python3-java.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/lisp.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/racket-java.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/ocaml-java.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
- duckerude 6y agoHas it absorbed features from functional Lisp dialects, or does it just have features in common? Early Python was inspired by ABC and C. ABC has a Python-like REPL, strong dynamic typing, automatic memory management, memory safety, a nice collection of built-in types, arbitrarily long integers, and rational numbers. C has low-level bit operations, (an easy way to call into C code,) a ternary expression-level if-else operator (and make no mistake, Python's expression-if is a ternary operator that's distinct from the statement-if-else), and hexadecimal and octal number literals. There is at least a little influence from functional Lisps (Mypy lists Typed Racket as one of its influences), but a lot of what you list was taken from different languages, or is distinctly un-Lisp-like in Python, or was in Python from the start rather than absorbed over time, or is just obvious enough to put in a very high-level language to be reinvented. It's also important to distinguish between internal complexity and user complexity. Arbitrarily long integers are complex to implement, but easier to use than fixed-length integers. Even features that do have a lot of user-facing complexity can be very easy to use in the common case. Python is hideously complex if you explore all the tiny details, but I'm not sure that it's all that complex to use. But I haven't used Clojure and Racket so I can't really comment on them. > I even think that Rust, while clearly being targeted at a very different domain, is more streamlined and well-composed than Python. I think I agree. But Rust has the benefit of only dealing with a measly five years of backward compatibility. Python has accumulated complexity, but the alternative would have been stagnation. If Python hadn't significantly changed since 1996 it would be more streamlined but also dead. > What is also worth mentioning is that these functional languages have seen steady improvements in compilers and performance of generated code, with the result that Rust code is now frequently at least as fast as C code I don't think Rust suffers from the issues that make functional languages hard to compile, so that might be a bad example. In Rust code it's unambiguous where memory lives. It has functional features augmenting a procedural model, rather than a functional model that has to be brought down to the level of procedural execution. So it might be "merely" as hard to optimize as C++.
- jnxx 6y ago> C has low-level bit operations, As an unrelated fun fact, Common Lisp has more low-level bit operations than C, such as "and complement of integer a with integer b" or "exclusive nor": http://www.lispworks.com/documentation/HyperSpec/Body/f_logand.htm http://www.lispworks.com/documentation/HyperSpec/Body/f_loga... It also has logcount, which is the counterpart to the implementation-specific popcount() in C.