announcements

opqdonut 2026-03-06T11:21:22.023359Z

malli 0.20.1 out! highlights: β€’ new experimental :validate schema for outputting custom validation errors β€’ fix for clojurescript 1.12 https://github.com/metosin/malli/releases/tag/0.20.1

πŸ”₯ 10
1
πŸ™ 3
πŸŽ‰ 13
borkdude 2026-03-06T12:40:23.641239Z

https://github.com/babashka/instaparse-bb: Use https://github.com/Engelberg/instaparse from babashka! v0.0.7 β€’ Bump pod to 0.0.7 β€’ Add add-line-and-column-info-to-metadata β€’ Add get-failure β€’ Fix opts passing in parser (e.g. :output-format :enlive) β€’ Support java.net.URL for grammars And what's cool about this release, you can now run https://clojurians.slack.com/archives/C06MAR553/p1772758259332449 from bb too :-D

bb -Sdeps '{:deps {io.github.babashka/instaparse-bb {:git/tag "v0.0.7" :git/sha "97ed438"} io.github.replikativ/superficie {:git/tag "0.1.11" :git/sha "41433c3"}}}' -e '(require (quote [superficie.parse :as p])) (println (p/parse-string "def x := 1 + 2"))'

πŸŽ‰ 18
whilo 2026-03-06T23:24:11.779129Z

Nice work! Parse everywhere...

whilo 2026-03-06T00:50:59.332449Z

https://github.com/replikativ/superficie β€” surface syntax for Clojure During my PhD (in ML) I worked in Clojure while everyone around me used Python. Whenever I tried to show my code in a presentation, a paper, or a whiteboard session I'd lose people at the parentheses immediately. Not because S-exps are bad, but because you can't expect someone to read them on the fly when they've never seen them before. That initial unfamiliarity takes a few days to overcome, but a few days is infinity when you're in a meeting. Superficie is a bidirectional renderer that translates Clojure into syntax that Python/Julia/TypeScript developers can already read:

;; Clojure                              ;; Superficie
(defn process-users [users]             defn process-users(users):
  (->> users                              users
       (filter :active)                     |> filter(:active)
       (map :name)                          |> map(:name)
       (sort)                               |> sort()
       (take 10)))                          |> take(10)
                                        end
It's not a new language - there's no separate runtime or ecosystem. You write Clojure as normal. When you need to show it to someone outside the Clojure world, you render it. The translation is automatic, bidirectional, and roundtrips cleanly (`.clj` β†’ .sup β†’ .clj). It can also serve as a gentle on-ramp: shown side-by-side with Clojure, superficie helps newcomers build fluency naturally instead of being blocked by unfamiliar syntax. Tested across 17 real-world projects (core.async, Datahike, Onyx, Malli, Clara Rules, ...) with 98% of files roundtripping cleanly. Includes a highlight.js plugin and an interactive side-by-side demo. https://github.com/replikativ/superficie https://replikativ.github.io/superficie/examples/side-by-side.html

πŸ‘ 11
33
πŸ†’ 6
πŸŽ‰ 13
henrik 2026-03-06T08:46:45.059979Z

Cool idea! Have you tested it on someone with paren-positional aversion syndrome?

whilo 2026-03-06T08:51:19.644819Z

Not really yet. I don't think people necessarily have paren-positional aversion, it is just hard to do it on the spot and I came across as weird when I expected people to do it. I will test in the next days though.

whilo 2026-03-06T08:54:39.777199Z

@pez I fixed reader conditional handling so it does not break and have an example at the end https://replikativ.github.io/superficie/examples/side-by-side.html, but for now functions containing it fall through to the sexp copy case. I can try to improve this if needed, maybe this is good enough though. Getting all the grammar perfect will be considerably harder (maybe doable, but this is why we don't like such syntax, right πŸ˜‰ ?)

henrik 2026-03-06T09:07:09.182429Z

Right, of course. I personally think it reads well, but I’m also not in the target group.

whilo 2026-03-06T09:11:55.992759Z

Hehe, yes. It is always very easy to forget how long it took to learn something and how difficult it felt in the beginning. Reading Lisp is not super hard, but when you look at it the first time it looks intimidating, I think. I remember when I first saw Elisp as a not yet real programmer a long time ago, and it just seemed very alien and difficult to even categorize.

