Okay, so when Clojure came along, it came with a strong underlying philosophy of what the language was supposed to be/do. Among them were design decisions such as, e.g.,:
- VMs, not OSes, are the platforms of the future, so target the JVM
- Object Orientation is overrated, but polymorphism is a good thing
- Multi-core is here to stay, so use immutable data structures to greatly facilitate writing correct concurrent programs
- Leverage the strengths of LISP but give it a modern overhaul (most notably, throw in different parenthesis)
Now, you may or may not subscribe to any of these but my question is just: how does Janet compete on that front? What is the problem it is trying to address specifically? I looked at the web page a bit but it's still not clear to me.
I've posted this quote before, but it might help explain why making Clojure easier to get into maybe hasn't been a priority for Hickey et al.
So we need players. I would rant here, but I won't. But look at this guitar player with blisters. A harpist has blisters, a base player with blisters. There's this barrier to overcome for every musician. Imagine if you downloaded something from GitHub and it gave you blisters. - Rich Hickey (Design, Composition and Performance)
Clojure seems more concerned with power, expressiveness, and reach, rather than ease of use. Does this alienate new users, sure, but the Clojure community seems OK with that as a trade-off.
I am full to my neckline with Clojure kool-aid: I love the language and programming experience. But the "getting started" your parent is referring to, IMO, is getting the tooling set up, getting the repls connected, figuring out what a full-stack app looks like with its 2 distinct repls and toolchains and lein config mashups, hooking up an editor... and then having it break the next day. After 5 years of Clojure I still get frustrated if I'm away for more than a month.
It's like you were getting blisters from stringing your guitar. You buy a guitar, get home, and it takes three days to open the case. Then another week to figure out which strings go where. God help you when you realize you have to tune the thing.
Two, five, seven days pass and you haven't played a note. I don't think that's what Hickey meant.
Spot on with your amusing guitar analogy. Getting to play notes seems like an afterthought, but when it does it plays for you as if it reads your mind to do so. The problem is the setup and that's the part that I dislike these days, the patience to to configure the tools is not there, a lot of the tools are like black boxes, something goes wrong and it isn't visible or or it is too complex to enjoy the process.
If you're not familiar with the JVM, I think this is a big ask for most people as far as ease is concerned. I have created a template on my github to use clojurescript with your typical NPM setup that would allow you to get started right away. I know of no equivalent in the JVM world mostly because of how tightly Oracle controls the download experience of the JDK.
No, you should almost certainly be using openjdk, which oracle jdk is based off, unless you have a compelling reason an alternative implementation is better.
OpenJDK releases become unmaintained as soon as a new release comes out, not ideal for anyone who cares about stability. Zulu and Corretto backport bug and security fixes to supported releases.
I agree that it doesn't have to be a trade-off, but that mindset might explain why there is less focus on creating one-click installers.
An example would be Clojure's newish approach to managing projects via the CLI and deps.edn. It's very powerful, and expressive, but definitely not a one-click approach.
Clojure is an inspirational language that has some insightful opinions about how things should be done. A month spent learning Clojure is a great investment. A lifetime programming in Clojure would be a joy.
But as I recall the original Rich Hickey talks on "Why Clojure?" he was explicit that dependency/project management were very hard problems that Clojure didn't really attempt to solve.
I'm not aware of any Clojure tools that are best-of-breed for project management. Java has a better model for locking everything down (or maybe how the Linux Distros manage their repositories) and Python has a better model for just keeping up with the current state of things. I'm not aware of any half-and-half model that gives satisfying results.
Clojure is inferior to Java in that aspect because the number of things to keep track of roughly doubles (for every concept there seems to be a Clojure version and a Java version) and library management is bizarre and warty - see also the horrible import/require/use/some other one I can't even remember mess. And then there is unpicking the syntax differences between using things in the (ns) macro vs calling direct. I dunno; maybe something changed but that part of the experience is a mess. Unusually poorly done in Clojure too, everything else was so lovely.
I never got on top of it and I tried for months; as evidenced I can't even remember how to load a library after putting it down for a little while. Even assuming the classpath is correctly set. What would have to happen for a C programmer to forget #include "name.h" ?
> I'm not aware of any Clojure tools that are best-of-breed for project management. Java has a better model for locking everything down (or maybe how the Linux Distros manage their repositories)
Uh? Clojure locks everything down as a well. In fact, deps.edn solves many issues experienced with Maven.
Personally, I've found Clojure dependency management to be the best I've ever used in any language. It's simple, explicit, gets out of your way, and lets you just do your work.
> and Python has a better model for just keeping up with the current state of things.
I'd like to hear about this? Pip doesn't even have a command to update all dependencies in one go. And figuring what even are the dependencies of any given project is a mess.
> he was explicit that dependency/project management where very hard problems that Clojure didn't really attempt to solve.
For what it's worth, having used Clojure for work for a couple years now, and ditching leiningen for deps.edn (built in package and dependency management that hooks into maven), I've not had an issue with it. You just add the dependencies to your deps.edn, and run your program. If your namespace needs something from a package, you add it to the (:require ...) section of your ns declaration.
Here's an example ns from one of our messiest modules:
To be clear, projects like this can be run with the base Clojure distribution, no additional tools required.
> I'm not aware of any Clojure tools that are best-of-breed for project management. Java has a better model for locking everything down (or maybe how the Linux Distros manage their repositories) and Python has a better model for just keeping up with the current state of things. I'm not aware of any half-and-half model that gives satisfying results.
deps.edn generally asks you for specific versions if you're getting things from maven, so you don't risk not "locking everything down". If you really want to lock everything down however, you should check all your dependencies into your source tree, this is an option that deps.edn supports well, through the :local keyword instead of :mvn/version for maven dependencies. That namespace declaration I showed you is from a subproject that we import into one of our other subprojects using the :local keyword, and the deps.edn for it just declares the source directories and and the dependencies, everything else is handled automatically.
And leaves open a lot of room for someone to try to use (use) which is probably a mistake since you don't use it.
And sometimes your way has [] and sometimes it doesn't. Pretty much at random considering '[profusion.utils :refer :all]'. And the official docs add in a dizzying number of combinations of quoting requirements to recall.
It isn't the end of the world but that is a far cry from how good all the other parts of the language are. It is really sloppy and confusing to learn. There is no recommended approach and I personally can't remember which easy way I used last time so my personal projects cycle randomly. I think Clojure has the worst library loading mechanism of any language I think is good. Even your way has two completely different code paths (import vs require) to bring in dependencies.
> Even your way has two completely different code paths (import vs require) to bring in dependencies.
import and require have different purposes though, it makes perfect sense to me that they are separate. Import, here, is used to import Java classes, which don't hook into Clojure's namespaces directly; require is for bringing in symbols from Clojure namespaces. In general, a beginner or intermediate Clojure user will not touch the :import feature at all, nor the :use feature.
> It is really sloppy and confusing to learn.
That's one opinion of it I guess; though in my experience, the way that I do it is very common in publicly-visible Clojure modules. I've been doing it the same way since day one, without issue. There may be other ways, but you don't really need to care about them.
With this you'll understand most modules you come across, and you'll be able to accomplish basically anything you'll want to.
Given the average completeness of documentation on publicly-visible packages (though to be fair most big ones have what most would consider adequate documentation) including the core, you're going to have lots of opportunities to read other people's modules, and these minutiae will fade into obscurity and be overshadowed by your own program's problem space.
> For what it's worth, having used Clojure for work for a couple years now...
> ...it makes perfect sense to me that they are separate...
> A lib’s container is a Java resource whose classpath-relative path is derived from the lib name [0]
> No matter what some people say, getting started in Clojure is a nightmare. ~ galfarragem (earlier in the thread).
I'm hoping this smorgasbord of quotes is making my point for me - the fact that there is an easy way is good, but the problem is that the easy way is very well hidden and Clojure is competing with systems like 'pip install foo', 'import foo' in every single piece of documentation on Python there is on the internet.
I'm not budging from Clojure's import system being byzantine. I don't care that the people who stuck with Clojure figured out something that works for them, it is stupid and it is a very effective filter on keeping people out of the language. The lesson 'ignore half the reference manual page' is not an appropriate lesson to be learning while working out how to load dependencies.
EDIT If all the other parts of the project build were easy then obviously this wouldn't be an effective filter; but this combined with a misconfigured classpath issue for someone who doesn't know Java well would be the end of it.
Yep..I've found Clojure to be pretty difficult as I have very little Java experience. The language itself is fine, but needing to install and configure so many tools to get anything done is a major turn off. In my opinion, Clojure/Scala/Kotlin on the JVM and F# on .NET all have the same problem of assuming you're a Java or C# developer. I have zero interest in either and asking someone to spend a large amount of time learning them so that I can hop to a language I do like is a stretch. That's why they'll never beat Python in adoption which doesn't require 20 years of knowledge of an entire ecosystem.
No, these are not making your point for you. You bring up :import and :use, but in truth, a beginner or intermediate Clojure user is not going to use either of them at all; and when they choose to, it'll be because they have some deeper knowledge which will make the documentation appropriate to them. :import is primarily for people who understand Java and the JVM. If you know what you're importing, you will understand :import quickly; if you don't know what you're importing, you have no use for :import anyway. In the case of :use, nobody needs :use; it is useful primarily to the people who know why it is useful, and the documentation for it is suitable for that audience.
Getting started in Clojure is not a nightmare, ordinary people do it all the time, the fact that somebody said it was a nightmare says very little.
Clojure's mechanism for requiring packages is far from byzantine, whether you "budge" on that or not; many Clojure libraries have the snippet for including the current stable release of that library at the top of their README on GitHub. It isn't matter of "sticking with it" or "figuring out something that works for you", it is literally one relatively simple piece of knowledge that is learned once and works forever.
In short, if you find namespaces and importing byzantine in Clojure, you are probably at the level of struggling to write fizzbuzz in any language. The fact that there are features other than :require in ns does not indicate that :require is complicated, it just indicates that ns has features.
Somehow a language designed from scratch with all the purported wisdom of Lisp ended up with a nastier import solution than JavaScript, which had none out of the box for its first two decades of life, and then had to reconcile as many as 5 different module systems.
Am I missing something here? The experience is basically the same as the best available in JavaScript/TypeScript, how is it "nastier" or even "nasty" at all?
Also Clojure is doing just fine, not sure what you mean by "dying". The core and the tooling continue to improve, there are lots of libraries, more people writing than ever. I just don't see this death you're describing.
The comments here just strike me as ignorant and incoherent as a whole. Why do people who clearly have no experience actually trying to do something in Clojure have so much to say about it?
Clojure may support things that look daunting to you, but if you actually had any goal other than critiquing the variety of things you actually have no use for, you would not have the difficulties you describe.
Maybe I'm spoiled, I remember JDK setup being a pain on Windows a decade ago when I used it last, if that's the problem then I get it. My spoiled experience on a system with a functioning package manager is basically install-and-go, and
zero configuration required to get CIDER going after that.
I just don't get what's so bad about it, it's basically the same experience as Rust with Cargo; is that another "nasty" experience? What language with package manager has a better experience?
>For what it's worth, having used Clojure for work for a couple years now, and ditching leiningen for deps.edn (built in package and dependency management that hooks into maven), I've not had an issue with it.
>...
>To be clear, projects like this can be run with the base Clojure distribution, no additional tools required.
Didn't you just say that dependency management hooks into Maven? So doesn't that imply you need to get Maven set up before you can run a Clojure project?
> So doesn't that imply you need to get Maven set up before you can run a Clojure project?
Not sure what is meant by "get Maven set up". With Clojure it does not involve any additional work, it's just built in to the Clojure runtime, and it goes ahead and fetches your dependencies either when you ask it to, or right before loading your program for the first time.
I think they just use the Maven repositories, as in the servers themselves, not the Maven client software for Java, whatever that may be (I've never used it).
What turned me of from clojure when I tried it last time was "Why my trivial syntax errors like unmatched brackets or easy semantic errors like wrong number of parameters to 'built in' functiins blow up in my face with java stack that involves some parser or something only after I 'lein run' the program?" I used vs code with most popular clojure plugin and I was expecting more.
Thanks for sharing this... I'd never seen it before.
It does make me wonder how many languages we use that could be compared to bag-pipes... in that even when you learn how to play them expertly, they still sound like an animal being killed.
This process might seem easy for you, but maybe not for people installing Clojure for the first time.
In an extreme case, someone who doesn't know Java ecosystem might want to stop to research: what is JVM, why is it necessary, which version would be the best, what's the difference between Oracle's Java and OpenJDK, etc...
One could say the same for a plethora of programming languages some research is needed and we don't have to resort to extreme cases.
Out of the top of my head:
- There is the Python 2.7/3.X situation still going on, then there are the several distributions of python.
- GNU's R has a similar problem
- Installing gcc on windows was (perhaps still is) a confusing mess for a newcomer.
IMO I did not find installing clojure any harder than installing Scala for instance, and yet I have never heard (anecdotal, I know) complaining about Scala.
The user above mentioned that for _them_ the installation experience of a programming language matters a lot, and that they found the installation experience of Janet superior to Clojure.
You might not share that users preference of caring about the installation experience of a PL, but arguing that this user's preference is somehow unfair because many other languages also have bad installation experiences makes absolutely no sense.
> you install clojure (via brew, or sh install) and that's it, you're good to go
The vast majority of PCs are Windows, not Mac or Linux. Though WSL2 (available with Windows Insiders) makes working with Linux software a breeze, it's not the standard flow. Java isn't installed by default, either.
Your guide suggests using WSL and IntelliJ. Does IntilliJ actually work with Closure running in WSL? For that matter, does the VS Code plugin?
These are all headaches a new programmer won't have when getting setup with PHP, Python, JavaScript or most popular languages.
The Windows story for Clojure is disappointingly weak, especially if you are going by the "Getting Started" section on their website.[0] They have reasonable instructions for Linux and MacOS, but for Windows they point you to an "alpha" level tool.
I think this is especially disappointing because there are mature, cross platform solutions available but whoever manages the Clojure project seems hell bent on pushing their "clj" tool which is, clearly, treating cross-platform concerns as an after thought. The Clojure organization conducts a survey every year and this is hurting their adoption with developers on Windows.
"One new question we asked this year was about the primary developer operating system to give us better guidance about tool-related work. As expected, MacOS was the leader (55%), followed by Linux (35%) and Windows (9%)"
Getting started with Leiningen, in my opinion, is much easier although, as has been pointed out, installing a JDK is an extra step that other languages don't have.
I have both a MacBook Pro and a standard PC running Windows, and yes on Windows I run Clojure both on Windows and inside WSL, both IntelliJ and VSCode works pretty well with WSL there's really no problem running it.
I'm doing a lot of Clojure since years both on my MBP and on Windows and there's no problem at all doing that way. Besides VSCode even has a plugin for WSL which will let you directly hook into it.
So yeah there are some questions like which Java to install, which IDE, .. but these questions are the same for other programming languages.
If you have any hint regarding how to improve my guide don't hesitate to tell me if something is not clear in it :)
I'm not familiar enough with Clojure to help (ironically because I myself was put off by the tooling). The reason I asked about WSL and editor issues is because I encountered them myself when working with Elixir on WSL and VS Code and saw related issues on SO about Clojure. This was almost 2 years ago, though.
Probably the biggest thing would be to assume the person reading the guide has a brand new computer and hasn't installed anything yet (including Java and Homebrew).
It's really hard to assume much about the background of someone just trying a new programming language. Maybe they've worked with other languages and you're familiar with, maybe not.
This I think is a fundamental impedance mismatch between Lispers and everyone else.
A Lisper sees a REPL, and thinks they have "gotten started." When I think most language learners don't think they have "gotten started" until they, on the low end, have printed something at a familiar terminal, or, on the high end, pointed a web browser to localhost:8080 and seen some text there.
Running the batch file that comes with the project works for me and has worked on a variety of versions of Windows. I haven't had as much luck with the "clj" tool.
I don't see who the "clj" shell script is somehow "part of Clojure" any more than Leiningen or Boot. IMHO it's just a shell script and it works similarly to the other tools, except not in any way cross platform.
Yes but Leiningen is not distributed with Clojure. And as far as I remember there is no installer for Leiningen on Windows. Right now I find it is available through Chocolatey, but the main Leiningen page asks users to download and run a batchfile. That's a very strange instruction to ask a windows user to do: Running batch files downloaded from the internet goes against so much advice on computer security that is given to users.
I still feel dreadful when doing all these integration with leninigen. Work for whole month then get it. But there is limit of my personal time budget.
And how to work with vscode as it all fails, at least windows.
But love clojure syntax. In particular I found it hard to see all () and the simple added some syntax sugars help the eye a lot.
Hence jump to janet. In fact the community is very helpful.
Not sure but the size is small enough to see whether one can do embedded as I try picolisp but it is bounded to a low end Env.
Very promising.
Btw the whole point I later schedule more time to try clojurescript to ... May be that can wait a bit.
Of course, that's not the official instructions. These are the official instructions: https://github.com/clojure/tools.deps.alpha/wiki/clj-on-Wind... - they've managed to work out what the powershell is for "run untrusted shell script directly from HTTPs".
What there should be is an exe or MSI installer like every other Windows program.
So according to that page, there are 3 ways to install on Windows.
1. Alpha version of "clj on Windows", which seems to be the recommended approach, and requires going to another page to get the instructions.
2. Homebrew on Linux or Windows with WSL, linked to under "Installation on Linux".
3. Build from source, under "Other ways to run Clojure", which assumes git, Java, and Maven installed, with no instructions on how to install them.
I would say it's pretty confusing from that what is the optimal, recommended way to install Clojure on Windows. It might be better to have subheadings under "Installation on Windows" like "For Java developers" (assuming Java tools already installed), "For WSL users" (Homebrew), "For Powershell users" (clj on Windows). This would consolidate the Windows installation strategies and reflect the diversity in the Windows developer population. Some are already full time Java developers, some live in WSL as much as possible, and some fully embrace Windows specific tools like Powershell.
I wasn't aware of the page update, there has been like two years since I used Clojure last time.
It used to be so that they provided a zip to download.
In any case as mentioned on a sibling comment, I assume that anyone willing to use a guest language should get comfortable with the host platform.
So git, well for better or worse that is what most are using nowadays.
Maven, number one build tool on Java world, even if using another one, most likely those jars are coming from Maven Central.
Just like, regardless of my opinion on C, I keep my C knowledge up to date, because that is what I eventually might need to reach to when on UNIX like platforms.
See I get why you’d say that about the JVM, but as someone working in Node daily I don’t find the server side JavaScript ecosystem particularly useful. As soon as you need to do anything else than database CRUD, you’re basically on your own.
> Easy to get started: one click install, great website and concise docs.
Idunno, I read the whole homepage and I don't really know where to go to download it. Is "clone and run Meson" what you meant by "one click install"?
> No matter what some people say, getting started in Clojure is a nightmare.
On my distro I just do pacman -S clojure and I have a working clojure environment, on everything else it's usually available as one package. Not much of a "nightmare" to my eyes, at least when compared to Janet, which doesn't tell you how to install it anywhere on the website.
Janet's purported focus is that it's easy to embed in a larger C program. I haven't really seen that in practice, but I have used the C api to write some language extensions, and it is a joy. In comparison with Clojure, I much prefer using either C or janet to using Java and lisp side by side; with Clojure running on multiple hosts now the differences in language semantics between clj and cljs are just annoying.
As far as language features, I miss a lot from clojure: immutable/persistent data structures, protocols, not to mention concurrency primitives. But Janet's approach to performance and design is "do less". With the C api you can easily add bindings to some C library that provides a desired feature. But even without that stuff, Janet is for me a python-killer, if not a clojure killer.
Edit: at any rate, I think it's not meant to be a competitor to Clojure, its similar syntax just often invites the comparison. It's much more fair to compare it to Lua.
> Janet's purported focus is that it's easy to embed in a larger C program.
There is Guile https://www.gnu.org/software/guile/ that is an implementation of Schema with the focus on being an extension language that integrates with C and C++. Wouldn't it more practical to adopt and contribute to it, rather than invent an own wheel?
Firstly, this is a rather silly argument in general. One could say that Embeddable Common Lisp and Guile address the same niche and all developers from one project should consolidate in the other.
I have not used Guile to any extent, nor was Janet really influenced by it, but the comparison has been brought to my attention several times in the past. Janet is not scheme nor common lisp, so there are of course many differences that I cannot address here. However, as an extension languages, there are several things that I believe Janet does better than Guile.
Guile is not an ideal extension language for C projects (this is distinct from an extension language for GNU projects). Firstly, they address garbage collection with the Boehm GC, which takes some control over your runtime and is not known for great performance (the runtime/non standard C is the bigger issue). This was of course a decision made by Guile devs to make it easier to write correct bindings to C libraries in Guile, but it is not without it's downsides. Secondly, the project is not easy to embed in foreign build systems. Janet is more like Lua - built in tracing GC that is not conservative nor platform specific, no external dependencies beyond libc, and can be added to a project as an amalgamation (a single C file and 2 header files). This has enabled people to get Janet running more easily on a variety of platforms like mobile phones and even recently someone has been doing some work on getting Janet running on the Nintendo Switch. I believe Janet is also significantly smaller than even the smallest build of guile. Basically, Guile is not simple, which is (IMO) antithetical to an ideal extension language.
At the same time, Janet should feel like a much less minimal language compared to Lua. While core Lua limits itself to pretty much only standard C, Janet goes a little further to provide some abstractions over different platforms (that can be turned off via compile time options).
Thank you for elaborating on the reasons to create Janet!
My argument can sound silly, particularly considering the fact that you do not have any obligations to justify your project that you opened for others. I am very thankful to open source contributors, but I have a feeling that many open source languages, frameworks, libraries, and desktop environments would be more popular, polished, and maintained, if we could compromise, tolerate, and control our ego or creativity, and contribute to existing projects.
I think, we can see the benefits of focus and discipline by comparing Rails and its gem ecosystem with “blossoming thousand flowers” of Node.js web frameworks.
I'm in no way associated with Janet, so I can't answer for them. But as someone who is implementing their own language which shares a lot of goals with Guile, the reason I didn't contribute to Guile is that Guile is an implementation of the Scheme Standard, and it bound at least loosely to that. Certain modern features just aren't compatible and might not be accepted if you go through the effort of implementing them. There are real benefits to implementing a standard, and I'm not criticizing Guile for doing that--I use Guile. But if your goals aren't compatible with the standard you have no choice but to go a different way.
Guile is more than a Scheme implementation. You can implement a completely new language for it (somebody recently did Python) and reuse their embedding capabilities. Guile comes with an Ecmascript implementation, just to show that it can be done.
You can do that in most (all?) Scheme implementations. Macros are powerful, yo.
This goes back to another discussion here: just because you've implemented a language doesn't mean you've implemented it well. Sure, I can implement all the syntax of what I want. But is it fast? Does it report errors well? Am I enforcing my type system, or can I accidentally drop back into normal Scheme?
I think a lot of times new Lispers learn macros and, drunk with their newfound power, start writing 20% implementations that get them 80% to mature languages. And if you don't need or want the other 20% of a mature language, then that's fine. But if you do need or want the other 20% of a mature language, then you'll quickly discover that the Pareto Principle[1] applies. Lisp metaprogramming can be super powerful, but it's not a magic bullet: not only does it not kill werewolves but you can shoot yourself in the foot with it.
On the VM front, I love the JVM, but a vast majority of languages gaining popularity are generating static binaries. GraalVM may help close the gap here.
OO is overrated but most apps have some state and I found the entity-component systems solid but not still unwieldy.
Clojure has really great concurrency primitives; all the semantics I could want built right in. Except my concurrency often occurs in the persistence layer, and unless I'm also writing that layer, Clojure can't help me. Persistent/immutable data structures are amazing.
The delimiters IMO are a vast improvement over most other lisps (especially for creating specific data types).
Clojure's startup time is pretty brutal for a lot of things I'd like to use it for, and no amount of REPL-driven development can make Clojure appropriate for CLI tools.
> Clojure's startup time is pretty brutal for a lot of things I'd like to use it for, and no amount of REPL-driven development can make Clojure appropriate for CLI tools.
If you got the repl-driven development down, you wouldn't test your CLI by launching it, you would just evaluate the same functions as the CLI uses. Only time when you'd want to launch the CLI would be before releasing a build or for E2E tests. Once you got the code down for your repl and the startup time becomes a hassle, you compile down your Clojure program to a binary with GraalVM and now it starts up fast.
It's not about testing, it's about using it. I know how to use a REPL :)
GraalVM simply is not production-ready, though I follow its progress with great interest. That said, it's hard to compare the process of integrating with GraalVM against a language that actually just has fast startup.
Babashka is pretty cool, but it's another example of something that isn't quite Clojure. Nice if you can tolerate various "almost the same" languages, but Clojure itself is still weak in these domains.
I hear you, GraalVM is pretty new and while I've managed to write and deploy plenty of clis using it without any problems, it's a big hassle to deal with anything GUI or server related. So it does have a long way to go.
And while Babashka is not Clojure, it's interpreter (sci - https://github.com/borkdude/sci) is in fact a "Small Clojure Interpreter" that tries to stay as close to Clojure as possible. Unless you're using the Java interop, I've yet to hit anything I cannot do in Babashka that I could do in Clojure (I barely use Java interop)
‘Starts up faster than Clojure’ and ‘doesn't need the setup+compilation voodoo of ClojureScript’ are pretty good value propositions for lightweight runtimes.
The first point clearly didn't pan out. In reality, applications ended up bundling their own OSes along, so Clojure is stuck with antiquated VM on its ankle for no good reason.
I'm always flabbergasted about the ignorance against the JVM on this site. There is nothing out there that has seen similiar research and optimisations and has so good monitoring/debugging tools.
My position on the matter might be summarized as "No TCO, no copyable stackful coroutines, no buy." Separately from that a lot of my experience with the JVM involves things like trusting the JVM's claim that it spent 0 microseconds GCing a certain thread that was running code specifically designed to produce no garbage, then running the code in production for one day and losing tens of thousands of dollars, then learning that even if the JVM pauses your thread for 1ms for heap compaction it will still tell you it spent 0 micros on GC.
In other words, on the first day day of testing under realistic load conditions you learned how to measure GC pauses; then, presumably, you were able to improve performance.
It shouldn't have happened in a production environment, but setting up a way to lose tens of thousands of dollars if performance is bad, trusting unreasonable numbers, trying to produce no garbage, and requiring no GC pauses because margins are too tight are all your faults, not a shortcoming of your JVM.
It's your fault if you trade equities, or you do anything else in which milliseconds matter, with a software platform that is aggressively optimized for average performance and for server stability at the expense of hard real time guarantees and with a language that privileges enforcing constraints (both to ensure correctness and allow optimizations) over allowing the user explicit control. ("Your fault" at the organizational level, not personally, of course.)
Can you explain how Java was chosen for your trading application? Also, why were you unable to test it properly?
The org chose Scala for the trading application in the hope that developers and researchers could both use it, when previously they had been using very different languages. I thought this went mostly well. Scala enables you to use some shenanigans to pretend that a byte-array is an array of structs, and the 31 other threads of the application ran acceptably on the JVM. As an aside, my impression is that Java is somewhat common in the industry.
The application was tested in an environment that's a lot like production, except that we had substantially fewer cores than an exchange running the same number of matching engines, so the incoming ticks were a bit less bursty. That burstiness was important in this instance. A big reason for the differences between the production environment and the test environment was the cost of hardware.
I'm not sure I've ever heard of the JVM being used in trading level software before. I've gotten a broad but vague impression that custom applications are the norm.
No criticism, as I've only read others' accounts, but that sounds out of character.
Java or Clojure applications are "custom" too: custom code running in some kind of application server is more or less the same as custom code relying on libraries and frameworks in C or C++ or other leaner languages.
What's "out of character" (nice euphemism!) is adopting state of the art automatic garbage collection technology, writing in a language that makes actual garbage collection practically unavoidable, and then expecting that garbage collection doesn't happen or happens accordingly to arbitrary expectations. The JVM is clearly inappropriate technology if latency is important: it can perform well in common cases and with a reasonable level of tuning effort, but other options simply do not have the threat of GC pauses.
I gotta agree with HelloNurse here. When that kind of money is on the line you set up a production version that ingests real data at real speed, and produces the same output / response but doesn't actually spend / affect any money. You watch it for at least a week and see what happens.
I'm sorry to say it, but the loss of money here was not the JVMs fault. It was putting code with insufficient load testing in a production environment and crossing your fingers despite the fact that serious money was on the line.
You don't need another complete set of servers: the new production servers, before beginning actual service, are available for brutal stress tests and all sorts of other experiments while the old servers running the old software are still in use and undisturbed. If the system is completely new and there is no old software on old servers, it's even easier.
Considering that software mishaps in securities trading can annihilate a company of any size, not only cost you as much as a bunch of servers, lack of testing appears very reckless.
> You don't need another complete set of servers: the new production servers, before beginning actual service, are available for brutal stress tests and all sorts of other experiments while the old servers running the old software are still in use and undisturbed. If the system is completely new and there is no old software on old servers, it's even easier.
We did not generally physically swap out servers each time we changed a line of code. Rather, we had two identical sets of servers, one for production and one for test. For test, we had some additional machines to run matching engines. If we wanted to make the test environment more closely match an actual venue, we would need many more machines that run matching engines. That still might not be sufficient to produce identical output timings in prod and test, though, because venues generally do not publish the sequence of all incoming ticks they receive during a day, the source code of their matching engine, what hardware they are using, their kernel version, and so on.
> Considering that software mishaps in securities trading can annihilate a company of any size, not only cost you as much as a bunch of servers, lack of testing appears very reckless.
It's strange that you replied to me suggesting we had no production-like test environment ~10 hours after I replied to you saying that this code did fine in our production-like test environment.
I reckon part of the point is that a VM (in the JVM or CLR sense) might be a poor fit for the given use case, as might an automatic garbage collector, and thus that might dictate the use of languages which rely on neither (like C/C++ or Rust).
If you do a trivial amount of up-front work, C and Luajit have these properties, but Luajit often isn't a suitable replacement for the JVM and C isn't a VM. So no.
I did a JVM targeting language as a research project, and was involved into porting KVM to an obscure architecture. It's been a while of course (early 00s) so maybe I misremember something or there were huge strides of progress in JVM.
Can you jump over 64Kb in bytecode yet? Allocate a lexically scoped variable?
Of course, enormous amount of work has been put into making this particular pig fly at reasonable speed. Doesn't change the fact that most usability complaints about Clojure stem from reliance on JVM piggybacking.
As far as I know, people in the Erlang world tend to use NIFs for computation heavy tasks: http://erlang.org/doc/tutorial/nif.html However, I have not done that myself, so I cannot tell from experience how that works.
From the narrow scope of web development, JVM is fine. Kotlin is able to have every ergonomic feature you'd want from a language, and it gets closer to the performance of C in TechEmpower than many other languages (notably C#, Node, and Python, three of the most popular languages).
Tuning can be a pain, but scaling anything is hard.
It is clear that a lot of very important and practical work had been delivered with Java/JVM. But the original point was not about what is possible, but what is optimal.
Kotlin, from the little I've seen, appears to be largely a syntactic variation of Java, so there is certainly good impedance to JVM. Clojure is less so, and here lies the reason everyone curses about its backtraces.
Java is antiquated though, I don't see many new big libraries/frameworks being written in it. Java is too big and too entrenched in the enterprise to go away any time soon but in ten years the language will become legacy. For what's being used, languages like Go and to some extent Rust are eating Java's market share for new stuff being built. More and more universities are moving away from Java as teaching language too.
Clojure is in a bad spot here, it was a good idea at the time but not today. Clojure relies on Java for its libraries cause Clojure has almost no ecosystem. 95% of Clojure libs are Java wrappers.
HN has a very large bro/cowboy coder constituency. I suspect a large portion of the commenters here have not built anything non-trivial. You learn to filter it out but it's disappointing to learn that "engineers" are not much more rational and objective than the average Joe.
That "antiquated" VM is head and shoulders above any other extant runtime in compilation, GC and observability. Not only that, most of the major innovations in recent years in those areas seem to be happening there. Moving from the JVM to almost anything else -- be it Python, Go, Erlang or Node -- feels like being transported to medieval society. Don't get me wrong, some find it liberating as in, huh, I turns out I can survive without my smartphone, but calling the state-of-the-art technological leader "antiquated" is taking it way too far. If you care about performance, productivity and observability, there really aren't that many alternatives out there, and whatever adequate alternatives there are, they are even more "antiquated." And guess what? It turns out that a great many people care about those things.
Is it? I've looked hard and couldn't find any runtime that isn't more than five years behind OpenJDK(+Graal) in those areas, but maybe I missed something. I'm not saying it's perfect, but there's nothing out there that's better in those areas.
Just to add to your point the only alternative that I would consider is .NET, and even then I do acknowledge that it is behind some JIT stuff, given that they have been favoring AOT / and single JIT scenarios.
Without Valhahla we will never get a Java variant of Unity, jMonkey Engine is a good as it gets and it has plenty of native code to overcome the areas where the JVM is found lacking.
It's probably the closest contender [1], but its non-Windows story is still a handicap, as is Microsoft's habit of making sweeping incompatible changes to their development platforms every 5-6 years.
[1]: A different philosophy that gives more control to the user in exchange for explicitness puts it ahead in some areas (structs) and behind in others (compilation quality, GC), but as a runtime engineer it's "technologically" behind (I work on OpenJDK so I'm biased, but I came to work on OpenJDK because that's where most interesting innovation in runtimes happens).
Disappointed? Not at all! I worked with it many years ago.
Whilst WCF made some notable improvements over what existed within the ecosystem before it, it was still a sprawling, complex PITA and full of developer friction. Killing it off in this case was definitely the right thing to do :-)
Do you have anything to support that expression trees are being sunset? I haven't seen anything of the sort, unless you are talking about a deprecated library that has been replaced. But System.Linq.Expressions is still around.
.NET Core's cross-platform tools and ecosystem is wonderful. I'm working on a small team and the devs are using Windows, Mac, and Linux. CI builds are a mix of Windows and Linux, deploying to Linux.
I think their biggest weakness now is branding (.NET vs .NET Core). This will be fixed with .NET 5, which merges the two and will make all flavors of .NET cross-platform.
I guess this boils down the difference between what I call "l'art pour l'art" software engineering vs production-ready code providing a business functionality. The amount of hello world computing on HN is out of the roof, it seems nobody really cares about software lifetime or just never run into a situation when observability is a must. I think the reason for this that most businesses being ok with software being ridiculously expensive and shitty quality. The few places where software matters use Java/C++ because that works at a massive scale and these languages bring observability to the table that is required to maintain a service.
But that's besides the point, right? My question is about what Janet's niche is -- or are you arguing that we need a native Lisp because Clojure is only available on the JVM?
I feel like a better description of how closure feels as a language would be something like “a functional language where everything is data and that data is flexible”. In particular the difference from a typical strongly typed functional language where basically everything is data you can dig into is that the data representation in closure is more extensible and uniform (because the types are implicit and not enforced)
In that respect, Janet doesn't really bring anything very new. Its just an alternative to Lua. Truth is, Lua had pretty few alternative as it stands. When you need something small, fast, to embedd. So Janet is a competitor there.
Clojure was never against any of the ideas in OO, just that they should be accessible individually if or when they make sense. Traditional OO is very “all in”, while Clojure is very a-la-carte use the bits that make sense for the problem you are trying to solve. Clojure also encourages a data-over-objects and a functional-first approach, but when you need the OO features, they’re there and you should use them.
Even Smalltalk supports the other way around, although very few are aware of it, because they never bother to learn it.
You can do LINQ style coding in Smalltalk-80, and modern Smalltalks like Pharo do support traits as well.
So the point being that all major languages embrace both paradigms.
"Traditional OOP" basically boils down to Java until version 8 or C# until version 3, and very little else, but unfortunately most teachers fail at giving overviews of programming languages thorough computing history, and many just learn what they can reach out for.
Well, yes, I should have said “popular OO” instead of traditional. I did mean the Java’s and C#’s, Ruby’s and Python’s of the world, not the Smalltalks.
> So the point being that all major languages embrace both paradigms.
Sure, nowadays, most languages are very much multi-paradigm, but typically there is a dominant paradigm and the others are somewhat second-class. For example, in recent years, Java has gained a lot of functional programming feature too, but its not in the same ballpark as Haskell.