Goodbye, Chlorine. And welcome, Lazuli!

So, if you’re not familiar with Chlorine, or any of my tooling, let me get you a refresher. If you don’t want to read it all, the TL;DR; is – Chlorine is a Socket REPL plug-in for the Clojure, and ClojureScript languages. It also supports nREPL, although to a lesser extend, and it works on the Atom editor. It also contains a VSCode version called Clover, and I tried to port it to NeoVIM and I called it Clematis.

And now, it’s gone.

For historical reasons, I wanted to rename the project for a while – so that Chlorine would stay as a “socket REPL for the Atom editor” and the new plug-in would be the “Chlorine:Next” or something like this. I tried to like the name Alya, but in the end I never did…

… and then, I stopped working with Clojure. Like, at all. For a while I haven’t touched a single line of Clojure code, although I still use ClojureScript on my personal plug-ins. But ClojureScript have a weird problem – I can’t develop two plug-ins written in ClojureScript at the same time, so I need to compile everything, except for one, plug-in for “release”. Which is annoying to say the least, so that’s why I started the “Star Ring” metapackage – to make all plug-ins a “single, unified codebase”. Unfortunately, this have its own fractal of problems that I won’t discuss now.

So not that I’m now working with Ruby, I needed better tooling for Ruby otherwise I would go crazy. Leaving the “REPL-Driven Development” of Clojure behind is a nightmare, because it’s such a great tool and it somehow “grows” in you in such a way that you can’t imagine working in a codebase when you can’t evaluate your code all the time. And that’s where Lazuli appears… but again, because of the problems with not being able to develop Lazuli and Chlorine at the same time, Chlorine’s development stalled… and I decided to stop working on it to work in Lazuli.
(more…)

Last open-source improvements

For the last two months, I have been busy searching for a new job, unfortunately. But also, because of this, I was able to evolve on lots of projects that I have been working in a while. So in this quick post I want to explain a little bit what I did, what is happening, and hopefully somebody might be interested in some very interesting improvements.

First thins, I already wrote about Chlorine in my last post. This week I was able to remove all the dead code that I had in the previous version, and I’m closer than ever to publish a new version of that I will call “Version 2.0”. Unfortunately, this version will be lacking some features that the previous version had, and I’m not really sure if I’m going to add this back or not.

But the thing is, because the new Chlorine is more configurable and the config file is easier to write, I hope people can add these features in user-space, so I can decide later if I’ll re-include them or not (it’s always easier to add stuff than remove what people already depend on).
(more…)

A new Chlorine is almost done!

For the last few months, I’ve been working on a new version of Chlorine (now that Pulsar is on a good track). Here I want to share what to expect of this new version.

For a quick TL;DR; it’ll have better ClojureScript (shadow-cljs) support, fix some bugs related to evaluating code and the REPL being “locked” without returning the results or evaluating new commands, and have better configurable parameters. Things will probably break a little bit – it’s not a non-breaking-change, unfortunately – but hopefully it’s good enough that people will want to migrate to the new version.
(more…)

Killing Atom

So, Microsoft blogger decided to post about “sunsetting Atom”.

Honestly it’s an amazing euphemism for “for killing Atom” so I’m not going to bother to sweet-coat anything: in fact this post will probably have some harsh words, so if you like Microsoft (for some reason) I advise you to stop reading…

Anyway: Microsoft is a shitty piece of crap company. They committed so many crimes and the reason why they didn’t answer for most of these is because they bought the lawyers that were accusing them. When they they posted that they are going to Sunset Atom, it sounded like an inevitable thing – Atom was stalled, so they’re going to archive the repositories and if someone wants to keep using this just fork it and keep developing the editor.

But the truth is – not even this is possible. And we’re going to find out why in a moment, but first a little bit of story:

Even though Microsoft told everybody that they were going to keep developing the editor, it is strange that years later they decided to just give up on the idea. But this decision was not rushed in any way – they were planning to do that for a long time!
(more…)

The magical wonders of programming with pure data

I’ll start with a disclaimer – if you’re developing in ClojureScript because of performance, you’re doing the wrong thing. Although a Clojure code can be really close to Java performance, ClojureScript simply can’t match JS performance – specially because in Javascript, the fundamental data structures like arrays, sets, and objects are implemented in a faster language, and as of today, no “user space” data structure can get even close the “native” ones. And, let’s not forget that JS is slower than Java.

