If you like Janet, you'd probably like Clojure a lot as well.
If you want to take on web apps, backend services, machine learning and data-science, desktop GUI applications, mobile applications and/or distributed computing use cases, it could be a good choice where Janet lacks the chops, but Clojure offer a very similar feel while enabling those use cases.
For scripting, CLI, and embedding with a C interface, Janet rocks.
As someone who learned Clojure before I picked up any sort of Java knowledge, the "big stacktraces from hell/JVM" problem seems kind of over-pushed, it's not as bad as people make it out to be.
Yes, the stack traces are long, but if you actually follow them, they'll show you what your problem is, not sure what else you can wish from a stack trace. I'd rather have too long stack traces with all the details than just a error message without anything to go by.
And since you most likely get your stack trace from when evaluating just a snippet of code with some exception, the stack traces tend to not be as big as for other programming projects (like Java, JavaScript, Golang and else) either where you need to run the entire program in order to reproduce some issue.
I guess what bothers me is that if I'm going out of my way to try and deal with Clojure, I don't want the information with all of the JVM magic (tm) underneath, I just want to know why my Clojure is wrong. Come to think of it, I don't think I've ever really used a hosted language of any kind before, for serious work, so I guess I've just never had to be aware of this.
On a laptop with only a single screen of real estate, even as orderly as the trace might be, it's a distinct hassle to scroll and walk it all the way back to a method argument problem somewhere, and equally frustrating to think about because I'm using a functional language to try and avoid thinking about classes and methods and whatnot.
Maybe I'm just expecting Clojure to taste like Scheme, and I'm probably wrong.
Yeah I think that’s your expectations. Clojure doesn’t treat the JVM as an implementation detail, but as a very important part that you’ll want to use and interact with directly. It wouldn’t make any sense for clojure to not show you the JVM details, because for all it knows, those are the parts that you really care about and you just use clojure to glue it all together
There's definitely a higher barrier to entry to Clojure.
There's more layers to understand, because it is hosted over existing runtimes, instead of being self-contained like Janet.
For that I would recommend starting out with Babashka https://babashka.org/ it'll take some of that edge off, because it is a self-contained interpreted Clojure. It's a good way to start where you can get straight to writing code and learning the language itself, and not having to learn about how it is all scaffolded and bootstrapped over a JVM, CLR or JS runtime.
Clojure also forces you almost exclusively into the functional programming style. Doing imperative things in it is ackward. So if you tend to rely mostly on Janet's imperative constructs, this might be a bit of a shock.
Don't really have a trick for this one, just got to learn and practice FP to get familiar with it. Also, it depends a bit what you're doing, a lot of coding questions and small exercises tend to be simpler to implement imperatively, because they're either designed to be so, or are very focused on raw performance. FP will show its worth when writing larger programs in my opinion, where long term productivity, extendability, modularity, maintainability, and robustness/correctness become your biggest concerns. So in the small, it can often seem like a more convoluted way to do things, though for certain problems it also can land itself really well.
One thing I find funny/curious: Does clojure not have a destructuring match in it's standard library? Most people that I've seen move from Clojure to Janet seem to avoid using that.
For me, the two types of programs I tend to use to exercise an language early on are small CLI programs that help me free up mental space, and web apps. Clojure, outside of babashka seems ill-suited to the first (and I've not figured out how to get the CLR clojure up and running).
And when I last tried to do web apps with Clojure, it seemed like everything relied on a lot of self-assmebly, and didn't map cleanly to ways I knew how to web apps at the time from Go, C#,or Erlang. I dunno what the situation is there these days.
For Janet, I did lean into the more imperative constructs early on.
Clojure doesn't natively support destructuring inside def and var though, the latter doesn't really exist in Clojure since there's not real local mutable variable, only local bindings. It supports it in let, function parameters, loop, and everything else that derives from those.
For fun, I just made a macro to support it in def as well:
> are small CLI programs that help me free up mental space, and web apps. Clojure, outside of babashka seems ill-suited to the first
Ya, Clojure JVM is not ideal for small CLIs, because it has a slow startup. Though you can now compile a Clojure JVM program into a self-contained statically compiled native executable, it requires understanding a fair amount of GraalVM native-image, and Clojure infrastructure and all that to do so, actually Babashka itself is such a program. But that's also where Babashka comes in, because now all your effort learning Clojure also means you can reuse those learning for scripting and babashka driven CLIs, where as before you needed to rely on some other language for those, which meant having to learn something else for those use cases. You can also use ClojureScript to write Node.JS driven CLIs and scripts if you want, though I'd say Babashka is much nicer, unless you cared for some Node.JS library.
And when I last tried to do web apps with Clojure, it seemed like everything relied on a lot of self-assembly, and didn't map cleanly to ways I knew how to web apps at the time from Go, C#,or Erlang. I dunno what the situation is there these day
It hasn't changed, familiarity is Clojure's enemy, that holds for frameworks as well. This is another learning curve.
For Janet, I did lean into the more imperative constructs early on.
When I think of destructuring match, it's not just about destructuring, but also about matching a set of clauses against the matches.
I rely on the imperative parts of Janet less than I used to, but yeah.
I am surprised that no one has tried to build something like Sinatra for Clojure. From what I can see, nothing would keep Clojure from being able to make something like that.
I am surprised that no one has tried to build something like Sinatra for Clojure. From what I can see, nothing would keep Clojure from being able to make something like that.
Sinatra is a framework rather than a library (Sinatra calls your code when requests come in rather than you calling the library code when requests come in [we call you VS you call us]) and so generally doesn't get a lot of mindshare in the Clojure community, where small, composable libraries are preferred.
Normally I see people using Ring (http request/response abstraction) + Compojure (routing) + Ring-compatible HTTP server (something like http-kit) for those purposes, and is what I normally use myself as well. Works well and once you've grokked the architecture of plugging those together, it becomes easy to hunt down issues and switch out parts whenever you want.
Comments
If you like Janet, you'd probably like Clojure a lot as well.
If you want to take on web apps, backend services, machine learning and data-science, desktop GUI applications, mobile applications and/or distributed computing use cases, it could be a good choice where Janet lacks the chops, but Clojure offer a very similar feel while enabling those use cases.
For scripting, CLI, and embedding with a C interface, Janet rocks.
I've been trying to get into clojure but getting a big stacktrace of JVM junk whenever I make a mistake is frustrating.
As someone who learned Clojure before I picked up any sort of Java knowledge, the "big stacktraces from hell/JVM" problem seems kind of over-pushed, it's not as bad as people make it out to be.
Yes, the stack traces are long, but if you actually follow them, they'll show you what your problem is, not sure what else you can wish from a stack trace. I'd rather have too long stack traces with all the details than just a error message without anything to go by.
And since you most likely get your stack trace from when evaluating just a snippet of code with some exception, the stack traces tend to not be as big as for other programming projects (like Java, JavaScript, Golang and else) either where you need to run the entire program in order to reproduce some issue.
I guess what bothers me is that if I'm going out of my way to try and deal with Clojure, I don't want the information with all of the JVM magic (tm) underneath, I just want to know why my Clojure is wrong. Come to think of it, I don't think I've ever really used a hosted language of any kind before, for serious work, so I guess I've just never had to be aware of this.
On a laptop with only a single screen of real estate, even as orderly as the trace might be, it's a distinct hassle to scroll and walk it all the way back to a method argument problem somewhere, and equally frustrating to think about because I'm using a functional language to try and avoid thinking about classes and methods and whatnot.
Maybe I'm just expecting Clojure to taste like Scheme, and I'm probably wrong.
Yeah I think that’s your expectations. Clojure doesn’t treat the JVM as an implementation detail, but as a very important part that you’ll want to use and interact with directly. It wouldn’t make any sense for clojure to not show you the JVM details, because for all it knows, those are the parts that you really care about and you just use clojure to glue it all together
Clojure was something I tried once or twice, but couldn't quite get into, at least back when I tried it before.
These days, I might be better able to pick it up, having cut my REPL teeth on Janet.
There's definitely a higher barrier to entry to Clojure.
There's more layers to understand, because it is hosted over existing runtimes, instead of being self-contained like Janet.
For that I would recommend starting out with Babashka https://babashka.org/ it'll take some of that edge off, because it is a self-contained interpreted Clojure. It's a good way to start where you can get straight to writing code and learning the language itself, and not having to learn about how it is all scaffolded and bootstrapped over a JVM, CLR or JS runtime.
Clojure also forces you almost exclusively into the functional programming style. Doing imperative things in it is ackward. So if you tend to rely mostly on Janet's imperative constructs, this might be a bit of a shock.
Don't really have a trick for this one, just got to learn and practice FP to get familiar with it. Also, it depends a bit what you're doing, a lot of coding questions and small exercises tend to be simpler to implement imperatively, because they're either designed to be so, or are very focused on raw performance. FP will show its worth when writing larger programs in my opinion, where long term productivity, extendability, modularity, maintainability, and robustness/correctness become your biggest concerns. So in the small, it can often seem like a more convoluted way to do things, though for certain problems it also can land itself really well.
One thing I find funny/curious: Does clojure not have a destructuring match in it's standard library? Most people that I've seen move from Clojure to Janet seem to avoid using that.
For me, the two types of programs I tend to use to exercise an language early on are small CLI programs that help me free up mental space, and web apps. Clojure, outside of babashka seems ill-suited to the first (and I've not figured out how to get the CLR clojure up and running).
And when I last tried to do web apps with Clojure, it seemed like everything relied on a lot of self-assmebly, and didn't map cleanly to ways I knew how to web apps at the time from Go, C#,or Erlang. I dunno what the situation is there these days.
For Janet, I did lean into the more imperative constructs early on.
Yes it does:
Clojure doesn't natively support destructuring inside def and var though, the latter doesn't really exist in Clojure since there's not real local mutable variable, only local bindings. It supports it in let, function parameters, loop, and everything else that derives from those.For fun, I just made a macro to support it in def as well:
> are small CLI programs that help me free up mental space, and web apps. Clojure, outside of babashka seems ill-suited to the firstYa, Clojure JVM is not ideal for small CLIs, because it has a slow startup. Though you can now compile a Clojure JVM program into a self-contained statically compiled native executable, it requires understanding a fair amount of GraalVM native-image, and Clojure infrastructure and all that to do so, actually Babashka itself is such a program. But that's also where Babashka comes in, because now all your effort learning Clojure also means you can reuse those learning for scripting and babashka driven CLIs, where as before you needed to rely on some other language for those, which meant having to learn something else for those use cases. You can also use ClojureScript to write Node.JS driven CLIs and scripts if you want, though I'd say Babashka is much nicer, unless you cared for some Node.JS library.
It hasn't changed, familiarity is Clojure's enemy, that holds for frameworks as well. This is another learning curve.
Ya, that will be another big learning curve then.
When I think of destructuring match, it's not just about destructuring, but also about matching a set of clauses against the matches.
I rely on the imperative parts of Janet less than I used to, but yeah.
I am surprised that no one has tried to build something like Sinatra for Clojure. From what I can see, nothing would keep Clojure from being able to make something like that.
Sinatra is a framework rather than a library (Sinatra calls your code when requests come in rather than you calling the library code when requests come in [we call you VS you call us]) and so generally doesn't get a lot of mindshare in the Clojure community, where small, composable libraries are preferred.
Normally I see people using Ring (http request/response abstraction) + Compojure (routing) + Ring-compatible HTTP server (something like http-kit) for those purposes, and is what I normally use myself as well. Works well and once you've grokked the architecture of plugging those together, it becomes easy to hunt down issues and switch out parts whenever you want.
I assume you mean something like clojure.core.match https://github.com/clojure/core.match ? It is available, but not used that often.
With the exception of Electron apps, this is a bit of an exaggeration. There are far better choices in that area than Clojure.
That are also going to be close to Janet in look and feel? Please let me know, I'm interested to try.
Racket has a cross-platform GUI library. It’s what drives the DrRacket editor.
Oh nice, I did not know that, I've been wanting to try Racket for a while, maybe trying my hand at a desktop GUI will be it. Thanks.