6 ms·
While I can't argue about Python's design decisions impacting the ability to optimise it (not my area of expertise), I'd like to defend these decisions. Subcla
by rollcat 3y ago
While I can't argue about Python's design decisions impacting the ability to optimise it (not my area of expertise), I'd like to defend these decisions.
Subclassing numbers (or other primitive types) is one way to achieve the goal of having type-safe enumerations. In Python, I can do:
class Weekday(int): pass
Monday = Weekday(1)
...
The value x=1 will not pass the test of isinstance(x, Weekday); mypy won't let you accidentally pass April as a Weekday; etc. There definitely are many ways to make this prettier, or easier for an optimising compiler, but I would like to echo DJB's talk referenced by the original article:
> Programmers waste enormous amounts of time thinking about, or worrying about, the speed
of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered.
Likewise, the ability to inspect the stack enables creation of useful tools, that would be difficult or impossible otherwise. When working with pytest, I can write "assert my_array == [1, 2, 3]"; when my_array contains an extra element at the end, my test fails with a pretty-printed diff of the two sides.
You don't need to perform aggressive whole-program optimisation passes when running a test suite, and you shouldn't need to inspect the stack at runtime while executing performance-critical sections in production. I save time and energy by not having to add "print(my_array)", re-running the tests, and copy-pasting the pretty-printed values for diffing. I save time and energy when my program has less bugs, because I had the tools to make it more correct.
- noelwelsh 3y agoI agree those are useful tools, but I think the same goals can be achieved with different tools that don't make optimization hard. For example, type safe enums are one use of so-called algebraic data types found in Rust / Scala / Swift etc. (The language feature is called an enum in these languages, but it can represent a lot more than what people usually think of as an enumeration.)
- rollcat 3y ago100% agree on everything you said. However it's easy to judge Python's mistakes through the lens of where we are right now - nobody even considered tracing JITs for dynamic languages before V8 showed up, and without this perspective, subclassing int could look like the more ergonomic choice. Python could have had ADTs as a core language feature 20+ years ago (rather than sloppily grafting them on in a recent release), just like it could have had unicode strings as the default text type since before 2.x (1.6 was 2000; unicode was early 1990s). But it also had a much smaller community back then, and who knows how making these choices back then would've impacted its development? Maybe it'd end up being as relatively obscure as say Tcl. Also I think you could still achieve reasonable optimisations even if you do go that route; Go has type aliases (including on primitive types) that you can define custom methods on: type Weekday int const ( Monday = Weekday(1) ... ) func (w Weekday) Name() string { switch w { case Weekday(1): return "Monday" ... default: panic("?") } } If your compiler could prove nothing crazier than that is happening with your int subclass, I don't see why similarly written Python code should have a lower performance ceiling; but yes, that's more work for the compiler.