So, if you want to beat JS performance in ClojureScript, you have to make use of what ClojureScript offers you – the REPL, the fast experimentation, and the wonderful experience of programming with data. So, this is a tale of a huge performance improvement that I’m currently working in Chlorine.

Rendering EDN

In Chlorine and Clover, when you evaluate something, the result will be rendered in a tree-like way at the console. This works quite well for Clojure, because UNREPL makes structures that are too big small, and you can query for more data. So far, so good.

In ClojureScript, Clojerl, Babashka, etc, things are not so good. Big data structures will be rendered fully on the view. They can lock or crash your editor, they can occupy all your memory, etc. The reason for that is that tree structures are hard – when you’re rendering the “parent”, you don’t know what the children will be. Currently, in Chlorine, rendering (range 80000) locks my editor for 4 seconds until it calculates everything, layouts all data, etc… and I wanted to change this.

Reagent vs Helix vs React

I was always intrigued on how much performance hit I get when I use Reagent’s Hiccup data structure instead of React objects – after all, there must be some performance problems, right? After all, that’s the promise of Helix – to not pay this performance hit because you’re closer to what React wants.

So, first things first: profiling Javascript inside Electron IS A NIGHTMARE. I decided to install React Devtools extension on Electron (inside the Atom editor) but that got me into so much trouble, false-positives, wrong profiles that I ended up deciding against it and simply used the “performance” tab to do my profiling. There, I could see batching.cljs hogging my performance, so the next move was easy – move away from Reagent and use Helix.

Except… that Helix uses some macros and I ended up doing the code in React. My testcase was simple: render a vector of 80000 elements and see how it would perform, obviously without all the bells and whistles that Chlorine offers today (otherwise this experiment would be waaay longer). And that’s where things get surprising: with Reagent, I was hitting 1800ms of scripting, and about 120ms of rendering. With React… 1650ms of scripting, and about 200ms of rendering. I decided to do more benchmarks and probably because of OS caching, warm-up, or whatever, the results got even closer, with Reagent sometimes performing better than React – but still too slow.
(more…)

Your editor as a query

Some time ago I found out this post: https://petevilter.me/post/datalog-typechecking/. It stroked me as really interesting – because it was an idea to make some IDE not depend on some internal API that only works for a single editor, but somehow make a tooling that’s query able by datalog. This datalog Read more…

Implementing shadow.remote API

Since version 0.8.0 of Chlorine, there’s a new way to evaluate ClojureScript code: that’s the Shadow-CLJS Remote API. It is basically a new REPL (not nREPL, no Socket REPL) over WebSockets to try to solve problems when translating other REPLs to ClojureScript. So, to understand why these problems exist, I’ll first introduce the difference between ClojureScript and Clojure.

On Clojure, you’re always inside a JVM. This means that compilation happens on the same JVM that your REPL, and your code is running. If you practice REPL-Driven Development, even your tests are running on the same JVM. In practical terms, it means that when you fire up your REPL, you already have everything ready to run code, compile code, and evaluate forms.

On ClojureScript, the compiler is written in Clojure – that means it’s running on the JVM. So, to produce Javascript code you don’t need a Javascript environment – and that’s when things become confusing, because when exactly will you run the REPL? Let’s try from another angle: if you start the REPL on compilation time, you can’t evaluate code (because there’s no Javascript generated, nor any Javascript engine running). If you start the REPL when you run the compiled code, this REPL can become unusable if you stop the Javascript environment, and also you have to coordinate lots of state and translations between formats.
(more…)

The History of Chlorine

Before I even started with Clojure, I was analyzing LightTable – the idea of that editor was to support better integrations between the code you’re writing and the code that’s running. It was a really good experience, but the main problem I had is that it was in the very beginning, with few plug-ins and bad documentation. I tried to make the parinfer plug-in work in the editor, but it had lots of bugs and then I simply changed back to Atom. At the time, proto-repl was the best package to work with Clojure, and I made some small changes to it (so I could add some callbacks to when a new connection to nREPL was made, and other small issues) to improve my workflow.

Fast forwarding a little bit, I started my first Clojure job at Nubank. Most people were using InteliJ, but I felt that by using Atom I had a different approach on problem solving, specially those hard parts where the fast feedback of “run in the REPL and see the results in your editor, then browse over the keys” could give better insights about what’s happening. I tried to implement some features that proto-repl didn’t have at the time (and Chlorine still does not have some) like “automatically add nREPL port”, and “watch expressions” (almost the same as watch variables in a debugger). These ended up in a package called clojure-plus, that still exist today.

