|
| Joker_vD wrote:
| Hey! That's _my_ name! :) Incidentally, I also have a small
| language also implemented in Go although it 's actually called
| "".
|
| So it's a Clojure REPL _and_ linter /formatter? Why have REPL at
| all then?
| stcredzero wrote:
| _Why have REPL at all then?_
|
| To many, interactive development and debugging is the main
| point of the Clojure REPL. (Also true for many dynamic
| languages.) I take it you don't code and debug using such
| techniques. Some feel they are a _revelation_.
| Zababa wrote:
| This would go really well with https://cyclone.thelanguage.org/.
| eggy wrote:
| I realize the project is no longer being developed by the
| original group, but is there a recent fork by others or version
| of cyclone for 64-bit computers?
|
| I've given up on Rust for me personally, but I think it is a
| great PL and effort. I am still playing with Zig, but I would
| love to just leverage my C background, and see if Cyclone eases
| me away from always coding in C.
| pjmlp wrote:
| If you had issues with Rust, with Cyclone it would be even
| more complex, given the way its type system works, in fact
| Rust is must more ergonomic from what I can gather from the
| surviving Cyclone papers.
| bruce343434 wrote:
| What made you give up on rust?
| truth_ wrote:
| For me, it was "no need". I liked everything I saw. I just
| had no need to write Rust.
| emacsen wrote:
| The Eclipse Public License is a showstopper for me. :(
| vnorilo wrote:
| It's quite common in Clojure circles. Care to elaborate? Not
| copyleft?
| didibus wrote:
| Some clarification for those interested:
|
| Joker is not a dialect of Clojure hosted on the Go runtime. Joker
| is a dialect of Clojure using its own interpreted runtime, that
| happens to be implemented in Go.
|
| That means you cannot use Joker to build statically linked Go
| binaries and you cannot interop with Go from your own code.
|
| And if you're interested in the idea of having an interpreted
| implementation of Clojure, for scripting use cases and fast
| startup, I would recommend you look into Babashka instead of
| Joker: https://babashka.org/
|
| Joker was the best interpreted Clojure prior to Babashka, and
| nowadays, I would recommend Babashka over Joker all the time.
|
| The reason Babashka is better than Joker for this is that it is
| implemented in Java, so it can directly reuse the existing
| Clojure implementation and libraries as-is as part of its
| interpreter. That allowed it to quickly surpass Joker in the
| amount of Clojure features it support and libraries it exposes,
| and continue to quickly keep up with Clojure. I'd also say the
| main developer behind Babashka is more active.
|
| Even though Babashka is implemented in Java, it is still a single
| statically linked binary runtime that starts extremely fast and
| has a small memory footprint.
|
| Kudos to Joker though for pioneering the idea and leading to
| Babashka.
|
| Edit: And if you were excited because you thought this would let
| you write compiled statically linked binaries in Clojure, well
| for that you want to look at GraalVM native compilation which
| lets you compile real Clojure programs as low memory, fast
| startup, statically compiled single binaries:
| https://github.com/lread/clj-graal-docs
| didibus wrote:
| A small correction, Babashka is implemented in Clojure, not
| Java, but, as such, it can also make use of Java libraries as
| part of its implementation. So Babashka can bundle both Clojure
| or Java libraries inside itself.
| cutler wrote:
| For me the most interesting compilation target for Clojure is
| Dart. Writing Flutter apps in Clojure would be the dog's
| spherical objects. David Nolen thinks likewise and has commented
| on it in a recent defn podcast. Christophe Grand and Baptiste
| Dupuch are the brains behind it:
| https://twitter.com/cgrand/status/1350063059864346624?lang=e...
| didibus wrote:
| Has Flutter really become that popular and awesome? I feel I'm
| still seeing a lot more of React Native or Electron and other
| JS based front-ends in the wild, for which ClojureScript is
| best suited. I'm not sure I'm convinced Flutter will be able to
| break through those even with Google behind it.
| nkozyra wrote:
| I feel like it's picking up steam.
|
| I've written a few things in it and found fewer footguns than
| React Native.
|
| Granted, it comes with its own set of idiosyncracies,
| breaking version changes, half baked community libraries and
| developer ecosystem, but that's par for the course.
| masijo wrote:
| This project looks awesome, though I'm a bit sad that
| "performance" is a non-goal as stated in the README. Clojure
| being able to compile to a single shippable binary is just what I
| need in my life. Kudos to the author.
| skybrian wrote:
| It's difficult to write a fast interpreter in Go. It doesn't
| optimize interpreter inner loops particularly well, you can't
| do the data structure tricks you can do in C, and there is no
| JIT compiler available like in Java.
|
| The best way forward might be an option to compile some Joker
| code by generating Go code for it.
|
| (This is based on writing an interpreter a few years ago.
| Perhaps Go's compiler has improved?)
| AtlasBarfed wrote:
| What C tricks are used? I'd be fascinated to know some
| details.
| spijdar wrote:
| Caveat: I've barely used Go personally.
|
| Just speculating on what GP specifically meant, but Go
| lacks the ability to pack structs, and probably lacks the
| equivalent of tricks like computed gotos [0] to increase
| bytecode interpreter speeds. In general, Go seems to
| (intentionally) lack a lot of low-level control of code
| generation, preferring a "there's one way to do things, and
| it either works, or it's a bug we'll fix" approach.
|
| Which is probably for the best in "most" software, but
| interpreters typically use weird hacks to squeeze more
| performance out of the rock. Wren is a good example [1] of
| some of these optimizations, and has splendid
| comments/documentation.
|
| [0] https://eli.thegreenplace.net/2012/07/12/computed-goto-
| for-e...
|
| [1] https://github.com/wren-
| lang/wren/blob/main/src/vm/wren_vm.c
| skybrian wrote:
| For one thing you have C unions. You can store different
| types in the same place and use information stored
| elsewhere to know what the bits really mean. It's horribly
| unsafe compared to a Go interface or the tagged unions in
| other languages, but uses less space.
|
| Also, there is the NaN boxing trick [1], which allows you
| to store a value that is essentially a tagged union that is
| either a double, a pointer, or an integer, in the same
| space as a double. To get these in a safe language, they
| essentially have to be built in already.
|
| Go's interface type is very high overhead compared to the
| union types used in other languages because it uses an
| entire pointer as a tag. Though, it only matters in special
| cases like interpreters. Most performance-intensive code
| isn't nearly so dynamic.
|
| [1] https://sean.cm/a/nan-boxing
| geeio wrote:
| I think you could do the pointerless version (the one
| using an int32 index) of this in go via unsafe casting.
|
| I'll try it out later
| bpicolo wrote:
| Can do that with Graal these days:
| https://github.com/BrunoBonacci/graalvm-clojure/blob/master/...
| uDontKnowMe wrote:
| I explored this briefly but it ended up taking about 25
| seconds to compile hello-world in Clojure. That struck me as
| causing a lot of pain to develop for.
|
| That, combined with how you'd lose access to a lot of the
| java library ecosystem, makes it less appealing to me to
| develop on.
| dig1 wrote:
| True, but you don't develop that way using graal. You
| develop java apps the usual way (eclipse, emacs/vim/maven,
| whatever) and create a fat jar (or uberjar). When you make
| sure the application is working, compile it with graal,
| creating a static binary.
|
| Clojure cycle is even faster because you keep REPL open and
| evaluate code directly while application is running. After
| that, you build uberjar, then compile it with graal.
| uDontKnowMe wrote:
| Would there not be a risk that you may get something
| working nicely in openjdk and then you go to do a native
| compilation, and it turns out that it doesn't work due to
| some new method call which uses reflection or something?
| didibus wrote:
| Reflection is supported by GraalVM native compilation,
| but you need to declare what classes you need reflection
| support for at compilation.
|
| What you must understand though, is that you're asking
| for something contradictory. You cannot get runtime eval
| and code linking and also deliver a statically linked
| compiled machine code binary.
|
| That's why statically linked to machine code binary
| languages don't offer dynamic code generation, linking
| and reflection that can't be declared or performed at
| compile time.
|
| This is true for GraalVM. It means when you develop
| Clojure for GraalVM native compilation you can't leverage
| such dynamic behavior as well.
|
| Though you can embed the SCI Clojure interpreter inside
| your application and do dynamic code evaluation with it
| at runtime.
| [deleted]
| jgrodziski wrote:
| GraalVM issue an error if it can't resolve the proper
| method call or if another Thread is involved in the
| computation so I find it pretty safe to use. Of course,
| GraalVM doesn't exempt you from doing some tests.
| zerr wrote:
| What would be the advantage over other Lisps if you won't be
| able to leverage JVM ecosystem?
| didibus wrote:
| Depending who you ask, Clojure provides some benefits over
| other Lisps unrelated to its ability to leverage the JVM.
|
| Some of those are: - Default efficient
| immutable collections - Good support for safe
| concurrency and multi-core programming - Extended
| homoiconicity to include maps, vectors and sets as well as
| lists - Convenient short lambda syntax -
| Extensible data representation - Distinguishes
| between nil and empty list - Distinguishes between
| keywords and symbols - Real boolean types -
| Function arity overloading - Well thought out
| abstractions and set of standard functions: collections are
| abstractions, lazy sequences, transducers, relational set
| manipulation, etc. - Only two kinds of equality: by
| value or by reference, with the former being the default
| - Is a lisp-1 like Scheme, but also with more batteries
| included like Common Lisp - Slightly different visual
| appearance in its syntax, due to support for literal maps and
| vectors as well as lists, which can make things easier to
| visually parse.
| leephillips wrote:
| Some people like Clojure's data structures, which add a
| couple of things to lists. Also, there's ClojureScript, which
| is huge. And, ideas such as software transactional memory.
| chitowneats wrote:
| Have you tried Babashka? https://github.com/babashka/babashka
| dimitar wrote:
| babashka also has a performance non-goal
| chitowneats wrote:
| Ah. You are correct.
| Borkdude wrote:
| The performance non-goal is there to lower expectations
| compared to compiled Clojure. Babashka's author (me) does
| try to make it as fast as possible within the constraints
| it's implemented in.
| didibus wrote:
| That's true, but in my poor man tests, Babashka was in the
| ballpark of Python for me.
| chitowneats wrote:
| I was surprised when I realized I had overlooked the
| performance non-goal considering how fast it has been in
| my limited experience.
| didibus wrote:
| Ya, it even supports multi-core programming, so I bet for
| some use case it can outperform Python by parallelizing.
| didibus wrote:
| You can just use GraalVM for that. Also, Joker does not let you
| do what you want, it is not Clojure hosted on the Go runtime,
| it is a Clojure interpreter runtime implemented in Go, so with
| Joker you always need the joker binary.
|
| If you want to produce native shippable statically linked
| binaries with Clojure look at GraalVM native compilation:
|
| https://github.com/lread/clj-graal-docs
| vnorilo wrote:
| I have long had the ambition to be the N:th guy to try Clojure
| on C++. For similar reasons. I have a pretty good idea how to
| do it, already got HAMT and some macroexpanded code to work.
| But then you remember how even ClojureCLR struggled at times,
| and that you'd be lightyears behind that, not to speak of
| CLJ/CLJS, and alone. Maybe one day? :)
| geokon wrote:
| I think recreating Clojure point by point is not optimal.
| There is some middle ground between full on Clojure and the
| straightjacket of the STL datastructures.
|
| - Clojure is kinda difficult to reason about performance
| wise. The lazyness.. some weird corner cases (like how
| `(first ..)` is slower than `(nth .. 0)`
|
| - The STL is very strict on the "zero cost abstraction"
| front.
|
| Maybe something like Immer but with some syntactic sugar to
| make it more light weight like Clojure?
|
| With hooking into GDB you could probably make a REPL as
| well.. GDB has live code reload, introspection - you even get
| state of crash and sane stack traces :)
| dig1 wrote:
| > some weird corner cases (like how `(first ..)` is slower
| than `(nth .. 0)`
|
| I would not consider this a corner case; it is stated in
| (first) docstring. (first) will create seq [1] object, then
| it will fetch the first element. (nth), on other hand, will
| not create seq object.
|
| > The STL is very strict on the "zero cost abstraction"
| front.
|
| Many edge cases which are lost in myriad of classes. For
| example, vector will allocate more memory than there are
| actually elements in it, and you never know when it will
| start resizing it (this is implementation detail). I would
| not call this as "zero cost abstraction".
|
| [1] https://clojuredocs.org/clojure.core/seq
| geokon wrote:
| I mean, I didn't say it's undocumented behavior :) but
| when the default performance of a basic function like
| `first` is not O(1) then that strongly suggests that
| performance is secondary to composability/flexibility
|
| (I'm actually not clear why it doesn't alias to `(nth ..
| 0)` .. I'm sure there is a good reason)
|
| In Clojure you don't really reason about vector's run
| time behavior at all like in C++. You can't even ensure
| cache locality b/c different items can have any size. You
| can try to be clever and fall back to Java arrays, but
| the documentation says "It is recommended that you limit
| use of arrays to interop with Java libraries that require
| them as arguments or use them as return values." and the
| language doesn't provide the syntactic sugar for their
| easy use with the other data structures. So it kinda
| looks like the language is actively trying to discourage
| you from using an efficient data structure.
|
| My previous post was trying to say that maybe you could
| elevate arrays to be more first class, make `first` and
| company O(1), maybe lose some flexibility/composability
| in the process but find some performant middle ground
| between Clojure and C++. I have no idea if this is
| actually achievable.
|
| btw, STL vector resizing is a total non issue ... Most of
| the time you'd just allocate sufficient space beforehand
| (then it's truly zero cost). If you need to do something
| dynamic and care about when it resizes then you can just
| resize manually as you go (that's also zero cost - b/c
| this resizing is unavoidable and part of your algorithm).
| The default auto-resizing behavior just handles the
| resizing for you in a sane O(1) way
| vnorilo wrote:
| I think zero cost in this context means compile-time
| polymorphism (templates) instead of runtime polymorphism
| (virtual functions).
| vnorilo wrote:
| You see, I'd like to write more of my software in Clojure
| (or any functionally inclined Lisp). If there was a really
| good interop story with a non-gc:d native lang I could do
| more of it.
|
| Clojure is a hosted language, so hosting it on C++ (or Rust
| etc.) would be sweet for me personally. Also, I like
| compiler projects.
| didibus wrote:
| Interop with C is pretty decent, but if you want to make
| a C++ hosted Clojure dialect I'm all for it! The more the
| merrier!
| geokon wrote:
| It does already sort of exist: https://ferret-lang.org/
| geokon wrote:
| I've never had to use it myself, but what part of the
| JNI/JNA is problematic?
|
| One thing I'd sorta fantasized about is (in a very hand
| wavey way) using Clojure + ClojureCL to run OpenCL
| kernels. In theory if you were to bundled your JAR with
| POCL.. you could selectively run your tight-loops/kernels
| on the CPU or GPU. So it'd be effectively like launching
| little C snippets. Furthermore, from what I remember,
| kernels are compiled and executed at run time - so it'd
| really fit with the whole REPL workflow and they would
| effectively simply be inline strings of C code that get
| executed
|
| I think the main catch for the moment is that ClojureCL
| uses a MKL matrices to talk to the OpenCL driver (driver?
| dispatcher? I might be mixing up my terms) - but that
| could be modified to a JVM container
|
| Probably my own bias - but the only time I've really been
| let down by Clojure and missed native was when I need to
| optimize a tight loop. Once you optimized Clojure past a
| certain point (to eliminate reflection, boxing issues,
| destructuring etc.) it starts to get ugly.
| yawaramin wrote:
| Check out https://github.com/carp-lang/Carp
|
| From the readme:
|
| > The key features of Carp are the following:
|
| > - Automatic and deterministic memory management (no
| garbage collector or VM)
|
| > - Inferred static types for great speed and reliability
|
| > - Ownership tracking enables a functional programming
| style while still using mutation of cache-friendly data
| structures under the hood
|
| > - No hidden performance penalties - allocation and
| copying are explicit
|
| > - Straightforward integration with existing C code
|
| > - Lisp macros, compile time scripting and a helpful
| REPL
| aidenn0 wrote:
| Consider perhaps https://github.com/clasp-
| developers/clasp which is a common-lisp specifically
| designed to interop with C++.
| jb1991 wrote:
| It would seem to me the most significant challenge would be
| having functional data structures in C++, that would be a
| non-trivial effort I would think. Even if you were to use
| other libraries that experiment with this. Without those, the
| language just doesn't make any sense.
| toymachine1974 wrote:
| My Park language does this
| https://github.com/toymachine/park-lang Currently the
| syntax is mostly JS but the semantics is all clojure. I
| recreated the map and vector datatypes in c++ by adapting
| clojures Java code. it needs a GC though which is another
| big part of the implemention of Park
| vnorilo wrote:
| Yeah, that was the problem with most attempts I saw,
| unordered_map won't work. I did write a persistent hash map
| and vector [1], but ended up mostly using them in C++
| projects. I wouldn't advise anyone else to use them at this
| level of testing/maturity though. Writing them was super
| interesting.
|
| 1: https://hg.sr.ht/~vnorilo/pcoll/browse (not production
| quality)
| bertmuthalaly wrote:
| Immer [0][1] seems like a really serious attempt at
| bringing high-quality persistent data structures to C++.
|
| [0]: https://www.youtube.com/watch?v=sPhpelUfu8Q
|
| [1]: https://sinusoid.es/immer/
___________________________________________________________________
(page generated 2021-09-03 23:02 UTC) |