Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It turns out that if you have language semantics that make optimizations hard, making a fast optimizing compiler is hard. Who woulda thunk?

To be clear, this seems like a cool project and I dont want to be too negative about it, but i just think this was an entirely foreseeable outcome, and the amount of people excited about this JIT project when it was announced shows how poorly a lot of people understand what goes into making a language fast.



I was active in the Python community in the 200x timeframe, and I daresay the common consensus is that language didn't matter and a sufficiently smart compiler/JIT/whatever would eventually make dynamic scripting languages as fast as C, so there was no reason to learn static languages rather than just waiting for this to happen.

It was not universal. But it was very common and at least plausibly a majority view, so this idea wasn't just some tiny minority view either.

I consider this idea falsified now, pending someone actually coming up with a JIT/compiler/whatever that achieves this goal. We've poured millions upon millions of dollars into the task and the scripting languages still are not as fast as C or static languages in general. These millions were not wasted; there were real speedups worth having, even if they are somewhat hard on RAM. But they have clearly plateaued well below "C speed" and there is currently no realistic chance of that happening anytime soon.

Some people still have not noticed that the idea has been falsified and I even occasionally run into someone who thinks Javascript actually is as fast as C in general usage. But it's not and it's not going to be.


> I was active in the Python community in the 200x timeframe, and I daresay the common consensus is that language didn't matter and a sufficiently smart compiler/JIT/whatever would eventually make dynamic scripting languages as fast as C, so there was no reason to learn static languages rather than just waiting for this to happen.

To be very pedantic, the problem is not that these are dynamic languages _per se_, but that they were designed with semantics unconcerned with performance. As such, retrofitting performance can be extremely challenging.

As a counterexample of fast and dynamic: https://julialang.org/ (of course, you pay the prize in other places)

I agree with your comment overall, though.


I'm sort of surprised I'm not seeing any modernized dynamic scripting languages coming out lately, despite the general trend towards static languages. A fast dynamic language, with a day-one concurrency story, and some other key feature that pushes it ahead seems possible to me. (I dunno, maybe a nice story for binding to Rust instead of binding to C at this point could be enough to lift a language off?) I don't see any reason why dynamic scripting languages as a category couldn't do that. The ones we have now don't, not because the category makes it impossible, but because by the time that was desirable they just had too much baggage, and are all still struggling with it even a decade after they started.


> A fast dynamic language, with a day-one concurrency story

That's pretty much what Erlang claims to be. Of course people will always quibble with "fast".


I do quibble with fast, and I also quibble with "dynamic language". Its variables are untyped, but that about ends the "dynamicness" of the language. It's not what people mean.

Elixir is closer, though BEAM in general still leaves a lot of performance on the table. I'm somewhat surprised that tracing JITs and stuff have not managed to make more progress than they have, but it could be lack of developer time. Unfortunately JITs eat that voraciously.

I'd expect this to be a mutable language, though part of that "day one concurrency story" could be an inability to transmit references between something like Erlang "processes".


Welcome to Elixir. A concurrency story baked into its architecture, Rustler for trivial Rust bindings, a full set of project tooling (package management, deployment handling, etc). And a killer combo of database bindings in the form of Ecto and a best-in-class web framework from Phoenix.

And it's got an unusually broad base of existing libraries for how young it is, both because writing bindings is really easy, and because you can import Erlang libraries which have been around since the 80's.


> fast dynamic language, with a day-one concurrency story

simple dynamic scripting languages target people without serious CS background

concurrency is a footgun best hidden from such people, they are not ready for it


What are examples of those semantics? I'm guessing rebindable functions (and a single function/variable namespace), eval(), and object members available as a dict.


Some examples that come to mind: You can inspect the call stack, and get a list of local variables of your callers. You can assign to object.__class__ to dynamically change an existing object's class at runtime. You can overwrite every operator, including obj.field access, dynamically at runtime (including changing an existing class)


a long time ago, there was Parrot and a bet with Guido https://justatheory.com/2004/08/oscon-notes/


This is all true, but there's another angle that often gets missed:

JITs are really only ideal for request-processing systems, in which a) memory is abundant b) the same code paths run over and over and over again, and c) good p99 latency is usually the bar.