I also began to experiment with ClojureScript (at the time, only Figwheel was available – Figwheel-main didn’t even exist!) and found that existing tools didn’t provide the same power that I had with Clojure. It also didn’t have autocomplete, goto var definition, and so on. To ease a little bit these problems, I ended up adding on clojure-plus some CLJS support – when you tried to evaluate a .cljs file, it would try to connect to ClojureScript, reserve a REPL, then evaluate the code over there.
(more…)

nREPL on… Chlorine?

When I started the Chlorine project, I just thought it would be great if I could target all Clojure-like REPLs that already exist but didn’t have tooling support. At the time, this would include Lumo and Plank, mostly. Also, Shadow-CLJS and Figwheel have some “clunky run-some-code-and-transform-in-cljs” way of working that simply didn’t click with me.

Now, almost a year later, Chlorine supports Clojure, ClojureScript (Shadow-CLJS, Lumo, Plank, or even over clj), ClojureCLR, Arcadia, Babashka, Clojerl (Clojure on Erlang) and Joker (Clojure on Go, also a linter). But the reality is that working with a pure Socket REPL is really hard – a socket REPL works exactly like a regular one, printing namespaces after each code, and so on. Also, there are some strange decisions on some REPLs, mostly likely ClojureScript (that is the second most used Clojure flavor), so things are not always easy. To put things in perspective, currently Chlorine uses 3 ways to evaluate code: It uses unrepl, that only works on Clojure, or uses internal APIs of shadow-cljs (that obviously only works for shadow-cljs), and for other implementations it uses a kind of a hack – it evaluates the code, inside a trycatch, and it returns a vector where the first element is a symbol in a specific format that Chlorine will understand and then link that with the response. This “hacky way” is currently being used for every other implementation except Clojure and Shadow-CLJS. Things work (autocomplete works too), but it is not pretty and sometimes have strange results.

As a matter of fact, I was already thinking about removing UNREPL (it’s really hard to implement new features on it, and some good ideas only work in theory – for example, the ability to evaluate long strings / collections and render only a part at a time aren’t that good with lots of edge-cases) and, to do it, I though about a better, non-hacky way to evaluate things on some Socket-REPLs (that, again, would only work on some REPLs – ClojureScript REPLs will probably never support “upgradable REPLs” because of the way they work) – the only thing that I had to understand is how to implement this “upgraded REPL”…

Then, recently, Babashka added an initial support for nREPL, with an insane low amount of lines. So, I’ve tried to implement a way to evaluate code over nREPL… and it was really simple to do it, using a npm library that already did it. But implementing like this meant that the user would need to know if the host/port to connect is a Socket REPL, or a nREPL (and the user does not know – lots of tools like lein and shadow-cljs show an nREPL port to be connected).
(more…)

REPL-Tooling Clients

Chlorine, Clover and Clematis are all implementations of the same library: REPL-Tooling. In this post I will show you how to create a new implementation of it in a way that’s completely disconnected from any editors, so you can grasp the general concepts.

Suppose I want to do an implementation for an editor that doesn’t run JavaScript – so it’ll connect by some kind of socket. In this example I’m going to use WebSockets because… why not?

We’re going to create a shadow-cljs node project and add repl-tooling as a dependency. We will also had some more dependencies: mostly ws for websockets and the same react libraries that we use for reagent (react, create-react-class and react-dom) – repl-tooling still needs reagent, and probably in the future I will split it into two different libraries (one for the REPL handling and other for the visual rendering part). This supposedly is not to much of a problem because ClojureScript compiler will probably remove these parts in the dead code elimination process anyway. So, our package.json file will just be like this:

{
  "name": "ws-repl",
  "devDependencies": {
    "shadow-cljs": "^2.8.83"
  },
  "dependencies": {
    "create-react-class": "^15.6.3",
    "install": "^0.13.0",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "ws": "^7.2.1"
  }
}

And our shadow-cljs.edn file:

{:source-paths ["src"]

 :dependencies [[repl-tooling "0.4.0"]]
 :builds {:node {:output-to "index.js"
                 :target :node-script
                 :main ws-repl.core/main}}}

The first step is when someone connects to the WebSocket. Then, we’ll just create a connection to the client, and send a list of supported commands – for now, is just the “connect” command:
(more…)