pez 2026-03-06T10:31:07.926459Z

@whilo I meant that I want to consumer Superficie as a library from ClojureScript. πŸ˜ƒ

Dustin Getz (Hyperfiddle) 2026-03-06T10:49:24.455759Z

can i see s-expr style UI code like electric, these two functions: β€’ https://electric.hyperfiddle.net/fiddle/dustingetz.talks.two-clocks$TwoClocks β€’ https://electric.hyperfiddle.net/fiddle/dustingetz.talks.dir-tree$DirTree

Dustin Getz (Hyperfiddle) 2026-03-06T10:50:31.296189Z

if you can crack UI code it might be a really big deal, note you can also use JSX-style inline xml literals if it helps

Dustin Getz (Hyperfiddle) 2026-03-06T10:51:35.185389Z

the reason UI matters is due to how compactly composed and nested it is, UI code is really a lot more dense and intricate than backend code

whilo 2026-03-06T11:10:59.399069Z

@pez done, latest release 0.1.10 should work in cljs.

πŸ‘ 1
πŸ™ 1
JosΓ© Javier Blanco Rivero 2026-03-06T11:11:58.362139Z

Awesome! I remember a re:clojure conference where James Gosling gave a talk and basically the only complaint he got about Clojure were parentheses. And I thought to myself: well, what if you could remove them just for reading (think of vim visual mode)?

πŸ‘ 1
whilo 2026-03-06T11:29:18.858329Z

@dustingetz added a special case for e/defn for now (not ideal, can be generalized later):

e/defn TwoClocks():                    
  e/client(let s := e/server(e/System-time-ms()), c := e/client(e/System-time-ms()):
    dom/div(dom/text("server time: ", s))
    dom/div(dom/text("client time: ", c))
    dom/div(dom/text("skew: ", s - c))
  end)
end

whilo 2026-03-06T11:30:33.737069Z

(special case to make it render like defn that is)

Dustin Getz (Hyperfiddle) 2026-03-06T11:33:14.440829Z

that's not bad

Dustin Getz (Hyperfiddle) 2026-03-06T11:34:31.035199Z

let can be flattened into imperative statements like JS also, the let scope extends the rest of the block

Dustin Getz (Hyperfiddle) 2026-03-06T11:35:53.224859Z

(let [a 1] (let [b 2] (+ a b)) becomes let a=1, b=2; a + b and this covers the happy path, if the let is bounded you need a block scope operator

Dustin Getz (Hyperfiddle) 2026-03-06T11:37:02.647369Z

i.e., this let has spurious indentation that can be eliminated to feel like JS

defn safe-divide(a, b):
  if zero?(b):
    {:error "Division by zero"}
  else:
    let result := a / b, rounded := Math/round(result):
      {:value result, :rounded rounded}
    end
  end
end

Dustin Getz (Hyperfiddle) 2026-03-06T11:37:35.281589Z

flattening out ))))) introduced by let solves half the problem with reading sexprs

Dustin Getz (Hyperfiddle) 2026-03-06T11:39:02.271839Z

clojure proper could do it too, (defn foo [] (let a 1, b 2) (+ a b)) is very natural

Dustin Getz (Hyperfiddle) 2026-03-06T11:42:17.985639Z

e/defn TwoClocks():                    
  e/client:
    let s := e/server(e/System-time-ms())
    let c := e/client(e/System-time-ms())
    dom/div(dom/text("server time: ", s))
    dom/div(dom/text("client time: ", c))
    dom/div(dom/text("skew: ", s - c))
  end
end

whilo 2026-03-06T11:44:40.607919Z

Makes sense. I will take a look.

pez 2026-03-06T11:48:04.178089Z

Here’s a quick experiment (using Joyride) to get a feel for what could be a nice Calva experience, when showing some code to someone not used to parens.

πŸ‘ 2
❀️ 1
pez 2026-03-06T11:49:47.891119Z

That one only watches files saved on disk, but we could watch the buffer instead to make it more easy to follow as the file is edited.

Dustin Getz (Hyperfiddle) 2026-03-06T12:26:33.776449Z

is it possible to make the syntax match exactly javascript so that javascript editors will have a chance?

borkdude 2026-03-06T13:05:20.343039Z

Now works in bb too! https://clojurians.slack.com/archives/C06MAR553/p1772800823641239

pez 2026-03-06T13:25:39.774839Z