In contrast, in user facing apps, you usually find that a) memory is constrained b) lots of code runs rarely or in some cases once (e.g. the whole start-up path) c) what would be considered good p99 latency for a server can translate to pretty bad levels of jank.

JITs can't do anything if the code you care about runs rarely and causes a frame skip every time you hit it, either because the JIT hasn't triggered yet due to too-few samples, or the generated code has been evicted from the JIT cache because you don't have memory to spare. And if you have code that needs to run fast _every_ time it runs, the easiest way to do that is to start with fast code already compiled and ready to execute.

We saw this play out when android moved from Dalvik (JIT) to ART (AoT compilation). Apple figured this out years earlier.

Of course it's not that there are no highly performant apps built on JIT runtimes. But it's a significant headwind.

(Most of the above applies equally to tracing GC, btw)


You missed the part where Android moved into caching JIT code with a mix AOT mode compilation, since Android 7 thus avoiding those issues. Latest version is Android 16, many other optimization happened since then.

Also that Android followed up on Windows Phone model, their mistake was making the AOT compilation on the phone instead of on the store like Windows Phone was doing.

JITs are very capable, provided people also design with them in mind.

The clever Apple with AOT failed against this now famous benchmark, against tracing GC languages, using a JIT.

https://github.com/ixy-languages/ixy-languages


While what you say is true, there is still a huge gap between the performance of javascript (and even Ruby) and that of Python. The efforts to optimize Python are lagging behind, so there is a lot of things that still can be made faster.


Python is also choosing to play with one hand behind its back; e.g., the “no extension API changes” rule which means any hope of a faster value representation (one of the most important factors in making a dynamic language fast!) goes out the window, refusing to change the iterator API (which means that throwing and handling exceptions is something that needs to be handled by the fast path of basically everything), and so on.


Those changes are big enough that they’d need to be a Python 4, don’t you think? Community is still gun why after the 2-3 transition pain.


The biggest problem of the Python 3 release was that it broke a bunch of _Python_ code. That's pretty different from changing the C API. But sure, it has ups and it has downs. One of the downs is that Python, despite a lot of announcements over the years, still is struggling to become significantly faster.


yeah. Python is somewhat trapped here. because Python is slow, real work gets moved to C, and the C api makes it almost impossible to speed Python up. If Python had made the API changes needed for speed 20 years ago, there would be way less C code, so further changes would be easier, but that ship has now basically sailed


It could have made the changes in the 2->3 transition.

Instead we got parentheses around print.


Google has been pouring huge amounts of effort into making their JS interpreter fast for many years at this point. They have a lot more resources than the Python foundation.


At one point, Google was also interested in pouring lots of money into making Python faster, and they shifted those resources away.

I think what always ends up failing here is that, as others have stated, they won't make breaking API changes, in particular those in charge of driving Python forward are extremely hesitant to break the C API for fear of losing packages that have make Python so popular.

I would imagine, if the leadership was willing to put in the elbow grease to help those key packages along the changes when they happen, they could do it, but I understand that its not always that simple


Meta does some work for this with Cinder, but Meta has a history of language forks, and it's far enough off the beaten track that I wouldn't use it.


cinder team member here - we are putting a lot of work into having cinder converge with rather than diverge from mainline cpython. the main idea is to get support for pluggable JITs into cpython, and then have cinder use those APIs to work as a regular extension module.


Microsoft had the Faster CPython team for several years, and then recently laid off some of the core devs and the team lead.


I remember this from the early 2010s "compilation of a dynamic language is a superset of compilation of static languages ergo we should be able to achieve both optimizations static languages can do and more because there are opportunities that only become apparent at runtime". When really its all about the constraints you can put on the user that set you up for better optimization.


And profile-guided optimization (PGO) for static languages turned out to be pretty good at revealing those “only apparent at runtime” optimizations.


That's like the joke that dynamic languages are static languages, but with only one type: hash table.


That's not a joke. It's a perspective that is seriously held: https://existentialtype.wordpress.com/2011/03/19/dynamic-lan...

