3 ms·
Maybe it's a bit naiive, but I'd imagine having a small-core interpreted Clojure and different host implementation would incrementally overload functionality an
by geokon 5y ago
Maybe it's a bit naiive, but I'd imagine having a small-core interpreted Clojure and different host implementation would incrementally overload functionality and reimplement using the host's features.
But the design (granted I'm judging from the docs and API - not digging through the source) seems like things weren't designed for multiple hosts in mind.
- didibus 5y agoI'm not really sure what you're imagining, but basically you need to implement the few special forms, the general rules of parsing and evaluation, and then you need to implement all the core types, and finally you need to bring in all the core data-structures and standard library functions. A lot of the standard library functions are already written in Clojure itself, and don't use interop, but a lot of them, as well as types, and core data-structures are implemented in Java, and core functions that uses them tend to use interop. So that stuff needs to be ported as well. And that's about it. Now, you might think it would be great if all the types, data structures and therefore all core standard functions could also all be implemented in Clojure on top of the special forms. But I actually think it's specifically because that's not the case that Clojure gets ported to so many hosts. The special thing is that this design makes Clojure hosted, which is very different from simply being implemented over multiple hosts. For example, Clojure always uses the host's native types. So Clojure types are the same as the host it is running on. That's why then interop becomes a first class thing, and why Clojure always feels very symbiotic and compatible with the host. And because it uses the host's native types, it also can't implement it's core data-structures and some of its core standard functions without using interop. Which is why those need to be re-implemented to be host specific normally. I think there's a few extra things you could lift to be in pure Clojure, and I think Clojurescript has lifted more of them to be so, but still the types are same.as the host. If this wasn't part of the design, the appeal of porting it would also be lost. It would just be like a bunch of exactly same Clojire language just with various quality of implement and performance characteristics, and people would probably just pick the ine that has the best performance and most stable. But instead, Clojure becomes an alternate language for a multitude of hosts. Suddenly it means you can use Flutter as easily as with Dart, but have Clojure as your language to do so. It means you can use NodeJS as easy as with JavaScript, but using Clojure as your language, etc. It's also why it's a bit wrong to say Clojure gets ported to other hosts, in reality it doesn't, what happens is someone creates a new dialect of Clojure that is well adapted to a new host. And that's also why it's so useful.
- geokon 5y agoThanks for the insight. It seems to match my understanding Correct me if I'm wrong, but you don't typically interact with the host directly when using core data structures. If you were to rewrite those for instance in terms of lists (like you'd probably do in a Scheme) I don't think that that change would be visible to the user from pure Clojure code. And similarly for the standard library. Then host to host you could re-implement them with whatever data structures you want. This would in principle make adding and then maintaining a new host significantly easier As for the types, are you speaking about how numbers are Longs/Doubles, and arrays are Java Arrays? And that matches what Java uses - so things work smoother (except when you get a BigInt..)? I get what you say about changing that host to host improves the coupling - but you loose the ability to share libraries which is a shame - hence why you say `dialect`. I guess if you write a Clojurefoo for a new host that normally uses Ints and Floats then it's a design choice if you want it to match the Host or to match Java. If Java is close enough I can see it making sense to create a compatibility layer and have users deal with whatever friction ensues.. From my own limited experience, host interop is super important and a huge part of why I used Clojure. Calling out to Java libraries saves me zillions of hours of coding. But the actual interop code is also not a huge fraction of the code I write. If it were a bit more complex on a different host b/c I needed to fiddle with some typeas I don't think this would be a deal breaker. On the other hand, not having access to all of Clojure's libraries would be a disaster I wish I knew this stuff a bit more thoroughly to discuss it more concretely :)
- didibus 5y ago> If you were to rewrite those for instance in terms of lists (like you'd probably do in a Scheme) I don't think that that change would be visible to the user from pure Clojure code You could probably, but persistent thread-safe data-structures are a bit non-trivial to implement. And I'm not even sure you can build them atop a simple list, and even if you could, definitely they would neither be performant nor memory efficient. I think it would be a cool project to have a kind of Clojure implemented over a more minimal core, like an implementation of the data-structures over a simple array or something, but it also wouldn't really be practical in usage I believe. > This would in principle make adding and then maintaining a new host significantly easier It would, but I wonder if it would just encourage toy implementations. In some ways, now it forces you to re-implement from the get go all the pieces that matter for performance and efficiency. > As for the types, are you speaking about how numbers are Longs/Doubles, and arrays are Java Arrays? And that matches what Java uses - so things work smoother Yup, numbers, strings, regexes, threads, namespaces, they're all host specific. Namespaces are particularly important, you want a Clojure namespace to be a module of the host. Having the same types makes interior a lot smoother, and also it makes implementing Clojure to a new host a lot easier as well, because building custom primitive types over an existing runtime is non-trivial. > but you loose the ability to share libraries which is a shame That's why you've got reader conditionals, so you can still technically implement portable libs, though it does force you to re-implement the parts that differ as the library author. But this is a tradeoff, either reusing the host libraries is trivial and easy, or reusing Clojure's would be. I'd say 90% of the appeal of Clojure on a new host is leveraging the new host's libraries, so I think Clojure makes the right trade off here. And the IO pieces you'd always have to reimplement as well. And because of Clojure generally using interop for that, the person who ports Clojure also has less to re-implement, since users can just use interop. > On the other hand, not having access to all of Clojure's libraries would be a disaster How many of those libs are interop free though? Because otherwise you'd always lose access to them anyways.