The single example I typically give is that in Python you can inspect stack frames after they've exited! This has concrete implications on your VM design.
Another example is that the multiple dispatch protocol for binary operations (such as addition) is sufficiently complicated that you generally cannot encode it into your compiler. We have been able to have a simplified version of that by building a tracing JIT for C, which is able to understand the dispatch protocol, but it is not always applicable.
Source: I've been working on Python optimization for several years as part of the Pyston project.
Also I think Python’s truthy/falsey semantics make it dangerously close to being weakly typed.
How about an implementation of python that doesn't let you do fancy things like that that are not needed in production?
People have tried, pypy started with that goal before it became clear it wasn't practical.
https://markmail.org/message/dp56i26zhpf4fehb#query:+page:1+...
How does that work and what is it used for?
From what I’ve seen last time I heard about graal python is that it is seldom faster than the pypy approach (AST-based vs tracing JIT), even though in case of TruffleRuby and TruffleJS it is insanely fast compared to the maturity of the projects.
Is your mentioned example of stack frame inspection make it map much worse to Java primitives (which happens behind the scenes of the truffle languages)?
How Python was Shaped by leaky Internals(2016):
https://www.youtube.com/watch?v=qCGofLIzX6g
See also this HN post (Attempts to make Python fast):
Then release a new 'fast' module API, and all the performance critical modules will soon move over.
So I stipulate that if the runtime becomes faster, those gains won't be visible to large swathes of code because python libraries do lots of weird things under the hood.
https://markmail.org/message/dp56i26zhpf4fehb#query:+page:1+...
Unfortunately, there is no Python subset people can stick to as such. But you can use e.g. TransCrypt to compile Python to JavaScript; the docs tell you about an efficient subset. It should be possible to build an efficient Python JIT for such a subset (and you sort of have one already through TransCrypt and JS)
a become: b
It is a myth that only Python enjoys such dynamic capabilities, it happens to be a convenient excuse.And the fact that there are languages as dynamic as Python is not as important as how it is implemented through the language; Lua is about as dynamic as Python, but with effects that are much more local in general. IIRC Mike Pall (of LuaJIT fame) said that Lua was almost optimal for JITting, JS is sort-of-ok if you ignore some things, but Python is beyond hope -- and I tend to think he knows what he's talking about, given that his hobby, one-man-show LuaJIT handily beat all well-funded-with-tens-of-employees JS engines for a very long time (maybe still does).
I wonder how good the SmallTalk JITs really are by today's standards, in the presence of e.g. "become:". The fact that's it is there, and supported, doesn't mean it's in common use, or supported efficiently -- just like JavaScript's "with".
Those that focused on a subset (numba, shedskin, rpython) were actually able to deliver significant speedups. Even PyPy dropped binary compatibility.
The odd one out is Psyco, the precursor to PyPy. Perfect compatibility with non trivial speedup - but was considered a dead end by its authors, and that’s why they started PyPy
Where have you seen it used as an example in that way?
As for become: usefulness, Gilad Bracha explains it better than ever will, https://gbracha.blogspot.com/2009/07/miracle-of-become.html
Python has all the issues that “become” has, with hundreds of “assumptions might have changed” points along common execution paths.
Liajit, for example, hoists everything it can outside of loops rather quickly, because it knows the cases “become” or Python equivalent can happen, and they are rare and uncommon in idiomatic Lua code.
The second is the inspect module that builds on that, allowing you to get the stack frames, inspect function signatures etc.
The third is trackbacks, which need the stack and themselves are introspectable.
The fourth is metaclasses (making dynamic classes at runtime).
These are heavily used in Python, and are optimisation barriers. For example PyPy (Python with a JIT) disables optimisations when “inspect” is imported or used anywhere in the call stack.
(that said, I guess the fourth one (metaclasses) isn't a clear yes/no, since OO is very different in js)
metaclasses isn't really a major optimization hazard, it effectively boils down to hijacking the "class" syntax to instead run some custom code. It's used by things like dataclasses and the Django ORM to use class syntax to make a little DSL.
None of those are insurmountable, they merely make writing a JIT harder if you want to support them: it’s hard to inline a function call if the inclining can have a visible effect.
All of them just as dynamic, if not more.
I’d say the lack of control flow structures and message passing would make it far, far easier to JIT.
If they were share nothing, we probably wouldn't have shipped them.
Source: I'm Node.js core and one of the people who worked on them