(Not everyone agrees, for sure, but that's different from it being a joke.)


Javascript and Common Lisp aren't as fast as C but they are faster than Python.


Javascript and common lisp don't have object models that are as anathema to optimization as python does. Well, CLOS is pretty bad, but at least the badness is typically isolated.


Python is definitely slower for programs that do the same thing. What I see is that the users of fast languages often write programs that do the wrong thing, 30x faster than Python. No free lunch either way


I don’t understand the sentiment of not wanting to learn a language. LLMs make learning and understanding trivial if the user wants that. I think many of those complaining about strongly typed languages (etc) are lazy. In this new world of AI generated code, strongly typed languages are king


Especially when one keeps ignoring the JITs of dynamic languages, that were in the genesis of all high end production JITs being used nowadays, tracing back to Smalltalk, Self, Lisp, Prolog.

All those languages are just as dynamic as Python, more so given the dynamically loading of code with image systems, across network, with break into debugger/condition points and redo workflows.


Agreed. I'd like CPython to offer the possibility to opt in semantics that are more amenable to optimizations, similar to what Cider is enabling with their opt-in strict modules and static classes: https://github.com/facebookincubator/cinder.


The semantics of Python-the-language aren’t any worse than JavaScript’s for optimization.

Something else is going on.


pypy manages


The black swan of Python JITs, mostly ignored by the community, unfortunately.


Pypy is only "fast" relative to CPython. In all other metrics it's still very slow, and it comes at the cost of making interop with actually fast languages much harder and slower. It's basically useless.


> It turns out that if you have language semantics that make optimizations hard, making a fast optimizing compiler is hard. Who woulda thunk?

Is this in the article? I don't see Python's semantics mentioned anywhere as a symptom (but I only skimmed).

> shows how poorly a lot of people understand what goes into making a language fast.

...I'm sorry but are you sure you're not one of these people? Some facts:

1. JS is just as dynamic and spaghetti as Python and I hope we're all aware that it has some of the best jits out there;

2. Conversely, C++ has many "optimizing compiler[s]" and they're not all magically great by virtue of compiling a statically typed, rigid language like C++.


JS is absolutely not as dynamic as Python. It supports `const`ness, and uses it by default for classes and functions.


More importantly, there's nothing like locals[] or __getattribute__.


Smalltalk has them, and its JIT research eventually became Hotspot.

Anything can change at any time in Smalltalk.


And then we find out that Smalltalk implementations might choose to optimize instead of allowing anything to change at any time.

    ifFalse: alternativeBlock 
        "Answer the value of alternativeBlock. Execution does not actually
        reach here because the expression is compiled in-line."

        ^alternativeBlock value


One tree doesn't make a forest, from whatever implementation that was taken out of, and naturally there are always magician tricks that PyPy also uses.


*iirc* pretty much all of the Smalltalks (that was CUIS).

    ~
"Creating blocks in Smalltalk has always been a potential source of performance problems. … In Resilient, we have restricted blocks to be last in-first-out (LIFO)…"

https://blog.bracha.org/resilient-paper.pdf

    ~
"Digitalk’s Team/V unobtrusively introduced a non-reflective syntax…"

https://wirfs-brock.com/allen/posts/914


Strongtalk limited dynamic features.

But you’re not wrong in general. Even for Python there’s PyPy, with a JIT ~3x faster than CPython.


Strongtalk was the transition step between Smalltalk JITs and what became Sun's Hotspot, but that wasn't the main point I was making.

Also to note that even in that regard, Java happens to be more dynamic that people think, while the syntax is C++ like, the platform semantics are more akin to Smalltalk/Objective-C, hence why a JIT with such a background was a great addition.


There's a pretty big gap between "its JIT research eventually became Hotspot" and "Smalltalk can be made to perform on a par with Hotspot."


HN comments usually aren't big enough for a CS lecture regarding evolution of dynamic compilation, aka JIT.

There is enough stuff to fill at least one semester.


yes there is: https://wiki.python.org/moin/UsingSlots

people really don't know enough about this to be talking about it with such confidence...


I was pointing examples of the opposite, that JavaScript is less dynamic than Python.

There's lots of Python code out there that relies on not using slots. If you're making a JIT, you can't assume that all code is using slots.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: