| ▲ | pansa2 2 days ago |
| In a similar vein, see this page about the performance of the interpreter for the dynamic language Wren: https://wren.io/performance.html Unlike the Zef article, which describes implementation techniques, the Wren page also shows ways in which language design can contribute to performance. In particular, Wren gives up dynamic object shapes, which enables copy-down inheritance and substantially simplifies (and hence accelerates) method lookup. Personally I think that’s a good trade-off - how often have you really needed to add a method to a class after construction? |
|
| ▲ | versteegen 2 days ago | parent | next [-] |
| Yes, language design is a hugely important determinant of interpreter or JIT speed. There are many highly optimised VMs for dynamic languages but LuaJIT is king because Lua is such a small and suitable language, and although it does have a couple difficult to optimise features, they are few enough that you can expend the effort. It's nothing like Python. It's not much of an exaggeration to say Python is designed to minimise the possibility of a fast JIT, with compounding layers of dynamism. After years of work, the CPython 3.15 JIT finally managed ~5% faster than the stock interpreter on x86_64. |
| |
| ▲ | pjmlp 2 days ago | parent | next [-] | | CPython current state is more a reflection of resources spent, than what is possible. See experience with Smalltalk and Self, where everything is dynamic dispatch, everything is an object, in a live image that can be monkey patched at any given second. PyPy and GraalPy, and the oldie IronPython, are much better experiences than where CPython currently stands on. | | |
| ▲ | dec0dedab0de 2 days ago | parent [-] | | The problem is that AI has been dominating the conversation for so many years, and they'll get more improvements from removing the GIL than they would from adopting the PyPy JIT. The JIT would help everyone else more than removing the GIL, I wish PyPy became the reference implementation during 2.7 | | |
| ▲ | pjmlp 2 days ago | parent [-] | | Actually because AI has been driving the conversation that CPython JIT efforts are finally happening and being upstreamed. It is also because of AI, that Intel, AMD and NVidia are now getting serious about Python GPU JITs, that allow writing kernels in a Python subset. To the point that I bet Mojo will be too late to matter. |
|
| |
| ▲ | dontlaugh 2 days ago | parent | prev | next [-] | | Python is worse, but not by all that much. After all, PyPy has been several times faster for many years. | |
| ▲ | vlovich123 a day ago | parent | prev [-] | | That is an incorrect analysis. CPython is difficult to JIT because of the lack of thought to the native bindings / extensions, not because of the language itself (as others point out PyPy was way faster long ago) | | |
| ▲ | versteegen a day ago | parent [-] | | You're correct. I neglected that; extension API compatibility is a big (the most important?) difference between PyPy and CPython's JIT. Amongst language features that affect optimisation potential, an extension API can be the worst. Edit: I think what you're alluding to is that tracing JITs can overcome a lot of dynamic language features which make things hopeless for method JITs. Where LuaJIT really shines vs PyPy is outside of JITed loops. (Also memory and compile overheads). I realise this is a bit of a motte and bailey. |
|
|
|
| ▲ | psychoslave 2 days ago | parent | prev | next [-] |
| That’s basically what is done all the time in languages where monkey patching is accepted as idiomatic, notably Ruby. Ruby is not known for its speed-first mindset though. On the other side, having a type holding a closed set of applicable functions is somehow questioning. There are languages out there that allows to define arbitrary functions and then use them as a methods with dot notation on any variable matching the type of the first argument, including Nim (with macros), Scala (with implicit classes and type classes), Kotlin (with extension functions) and Rust (with traits). |
| |
| ▲ | pjmlp 2 days ago | parent | next [-] | | It is getting better, now that they finally got the Smalltalk lessons from 1984. "Efficient implementation of the smalltalk-80 system" https://dl.acm.org/doi/10.1145/800017.800542 | |
| ▲ | igouy 2 days ago | parent | prev | next [-] | | > Ruby is not known for its speed-first mindset though. https://benchmarksgame-team.pages.debian.net/benchmarksgame/... | |
| ▲ | IshKebab 2 days ago | parent | prev [-] | | > Ruby is not known for its speed-first mindset though. Or its maintainability, and this is one of the big reasons why. Methods and variables are dynamically generated at runtime which makes it impossible to even grep for them. If you have a large Ruby codebase (say Gitlab or Asciidoctor), it can be almost impossible to trace through code unless you are familiar with the entire codebase. Their "answer" is that you run the code and use the debugger, but that's clearly ridiculous. So I would say dynamically defined classes is not only bad for performance; it's just bad in general. | | |
| ▲ | psychoslave 2 days ago | parent [-] | | That's yet an other topic, as monkey patching can definitely be explicit in ruby. The dynamically generated things at runtime are generally through the catch all method missing facility that can be overwritten. This can also be done in, say, PHP. It just that the community is less fond of it. Not sure about what most popular ahead of time oriented languages expose as facility in this area, obviously one can always even decide to generate automodifying executable. There is nothing special about ruby when it comes to go into forbidden realms, except maybe it doesn't come to much in your way when you try to express something, even if that is not the most maintenance friendly path. |
|
|
|
| ▲ | naasking 2 days ago | parent | prev [-] |
| > In particular, Wren gives up dynamic object shapes, which enables copy-down inheritance and substantially simplifies (and hence accelerates) method lookup. A general rule of thumb is that if you can assign an expression a static type, then you can compile it fairly efficiently. Complex dynamic languages obviously actively fight this in numerous ways, and so end up being difficult to optimize. Seems obvious in retrospect. |