Live data from Hacker News

A tail calling interpreter for Python (already landed in CPython)

blog.reverberate.org

61–70 of 93 posts

Re: A tail calling interpreter for Python (already landed in CPython)

#61

Will Python ever get fast? Or even _reasonably_ fast? The answer is no, it will not. Instead they'll just keep adding more and more syntax. And more and more ways to do the same old things. And they'll say that if you want "fast" then write a native module that we can import and use. So then what's the point? Is Python really just a glue language like all the rest?

The JIT will improve - you can also use PyPy to get speedups on programs that don't use a ton of C extensions. Also, free-threading is coming so we'll have threads soon. I don't know if Python can every really be fast as by design, objects are scattered all over memoryand even things like iterating a list, you're chasing pointers to PyObject all over the place - it's just not cache friendly.

PyPy has a list implementation that specializes under the hood. So if you stuff it with integers, it will contain the integers directly instead of pointers to them. That's at least how I understood it.

Re: A tail calling interpreter for Python (already landed in CPython)

#62
post #57
post #43

Earlier quoted context omitted.

I disagree. An optimization that speeds a program by x2 has the same effect as running on a faster CPU. An optimization that packs things tighter into memory has the same effect as using more memory. Program semantics are usually referred to as “all output given all input, for any input configuration” but ignoring memory use or CPU time, provided they are both finite (but not limited). TCE easily converts a program t…

> I probably won’t argue that a change that reduces an O(n^5) space/time requirement to an O(1) requirement is a change in semantics, even though it practically is a huge change Space/time requirements aren't language semantics though, are they?

it changes debug semantics

this is the reason guido avoids it. programs will still fail, except now without a stacktrace

Re: A tail calling interpreter for Python (already landed in CPython)

#63

Earlier quoted context omitted.

