HN user

swannodette

12,586 karma

Staff Software Engineer at https://lightweightlabs.com. Java, JavaScript, Clojure, ClojureScript mostly, but a language geek at heart.

https://convivivialcomputing.net

Posts255
Comments1,087
View on HN
www.vatican.va 5mo ago

Preserving Human Voices and Faces

swannodette
2pts0
stonetools.ghost.io 10mo ago

"Stone Tools"

swannodette
3pts0
github.com 1y ago

Fugato: Stateful Property Based Testing for Clojure(Script)

swannodette
9pts0
tech.redplanetlabs.com 5y ago

Tour of our 250k line Clojure codebase

swannodette
60pts2
vouch.io 5y ago

Developing mobile digital key applications with ClojureScript

swannodette
101pts12
tashian.com 6y ago

At Dynamicland, the Building Is the Computer

swannodette
132pts31
betweentwoparens.com 7y ago

Deploy ClojureScript to GitHub Pages

swannodette
3pts0
jacobinmag.com 8y ago

Tech Workers vs. The Pentagon

swannodette
3pts0
nono.ma 8y ago

Suggestive Drawing Among Humans and AIs

swannodette
124pts25
clojurescript.org 9y ago

ClojureScript Is Not An Island: Integrating Node Modules

swannodette
193pts42
mooistudios.com 9y ago

Choosing Functional Programming for Our Game

swannodette
161pts76
distill.pub 9y ago

Experiments in Handwriting with a Neural Network

swannodette
109pts15
medium.com 9y ago

Stop Pushing Pixels

swannodette
2pts0
medium.com 9y ago

Disrupting design interns, comps, and redlines

swannodette
3pts0
untangled-web.github.io 10y ago

Untangled: A ClojureScript-Based Webapp Framework

swannodette
45pts6
www.youtube.com 10y ago

AlphaGo and the Future of Computer Games: Conversation at U. of Alberta [video]

swannodette
53pts9
www.youtube.com 10y ago

Pro Analysis of Fan Hui vs. AlphaGo Match

swannodette
2pts0
medium.com 10y ago

RxJS is great. So why have I moved on?

swannodette
82pts37
www.pitheringabout.com 11y ago

Clojure at a Real Estate Portal

swannodette
10pts1
github.com 11y ago

Lisp implemented in under 1K of JavaScript

swannodette
108pts16
www.braveclojure.com 11y ago

Master Concurrent Processes with core.async

swannodette
131pts17
robert.kra.hn 11y ago

Programming Clojure, Smalltalk Style

swannodette
122pts26
open.bekk.no 11y ago

Easier UI Reasoning with Unidirectional Dataflow and Immutable Data

swannodette
7pts1
blogs.oracle.com 11y ago

Nashorn Architecture and Performance Improvements in Upcoming Release

swannodette
46pts8
www.jayway.com 11y ago

Comparing Core.async and Rx by Example

swannodette
5pts0
cognitect.github.io 12y ago

A Tour of Transit

swannodette
3pts0
alarmingdevelopment.org 12y ago

Developer inequality and the technical debt crisis

swannodette
114pts103
cacm.acm.org 12y ago

Those Who Say Code Does Not Matter

swannodette
266pts265
debug.elm-lang.org 12y ago

Elm's Time Traveling Debugger

swannodette
6pts0
swannodette.github.io 12y ago

The Future of JavaScript MVCs

swannodette
564pts156

Honestly what's mostly at the forefront of my mind is greatly improving the documentation around ClojureScript as well as our fork of Google Closure Library (GCL). At work we've switched to DataStar (a single JS include) and coupled that with ClojureScript/GCL - we no longer rely on anything from NPM, to call this a simplification would be a gross understatement. Bundle size is 30K gzipped and we spend no time thinking about our build or JS tooling/dependency tomfoolery.

So less about ClojureScript specifically, and more generally how I think we're well situated for people looking for a way out. The current mainstream practice dead end is bigger than the one that made React (also originally just a script tag include) appealing to me back in 2013. There are of course many ways forward that don't involve CLJS, but I think ClojureScript/GCL and the new crop of NPM-dep free pure CLJS solutions like Replicant are well situated for folks who can see that accepted practices are not delivering enough value even with AI assistance.

Offpunk 3.0 5 months ago

I don't think Gnus is that bad once you spend some time setting it up. For groups with a ton of content where I mostly want to search, I found it was better to just download the whole group and index into notmuch. I could query 20 years of the Smalltalk USENET group or the Supercollider mailing list instantly.

WASM and the performance seems catastrophically bad (45ms to render a frame on an M4 laptop)? It would be much more impressive if Claude could optimize it into something that someone would actually want to play? Compare this to a random hit from Google, https://jsnes.org/ which has sound, much smaller payload, and runs really fast (<1ms to render a frame).

The cost of slop is >40X drop in performance? Pick any metric that you care about for your domain perhaps that's what you're going to lose and is the effort to recover that practical with current vibe-coding strategies?

One Handed Keyboard 8 months ago

Some research on this topic http://edgarmatias.com/papers/hci96/