Ha! That was my next question, @borkdude! πŸ˜ƒ So then maybe also in JS SCI?

borkdude 2026-03-06T13:26:00.600799Z

This uses babashka pods so that won't work with JS SCI

pez 2026-03-06T13:26:57.069789Z

I’ll try out and see where it may run into problems.

borkdude 2026-03-06T13:27:22.850619Z

I mean with SCI you could bundle pre-compiled libraries all you want, if you own the project

borkdude 2026-03-06T13:27:33.626189Z

scittle doesn't support it from source, I'm sure

pez 2026-03-06T13:27:54.412089Z

Which I do. Joyride is my use case right now.

borkdude 2026-03-06T13:28:00.521899Z

yeah ok

whilo 2026-03-06T20:13:02.360629Z

@dustingetz let flattening is in 0.1.12 . I also thought about getting it closer to JS, but the {} are tricky to handle.@pez I added a textmate grammar and some VSCode instructions, but we can rearrange this with Calva, too. https://github.com/replikativ/superficie?tab=readme-ov-file#syntax-highlighting Once we agree on the syntax sufficiently well I would also add it to linguist or do whatever necessary to make sure it works in GitHub's Markdown. Happy to take suggestions.

πŸš€ 1
pez 2026-03-06T20:19:38.325009Z

@whilo, very cool. I now think best would be do this as a separate extension to VS Code. I have made a template project to make it easy to create VS Code extension with ClojureScript: https://github.com/PEZ/vscode-extension-template

Dustin Getz (Hyperfiddle) 2026-03-06T01:43:11.103379Z

i like it'

Dustin Getz (Hyperfiddle) 2026-03-06T01:43:45.293379Z

what does UI code look like

whilo 2026-03-06T02:45:31.900929Z

Added a hiccup example at the end https://replikativ.github.io/superficie/examples/side-by-side.html, maybe not ideal (?). Would you prefer a functional representation like (dom/div ...) ? This will basically create a nested function call structure. (Also syntax highlighting is not yet fully correct).

πŸ‘€ 1
whilo 2026-03-06T02:45:58.921019Z

(commata are also whitespace and can be removed)

pez 2026-03-06T07:05:25.493729Z

Anyone (like me) reading on their phone and not getting it: Tilt the phone and read in landscape. πŸ˜€

πŸ™ 2
robert-stuttaford 2026-03-06T07:27:09.408459Z

what a clever idea!

❀️ 1
pez 2026-03-06T07:46:01.366579Z

How much work to make it CLJC, @whilo? Then we could use it as a library from Calva and build a live Superficie-to-the-side viewer.

πŸ‘ 1
jeaye 2026-03-11T18:11:00.326879Z

This is very cool, @whilo. Nice work! Have you seen these? They're different from Superficie, but share a similar mentality. β€’ Clojure without parens: https://github.com/ilevd/cwp β€’ Rhombus (Racket dialect): https://rhombus-lang.org/ I'm quite interested in this direction as an alternative syntax people write for Clojure. The main challenge, aside from an optional alternative lexer, is how to represent macro output in this form while not breaking existing macros. This isn't strictly necessary, if we just accept that macro writers need to understand the underlying s-expr. If we start writing in this form, we would need to adapt our tools: β€’ Slurping and barfing β€’ Eval word/surrounding form (nREPL clients) β€’ Syntax modes for Pythonic Clojure, for automatic indentation β€’ clj-kondo? It's possible that the tools continue to work on the CLJ version, even if the source is in the Pythonic version (we need a name for this format, like hiccup). However, that might lead to disconnects in line/col info for error reporting. What're your thoughts on how we can take this all the way? Not just for rendering, but for authoring. Enable the Python users to write Clojure. I think it's an important step for Clojure and it's one I have been meaning to tackle once jank is more stable, but I love that you've already built something which works. It's important because one of the biggest reasons mainstream devs scoff at Clojure is because of the parens. We don't have to like it or agree with it for that to be true. But is Clojure limited by its parens as much as it's enabled by them? Perhaps not, if the same semantics can so readily be described using indentation.

whilo 2026-03-11T18:15:23.941299Z

Hey @jeaye! I talked to Matt Flatt before he did Rhombus, I was aware of that, but not of cwp, thank you for pointing me to it.

whilo 2026-03-11T18:16:40.164079Z