Modern C compilers are able to transform something like this: for (int i = 0; i To: a += n * (n+1) / 2; Is this an optimisation or a change in program semantics? I've never heard anyone call it anything slse than an optimisation.

This will get a bit pedantic, but it's probably worthwhile... so here we go. > Is this an optimisation or a change in program semantics? Note that I specifically said something can be both an optimization and a change in semantics. It's not either-or. However, it all depends on how the program semantics are defined. They are defined by the language specifications. Which means that in your example, it's by definition…

You do have a point. However, if I'm allowed to move the goalposts a little: not all changes in semantics are equal. If you take a program that crashes for certain inputs and turn it into one that is semantically equivalent except that in some of those crashing cases, it actually continues running (as if on a machine with infinite time and/or memory), then that is not quite as bad as one that changes a non-crashing result into a different non-crashing result, or one that turns a non-crashing result into a crash.

With this kind of "benign" change, all programs that worked before still work, and some that didn't work before now work. I would argue this is a good thing.

Re: A tail calling interpreter for Python (already landed in CPython)

#64
post #24

Earlier quoted context omitted.

Any examples? The biggest change since Guido stepped down has been the addition of pattern matching, which he was strongly in favour of. Moreover, Guido is in favour of ongoing addition of major new features (like pattern matching), worrying that without them Python would become a “legacy language”: https://discuss.python.org/t/pep-8012-frequently-asked-quest...

I was thinking of the walrus operator, various f-string changes, relenting on the "GIL removal must not cost performance" stance (although"covered" by other improvements), things like that. I don't follow python closely so it may 100% be stuff that GvR endorsed too, or I'm mixing up the timelines. It just feels to me that python is changing much faster than it did in the 2.x days.

This may just be time passing faster now that you're older.

Re: A tail calling interpreter for Python (already landed in CPython)

#65
post #48

Earlier quoted context omitted.

Pattern matching seems like a cool feature that was added just because it was cool. I think the syntax is really odd too - apparently to “be pythonic”. I really see no use for it other than to “look smart”. The fact that case match (switch case is a much better description) is expanded to practically a huge if else is disturbing. Similarly the walrus operator. Other than an answer to “what is a new feature of python…

Yeah, it was added to tick the box for people who ask "does Python have pattern matching?" If you look at the feature in detail, and especially how it clashes with the rest of the language, it's awful. For example: https://x.com/brandon_rhodes/status/1360226108399099909

To be fair, "The Substitution Principle" (more commonly known as "equational reasoning" in this context) has never been valid in any languages that aren't... Haskell, and maybe Ada? Any expression that can trigger side effects is an unsafe substitution. (The reason such substitutions are safe in Haskell and Ada is that those languages prevent expressions from triggering side effects in the first place.)

Re: A tail calling interpreter for Python (already landed in CPython)

#67
post #3

Earlier quoted context omitted.

That's probably one of the more frustrating things about Python. Each release it gets all sorts of questionable new syntax (including the very strange pattern matching "feature" that kind of sucks compared to something like Erlang or Scala), but we never get real useful quality of life improvements for basic functional programming like TCO or multi line lambdas

Python has always been unashamedly imperative, with some functional features entering by slipping through the cracks. The pattern matching thing seemed ok to me when I tried it, but I haven't used it except briefly, since I'm still mostly on Python 3.9. Interestingly, Python has been losing users to Rust. I don't entirely understand that, other than everyone saying how Rust's tooling is so much better.

I'm largely still a Python user, but when I've used it, rust overall gross way more thoughtfully and consistently designed— both in the core language features and in the stdlib.

Python's thirty years of evolution really shows at this point.

Re: A tail calling interpreter for Python (already landed in CPython)

#68
post #65
post #48

Earlier quoted context omitted.

Yeah, it was added to tick the box for people who ask "does Python have pattern matching?" If you look at the feature in detail, and especially how it clashes with the rest of the language, it's awful. For example: https://x.com/brandon_rhodes/status/1360226108399099909

To be fair, "The Substitution Principle" (more commonly known as "equational reasoning" in this context) has never been valid in any languages that aren't... Haskell, and maybe Ada? Any expression that can trigger side effects is an unsafe substitution. (The reason such substitutions are safe in Haskell and Ada is that those languages prevent expressions from triggering side effects in the first place.)

This isn't about general substitutability though, just about naming constants. If you have `case 404:` and you add a named constant `NOT_FOUND = 404`, you can't change the code to `case NOT_FOUND:` because that completely changes its semantics.

Given that one of the fundamental rules of programming is "don't use magic numbers, prefer named constants", that's terrible language design.

Re: A tail calling interpreter for Python (already landed in CPython)

#69
post #57

Earlier quoted context omitted.

> I probably won’t argue that a change that reduces an O(n^5) space/time requirement to an O(1) requirement is a change in semantics, even though it practically is a huge change Space/time requirements aren't language semantics though, are they?

it changes debug semantics this is the reason guido avoids it. programs will still fail, except now without a stacktrace

GvR always prioritised ease of debugging over performance, and honestly I'm in the same camp. What good does a fast program do if it's incorrect?

But I think you can get a fine balance by keeping a recent call trace (in a ring buffer?). Lua does this and honestly it's OK, once you get used to the idea that you're not looking at stack frames, but execution history.

IMHO Python should add that, and it should clearly distinguish between which part of a crash log is a stack trace, and which one is a trace of tail calls.

Either way this is going to be quite a drastic change.

Re: A tail calling interpreter for Python (already landed in CPython)

#70
post #3

Earlier quoted context omitted.

That's probably one of the more frustrating things about Python. Each release it gets all sorts of questionable new syntax (including the very strange pattern matching "feature" that kind of sucks compared to something like Erlang or Scala), but we never get real useful quality of life improvements for basic functional programming like TCO or multi line lambdas

The choice of “unique” verbs is weird too. Case match. Try except?

`match/case` looks absolutely fine to me. What's the problem?

`try/except` is definitely weird, though.

Post reply on HN