On OS X you can achieve this with Keyb, Karabiner Elements, etc. It's also easy to do with a programmable keyboard with ZMK/QMK. I've set up my Kinesis 360 Pro this way, being symmetrical means I can access every key easily. Hardware support for sticky keys also helps quite a bit.

I don't see how anything about what's presented here that refutes such claims. This mostly confirms that LLM based approaches need some serious baby-sitting from experts and those experts can derive some value from them but generally with non-trivial levels of effort and non-LLM supported thinking.

Learn to play Go 10 months ago

Blitz format is reasonably popular on KGS (once you get to a certain level) usually 10+0. Blitz is harder to find on Pandanet - but you can easily blitz on Fox.

Yes! Recent personal hacks with advice interactively programmed with the help of Claude 4.1 chat session running in Emacs.

  - popping the global mark to travel backwards to previous edit points would reuse the same Emacs window instead of using a window that is already showing the buffer. Fixed
  - I would accidentally destroy my window configuration w/ C-x 1. Fixed, use advice to automatically save the window configuration into a register if I invoke the command to remove all other windows. Now I can easily recover if I make that mistake.
  - I want to be able to select and then scroll any other open window w/o leaving the current one. Fixed
  - A crazy one. I collect note w/ links or whatever for reading/watching later, these are marked w/ a timestamp. My notes file is not an agenda file, i.e. not filled with todos / tasks. I made a hack to temporarily include the current non-agenda org-mode buffer in the agenda list and then show inactive timestamps. Now I can scan a day/week/month for interesting notes I took. This doesn't interact at all with my real agenda.
  - org-agenda opens items in weird places, use advice to fix it so that it always appears where I like.
  - fix inf-clojure so that it uses dep.edn as project root over .git
I used IntelliJ happily for 10 years (I was a heavy Emacs user for 10 years before that). While it's true that some things are a little less convenient (I don't use LSP), knowing that I can tailor things exactly to my tastes is a serious breath of fresh air.

It used to be I mostly used IntelliJ for work/OSS and Emacs for org-mode. Now the situation is likely reversed. Emacs for work/OSS and IntelliJ only if I need step debugging/global refactoring.

Yes. gptel supports two output modes out of the box, markdown (meh), and org-mode. I make an org-mode heading with my question, then I press `C-c <enter>`. Claude will use the area bellow the heading for its answer. It will make sub-headings, code blocks, lists, tables, etc. If I have another question then I make a new top level org-mode heading.

I started doing this because I got fed-up with Claude Desktop for my StackOverflow style programming questions - and then stumbled upon using it to configure Emacs.

  > My experience extending a core emacs function was an instructive and 
  > interesting exercise. I don't know what the future of emacs looks like in an
  > increasingly LLM-crazed world, but I hope that future  includes an open and
  > powerful way to extend and customize the tools we use to write software.
I have gptel configured with Claude 4.1 via API. Claude generates an org-mode file. I ask it questions about Emacs packages, Emacs configuration, and Emacs customization. It responds w/ Elisp snippets that I can eval immediately and see the effect. Claude knows a lot about Emacs. All these chats are version controlled into git so I can easily pull, consult-ripgrep, and pickup where I left off from any of my machines.

I can add my `.emacs` to the Claude context to get more precise answers. If it falls over on some package I can `M-x find-library` to add that library's source to the context. If the code it wrote doesn't work, I add the `Messages` buffer and the `Backtrace` buffer for errors. I eval the snippet, reprompt, rinse and repeat.

With this fast feedback loop (no restarting Emacs, just live coding), I've added a ton of customizations that in my twenty years of using Emacs previously just never felt like I had the time or enthusiasm for given higher priorities:

* Boring stuff: managing where modes open buffers in which windows

* More ambitious stuff: standard org-remark behavior isn't that natural for highlighting and making notes so I made a nicer Transient based thing for it.

* Stuff for work: a fast logging minor mode that font locks incrementally, disables all the save prompting, and handles ASCII color codes. Later I intend to linkify stack traces, linkify data so that they open pretty printed in a different buffer, collect errors and show an unobtrusive notification in the active window, etc. etc.

In two weeks, I've learned more Emacs than I did the 10 years prior. Most of all, this is a usage of LLMs that I can say I honestly love - improving my own day-to-day tools. Because Emacs is a text-oriented live programming environment - LLM integration just feels like it's on a completely different level.

Claude (or any good LLM) + Emacs is a killer app.

I have 2 Sailor Pro Gear Slims 14K and one Sailor Pro Gear 21K. The later is the best writing experience. I'm not an ink maniac but I tried a few and I found that Sailor inks tend to dry reasonably quickly while still having a good flow. Midori paper and Tomoe River both perform very well. If I'm going to do a whole page of writing smearing from hand moisture can be a problem, especially w/ non-Sailor inks so in that case I use the "today" cards you can get for the Hobonichi.

I’m left handed, with the right ink and paper this isn’t a huge problem. I picked up fountain pens a year ago and I will never go back to regular pens for my own writing.