I am not sure about macros without parens, this seems to be the most challenging bit in Rhombus and I bet it is less obvious than Clojure's how to write them. I think at that point the parens pay off.

whilo 2026-03-11T18:20:26.663649Z

I still think it would be good if people would learn to write code with the parens and did not want to go down the road of Dylan, M-expressions etc., which all did not work out. That is why I opted for it to be a bidirectional renderer instead of a language to write in. In your experience, would people still not be willing to learn it then? Maybe not. Because of the indentation cwp looks cleaner than superficie maybe, but I also still need to figure out what it is doing right now, I think the let bindings and assignments with := in superficie are actually better.

jeaye 2026-03-11T18:24:20.424449Z

I am interested, and heavily invested, in the idea of selling Clojure to existing native developers (C and C++, mainly). Not requiring them to re-learn how to edit text would be an enormous mechanical win, for the learning curve. Also, appealing to mainstream Pythonic aesthetics is not to be undervalued. In fact, it could be one of Clojure's biggest strengths. Yes, a lot of s-expr fans will curdle at the thought, but I place more value in Clojure succeeding than in pure philosophical roots. After all, it's meant to be a practical lisp. Wouldn't the most practical lisp meet people where they are?

whilo 2026-03-11T18:34:42.399869Z

Right, Julia kind of did this. This is also why I opted for its syntax with blocks delimited by end. I agree, but I think also that there are genuine trade-offs between familiarity and optimal syntax. There is a reason that Lisp-like syntax is used internally by many systems to express code, e.g. inside of gcc passes. Lisp has a meta-syntax that first can leverage a trivial parser that is available (or easy to code) in any environment by parsing lists. Inside this parsed s-exp language then special forms get a meaning and the grammar definition is much easier through macros. If you compare Clojure's reader to any non-Lisp language and the complexity of a parser with its grammar (including superficie) then the cost of inlining this list meta-syntax into a specific form becomes obvious. You throw away a lot of structure to be able to have shorthands for the lower-level special forms and grammar. This is at least how I think about it and why I think there is an irreducible loss, even in Julia (because its parser is still non-trivial in comparison to Clojure's). Having said all this if you can provide a bidirectional mapping (like superficie almost does), then it could be acceptable to write in this language first and maybe even ship some code. I just think there is a high risk this is a slippery slope towards accommodating Python more than winning people over to Lisp. I agree with your goals and am more than happy to keep discussing this though. I also agree that this would be the biggest unblocking for Clojure's (or Lisps) success.

jeaye 2026-03-11T18:41:41.074969Z

Yep, great points. Lisp is used internally, as you said, which makes a lot of sense. But Clojure devs use lisp more externally, which then hinders its adoption. I am a big fan of "Why not both?". Previously, you could have native, or you could have Clojure. Why not both? Previously, you could have Python-like syntax, or you could have Clojure. Why not both? Figuring out the details of bridging two worlds is not easy. But, for the native case, it's definitely doable. I suspect, with great optimism, that for the Pythonic syntax case, it's also definitely doable. This is where the tooling comes in. s-exprs are great for working with your code's parse tree. But if Superficie can map (nearly) 1:1, then why can't we have the same tooling behavior for that syntax? We should be able to slurp, barf, wrap, unwrap, etc. all using the Pythonic syntax. If we can do this, and we can eval forms with a REPL client, then we can have everything we love from Clojure in a different syntax.

jeaye 2026-03-11T18:42:28.856239Z

> I just think there is a high risk this is a slippery slope towards accommodating Python more than winning people over to Lisp. Fair consideration. Clojure needs to continue to be Clojure.

whilo 2026-03-11T18:43:41.199689Z

Superficie has a s-exp fallback where it passes through macros in Lisp form for instance. So you will have to be willing to learn Clojure eventually. At the moment it is also doing this for reader conditioned forms (can be solved probably) and some other edge cases.

jeaye 2026-03-11T18:44:14.300219Z

Yeah. It would be needed for macro writing, too.

jeaye 2026-03-11T18:44:47.396989Z

So, again, like GCC, we can use s-exprs internally. We don't need to hide that.

whilo 2026-03-11T18:45:55.597379Z

Do you know why cwp did not take off/stopped?

jeaye 2026-03-11T18:45:58.007129Z

