4 ms·
Can someone wiser than myself explain why there seems to be not a lot of support for languages targeting multiple runtimes? I see Clojure has a CLR version that
by BWStearns 10y ago
Can someone wiser than myself explain why there seems to be not a lot of support for languages targeting multiple runtimes? I see Clojure has a CLR version that seems to have died on the vine (maybe it didn't and I just haven't investigated enough) but I can't recall seeing more examples. Given the explanation offered int the article, it would seem especially worthwhile for a language's portability to target the LLVM since it's fairly generic. The most compelling reason I can see to not target multiple runtimes is to avoid ecosystem fracture, but it's really not that much overhead to understand a runtime as just another facet of the environment that has to be accounted for.
- xaduha 10y agoI asked why there wasn't an implementation of Rakudo for CLR* some time ago, one of the reasons given was that JVM has InvokeDynamic aka indy, while CLR does not. It also has to be said that even their JVM implementation fell behind MoarVM now, so the second and most important reason would be lack of time and manpower. *Yes, I know about Niecza, not the same.
- jerf 10y agoConceptually, it's easy. In practice, it'll drown you in a thousand details, and a lot of those details turn out to be foundational. For example, a slight difference in atomicity guarantees that would be no problem at all to build around from scratch can end up becoming a nightmare to try to port an existing set of runtime expectations on to. Such things tend to subtly but firmly work their way all the way up the stack. JVM's InvokeDynamic is a real-world example of how differences in performance guarantees can also cause surprisingly large differences. There's obviously nothing impossible about it, since it has been done, it's just that it takes a lot more resources than you might have initially thought to do it well. And I think from an economic perspective, the vast bulk of open source projects and similarly-staffed projects are way better off putting that "lot more resources" into becoming better on their native platform than being not-quite-as-good on a lot more platforms. (I had a lengthy defensive discussion of the differences between commercial and open source resource allocation, which grew to be more than half this post, so let's just pretend I proved that I understand the difference, and I still think this paragraph is true even given those differences.)
- jsnell 10y agoA lot of languages have different implementations targeting different runtimes. For example both Python and Ruby had JVM versions, CLR versions, multiple separate runtimes specifically designed for the language, etc. What's more rare is a single implementation of a language targeting multiple runtimes. There's Haxe, which has like 10 different targets (and those different targets seem to be the main selling point). Unity uses C# as it's programming language, but also has HTML5 + Javascript export. The general downside with either of these is that the runtime should actually inform the language design, and vice versa. When you target multiple runtimes, you either have to design the language conservatively such that it only takes advantage of the smalles common subset of features in the runtimes. Or you have to accept that some operations the language nominally supports will be uncomfortable on some of the target runtimes. As a classic example of the last one, a lot of scripting languages start off with memory management based on reference counting (possibly with some kind of facility for breaking loops automatically). This means that it's very natural for the language to provide deterministic object destruction as soon as the object goes out of scope, and for the library ecosystem to take advantage of that. (Like closing file descriptors when the matching file object goes out of scope). Move to a runtime with a garbage collector, and the finalization becomes non-deterministic. And you either accept the loss of this very convenient feature, you completely cripple the GC based implementation by adding this very expensive extra constraint on top of it, or you allow the two implementations to diverge.
- jesserayadkins2 10y agoIt's harder to develop features, because you have to get a feature to work in multiple runtimes instead of just one. So the language might be developed at a slower pace. You're also likely to run into bugs where something works for CLR but fails on the JVM (or vice versa). So more energy has to be spent fixing mistakes versus features. Then there's fracture. Imagine reading that language X is at version 3 for one runtime, but 2.5 for another runtime because "the guy who did the support of runtime B lost interest, and nobody has taken it up again".
- daxfohl 10y agoActually there's a lot of support for that. Just not official support. But seems like if you need X to run on Y then somebody somewhere has a hack to make it happen. Some obviously more substantial than others. That, and almost everything has support compiling to its original target and JavaScript these days. Nonetheless I agree with the sentiment, perhaps because I'd love to see Scala on .NET and F# on JVM in particular. I don't know why, of all the things that have happened, neither of these ever did. Maybe too much overlap to be worth it. I'd also have to imagine that strongly-typed languages are a bit more difficult since you have to match the underlying runtime. Curious if there were any languages and targets in particular you had in mind. FWIW ClojureCLR is still going strong; seems to track the JVM version within a couple weeks: https://github.com/clojure/clojure-clr/commits/master https://github.com/clojure/clojure-clr/commits/master It does have some warts, but I've played with it and it works fine.
- daxfohl 10y agoAlso FWIW the ClojureCLR blog has lots of interesting tidbits about some of the intricacies that directly address your question: http://clojureclr.blogspot.com/ http://clojureclr.blogspot.com/
- panic 10y agoIt's hard to separate how your language behaves from how the underlying runtime behaves. Unless you're incredibly careful, programs will end up depending on runtime behaviors which you'll have to either emulate or break when you target a new runtime.