We forked Google Closure Library. This is mostly a good thing as GCL started introducing frustrating breaking changes around 2018/2019. We've backed everything out and now ClojureScript libraries from 14 years ago work again.

I'm curious as to how you think this is different from say, committing to JavaScript/BundlerX/NPM or TypeScript/BundlerX/NPM? Surely those have an equally heavy influence on how you write code?

The implementation really is not built on top of GCL, the bulk of the standard library is persistent datastructure implementation and functional apis. The few cases here and there like `goog.string` can be removed over time. But really what's the rush? Large portions of GCL have worked unchanged for nearly two decades. Does Google archiving GCL make perfectly good code stop working?

When we eventually remove the direct GCL dependency it will sadly be more for optics than anything else.

I felt that way at first, but after getting around to listening to a few of them you start to realize he repurposed a lot his favorite material from these cantatas into his instrumental works. For example, one of Bach's innovations was the keyboard concerto - where the keyboard played the central solo role. The profound Harpsichord Concerto in D minor BWV 1052, https://www.youtube.com/watch?v=9ZX_XCYokQo, is actually reworked from the cantatas BWV 146 & 148.

While there's obviously plenty to enjoy w/o dipping into the cantatas, you might miss out on making these kinds of connections which I think really enriches our understanding of the instrumental works.

Organ pipe physics 3 years ago

Some scholars believe it to be an early work - possibly Bach was 19 years old. No copy in Bach's hand has ever been discovered, so there's no certainty. It is a wonderful, memorable piece of music but Bach was pretty good at that and not just at the keyboard.

To be fair there were definitely still bugs in Om as well as om.next (and both were marked as being experimental and of alpha quality) - however Fulcro came along and more less took the ideas and took them further and far as I know is actively maintained. I don't use it - but I suspect there was/is probably some kind of migration path.

Some technical points about Krell. It leverages the ClojureScript `:bundle` target which was released last year https://clojurescript.org/news/2020-04-24-bundle-target. By simply producing output that is JS bundler friendly we can just piggieback on Facebook's Metro just like we piggieback on Webpack etc. when targeting the web.

We simply reuse the debug loader provided by Google Closure and load ClojureScript and Google Closure JavaScript files through the Metro server. But this is the core of ClojureScript's hot-reloading capabilities without caveats. In Google Closure namespaces can be represented as nested JavaScript objects which delivers pervasive late-binding - which simply cannot be done with ES6 modules because imports will be captured (early bound).

The REPL bit (which is an independent piece from the hot-reloader) just runs on top of react-native-tcp-socket.

The only tricky part is that we need to be able to require Node libraries and assets into ClojureScript during development. This is done by a compiler pass - first we start at the entry point of the ClojureScript React Native project and follow the dep graph collecting all libraries required from `node_modules`. This is dumped to a file that is required transitively by `index.js`.

Asset handling is done as a simple compiler pass over every AST node searching for JavaScript `require` statements in the ClojureScript.

The end result is that we have an extremely rapid development workflow that simply is not possible with other existing technologies - not React Native, not Flutter, not SwiftUI. All of our apps are built via live-coding from our text editor of choice + REPL (either embedded in IDE or via shell).

Happy to answer any further questions!

Mostly a maintenance release, but the and/or compiler pass thing is somewhat neat. First, it might seem that such an optimization would not be that useful, but actually it's one of the most critical ones - we want to write the persistent data structure code in a language idiomatic way yet know that performance sensitive JavaScript code will be generated.

Here's the problem.

In Clojure `and` and `or` are just macros that expand to `let` + `if`, simple and elegant:

    (defmacro and
      ([] true)
      ([x] x)
      ([x & next]
       `(let [and# ~x]
          (if and# (and ~@next) and#))))
... except when you target JavaScript - which is not an expression oriented language. So `let` will be wrapped in an immediately invoked function expression (IIFE). Google Closure does elide these when it can, but it will give up after only a few levels of nesting. For an IIFE to appear in the middle of a conditional is a performance killer.

Another complication is that it's not safe to just use `&&` and `||` blindly because of `0` and the empty string and the other cases which are not false-y in Clojure(Script). Checks for JavaScript false-y values are a performance killer.

So years ago we implemented a simple form of type inference which annotates the AST with type information as a compiler pass on every node when possible. As long we know the JavaScript `if` will receive a boolean value we can elide the JS false-y value check.

But this is also exactly the information we need to safely run a following pass that looks for the above and/or syntactical patterns and optimize it. As long as each nested `if` is guaranteed to return a boolean, we can remove the local and use `&&` or `||` instead.

The and/or optimization pass ended up being ~120 lines of code with no actual dependencies on anything else in the ClojureScript analyzer or compiler because the ClojureScript AST is just plain EDN - https://github.com/clojure/clojurescript/blob/master/src/mai...

Happy to answer any further questions about this!

UPDATE: Also ClojureScript turned 10 years old this month :)

Honestly not sure, I'm not a Webpack expert and have no wish to be :) But again, as I've said elsewhere, there is no specific integration with Webpack. The bundle feature makes no choices so it's easier for users to fully control the integration with any JS build tool.