But the bulk of Clojure code written by these new Clojure devs could be Pythonic. And we could even hook this transformer into documentation websites, so you get to choose which syntax you want to see.

whilo 2026-03-11T18:47:21.861619Z

Yes, the dual documentation is definitely also my goal. I want my projects to be generally accessible and not immediately lose people with the parens on my websites/READMEs etc.

jeaye 2026-03-11T18:47:47.294999Z

No, I don't have any details on CWP. I suspect that part of the reason it didn't take off is because it didn't have enough weight behind it at the correct time, but there may also be some technical reasons with its approach.

whilo 2026-03-11T18:48:38.205529Z

One thing I would point out is that LLMs have become very good at writing decent code and I write a lot less code directly these days, which in my mind should also make it a lot easier to learn Clojure through that angle. Not everybody will want to work like this, but the trend will significantly amplify over the near term.

jeaye 2026-03-11T18:50:44.207329Z

I think that CWP keeps a manual list of fns to make infix, which is a limiting factor.

whilo 2026-03-11T18:53:12.170479Z

I have built Julia's typed multiple dispatch and optionally also compile a subset of Clojure to OpenCL now directly, including a large scientific/deep learning standard library, games etc. that matches/beats sota native code in benchmarks (Julia's ODE solvers, jax deep learning code). I could build this compiler with Claude (I still have to clean it up though, which is a chore with LLM code, but I could not have typed nearly as fast and tried out all the compilation APIs and figure out all the details etc. in two weeks). I think it is still valuable to be able to show readable code, but it might be less pressing to let people program in it directly. This is just a guess from how things are going.

whilo 2026-03-11T18:55:28.290709Z

This is a tangent to this topic, but a reason for me to build superficie, because I still need to show the code (I tested rendering also my special typed dispatch forms with it, and it works ok).

whilo 2026-03-11T18:56:03.729549Z

I know this is a heated topic, but I think it is important to very seriously reflect on it these days.

jeaye 2026-03-11T18:57:49.030899Z

With or without LLMs, people still have aesthetic prejudices. I think this is still a very useful road to travel.

whilo 2026-03-11T18:58:11.308639Z

I completely agree.

whilo 2026-03-11T18:59:03.408649Z

I am just saying that this eases the necessity to primarily work in cwp/superficie, to being to show the code in its syntax while letting the LLM do the editing in Clojure.

whilo 2026-03-11T18:59:51.824659Z

It is still desirable to get a clean complete mapping that can be used for programming though, just less pressing.

whilo 2026-03-11T19:00:00.097649Z

This was just not possible in the past.

jeaye 2026-03-11T19:04:42.750609Z

The work you're doing on Superficie, including that last 2%, can lead us to a light specification for how to map Clojure to/from Pythonic Clojure (still need a name for this). With this specification, we can then have various tool and dialect authors decide whether or not they want to support this, with your implementation acting as a tool, library, and reference for those who want it. We can then figure out what the file extension difference should be, how to handle this on documentation websites, etc. I can say that for jank, I am very interested in supporting this syntax and even leading with it. Is this a direction you're interested in going? If not, that's ok! Don't let me hijack your fun. I will end up going there myself later.

whilo 2026-03-11T19:08:27.643969Z

I am interested in getting Clojure out of its corner, because it also limits what I will be able to do, in particular in the direction of scientific computing/research, even if LLMs write the code. Maybe cwp is better than superficie, I need to take a closer look, it is true that Python is just the gold standard for people's readability in general (although I know mathematicians that did not get it and preferred Julia).

whilo 2026-03-11T19:09:26.025489Z

I just don't want to have to build an insane amount of parser infrastructure, tooling etc., but then again LLMs make this considerably easier (even if still somewhat messy, but Clojure helps a lot in reducing the messiness).

whilo 2026-03-11T19:11:11.673009Z

@ilevd tagging you here if you are around πŸ™‚

jeaye 2026-03-11T19:12:13.910219Z

@borkdude Let me know if you have thoughts on this. If it's something we can get behind together, I'm confident we can make it happen.

whilo 2026-03-11T19:12:49.085959Z

@jeaye also happy to discuss the multiple dispatch work, I will move this to private to not spam it here.

jeaye 2026-03-11T19:16:12.591669Z

I've made #noparens to discuss this (name credit goes to Christian). All are welcome to join.

❀️ 1