HN user

mechanicum

193 karma

https://www.tomwaddington.dev/

Posts1
Comments62
View on HN

I've found LLMs to be bad at balancing parenthesis.

I think that was true last year. In my experience, it’s no longer the case with Claude Code or Codex.

Last year, I thought it was awful. Even Opus would reliably unbalance parentheses on practically every edit and then enter a doom spiral of making things worse as it tried to figure out the right place to put a `)`.

Recently, I’ve been quite impressed, at least with Claude. At some point they figured out the parens issue, and the code is largely solid and idiomatic. I’ve mostly used it with Polylith apps, so the context for any given change is naturally well-defined. Usual issues with failing to reuse existing functions or make sound decisions about architecture, but no more so than I’ve seen with TypeScript or Rust.

I think there are a few points in its favour: it’s a very concise language, the documentation is terse but precise and comprehensive, and while there’s obviously nowhere near as much Clojure out there as there is JavaScript or Python, there is a lot. As the Clojure demographic skews toward experienced, senior programmers, I’d guess the quality of that corpus is probably well above average.

Java stack trace errors might even be an advantage now.

I can believe it’s much improved and I wouldn’t look down on anyone for using it.

But it’s still never going to be a language I like, and I’m yet to encounter any of these modern codebases in the wild. It’s invariably a crusty old relic, much closer to the PHP of 2006 than the PHP of 2026.

Eh? That's completely lifted from CL.

Clojure’s abstraction is a bit more far-reaching than Common Lisp’s SEQUENCE, implemented as interfaces rather than types.

A Clojure sequence is anything “seqable” (either implements the Seqable interface, or special case handling for host platform collections), not just lists and vectors. Hash maps, sets, Java Iterables, etc. are all seqable and work with the same standard collection functions.

e.g. you can `(map (fn [[k v]] …) {:a 1 :b 2})`, rather than needing a separate MAPHASH function.

Short answer: “a type system centered on the use of set-theoretic types (unions, intersections, negations) that satisfy the commutativity and distributivity properties of the corresponding set-theoretic operations”.

Long answer, well, there are blog posts[0], the Design Principles of the Elixir Type System paper[1] and related presentations[2, 3, 4] that talk about it at length. Giuseppe Castagna’s site has many more related papers: https://www.irif.fr/~gc/topics.en.html

[0] https://elixir-lang.org/blog/2022/10/05/my-future-with-elixi...

[1] https://www.irif.fr/~gc/papers/elixir-type-design.pdf

[2] https://www.youtube.com/watch?v=gJJH7a2J9O8

[3] https://www.youtube.com/watch?v=VYmo867YF6g

[4] https://www.youtube.com/watch?v=giYbq4HmfGA

The vi family 2 months ago

I think describing Kakoune/Helix as vi-inspired with “slightly different keybindings” is rather missing the point.

The most important difference is that they invert the editing model from verb-noun to noun-verb. Meaning you always see exactly what you’re going to be operating on before you do it.

The second most important difference is that they were designed from the ground up around multi-selection editing as a primitive, rather than a plugin or late addition.

That model is typically less efficient purely in terms of keystrokes, for some operations significantly so, but it’s somewhat mitigated if having the state on-screen rather than in your head means you undo less often.

I wouldn’t suggest either approach is superior. I suspect most people (“most people” in the subset of people who jibe with modal editing to begin with, anyway) will find that one just fits their brain better than the other.

Personally, even having used Vim almost daily since finding it on a Fish Disk sometime in the mid-90s, I still turned out to be in the kak/hx group. I can still use vi quite comfortably when I need to, but Helix removed a bit of friction I’d barely been aware of.

There’s a steady stream of NeoVim exiles to Helix forums, I think who mostly found its Lua-based config too complex/brittle, asking why the devs don’t add settings to make it work like Vim, include a *Vim keymap as standard, etc.

It’s kind of wild to me that people would choose their editor based on how minimalist its config/how batteries-included it is, rather than its fundamental editing paradigm.

Last week I actually did dig out my UK launch PSP-1000 from 2005 (a gift from Games Workshop for being Design Studio Employee of the Year, I think to the bafflement of almost everyone in the department, not least me – at the time, I was the bloke who kept the websites running, after most of the US-based team had left on 2 weeks’ notice in March).

Not out of any particular nostalgia for the device itself, nor because I’ve seen anyone else with one. I just had a sudden hankering to play a Ridge Racer, and it turned out my PS3 is stuck in some kind of update loop.

I was pleasantly surprised by how well it’s held up. And by that, I mean this specific unit: over 20 years old, left in the back of a drawer for at least the last 10, but seemingly as good as new. The screen is obviously a bit dim by modern standards, but the battery still holds a charge for hours. If I treated a smartphone like that, I’d be afraid of it swelling to the size of a football and setting fire to the building.

By contrast, the DS Lite I found in the same drawer no longer recognises anything in either cartridge slot and the screens have developed a brownish gradient running top to bottom, although the clock had only drifted by ~40 minutes.

For me, that era of portable gaming coincided with a lot of travel for work, holidays, gigs and music festivals. I’ve probably spent more time playing games on those two consoles than I have on every mobile device released before or since put together.

It’ll probably end up back in the drawer sooner rather than later, but I had a fun Saturday evening working my way through a shoebox of UMDs, checking out save files mostly timestamped 2006-2008. And maybe I’ll finish another run through Jeanne d’Arc first.

It’s trivially easy to do in Clojure (literally one line of code to start an nREPL server, after deps/requires), and often very useful in dev and personal, local projects. In practice, I’ve never once used it in a user-facing production system, in 16 years of writing Clojure.

Out of the box, there’s zero security or audit trail. Building that properly isn’t trivial and, even with it in place, many corporate infosec teams would have fits if you suggested that engineers can make arbitrary inspections/modifications to a running production system.

Where it could be appropriate, often you’re running the code in autoscaling containers or something similar. Modifying one instance then is rarely anything but a terrible idea.

Where I have used it is for things like long-running internal batch systems that run a single instance and never touch any sensitive data. Connecting a REPL in those cases is much more flexible and powerful than, say, building a dashboard UI or a control API over http, and you get it for free.

These have been available since mid-2022:

  :insert-output Run shell command, inserting output before each selection.
  :append-output Run shell command, appending output after each selection.
  :pipe, :| Pipe each selection to the shell command.
  :pipe-to Pipe each selection to the shell command, ignoring output.
  :run-shell-command, :sh, :! Run a shell command
The placeholder for the current file is %{buffer_name} (not as bad as it looks, the command line has tab completion for basically everything).

Cmd + click places multiple carets on macOS. Apparently – I never touch the mouse when I’m editing in Helix. I don’t know which modifier it is on other platforms.

I’m not sure if replicating Sublime’s Ctrl + D is possible or not, but there are other ways to achieve every use case for it I can immediately think of. e.g. I think I’d typically be doing `<space>h` to select every instance of the symbol under the cursor, or using `s`elect to reduce a selection to a match, possibly yanked and pasted.

I don’t think so, no. This is how it works today: https://www.gov.uk/check-job-applicant-right-to-work

If your new hire is a British or Irish citizen, you ask for their passport on their first day and retain a photo/scan. In most cases this means that a layperson has to verify that the (possibly foreign) document is genuine, but I don’t think fake passports are a statistically meaningful problem.

If they have a visa or, probably most likely in recent years, EU right to remain, they will have a share code for online verification. That takes you to a page with their details and a passport-style photo that you can download as PDF for your records.

Identifying whether someone has the right to work has never been a problem. If somebody is working illegally, it’s because the employer is either knowingly employing them illegally, or doesn’t care/bother to check (or even know that they’re legally required to do so – a perennial problem with early stage startups in London, in my experience).

iTerm2 Web Browser 10 months ago

You can have that. Cmd-Opt-Shift-V or H to split with a different profile, or use the move/swap options in the context menu to put any panes in the same tab after creation.

I know. My question is, isn’t the reason the command line tools work the way they do simply that they’re essentially the BSD programs (give or take an Apple patch), with BSD options, not because they needed to work that way for Apple to get the OS certified?

Even if macOS wasn’t UNIX-certified, Apple would still be unwilling/unable to include the GNU software due to the license. I can’t see the Apple of today implementing a full suite of non-GNU software but with GNU-style options either.

So, POSIX compliant or not, there’s probably no world where `grep -P` works out of the box on a Mac.

because macOS is adhering to the UNIX specification

Isn’t it rather that Darwin was based on BSD 4.4? I’d imagine GPL 3.0 is a bigger impediment to them ever migrating to GNU tools than any desire to be UNIX certified.

The % register contains the path for the current buffer, you can insert that into prompt commands with <C-r>%. <C-w> at the command prompt deletes the last word, which in this case will be the filename of the current buffer, leaving the directory path.

So:

:o <C-r>%<C-w>new-filename<ret>

Would open a new buffer at /path/to/the/previous/buffer/new-filename. The file isn’t created on disk until you explicitly write, so :w! to save the first time.

If you literally just wanted to create a new file instead of opening a buffer, you could do that from inside Helix with :run-shell-command (aliases sh or !) instead of another terminal:

:sh touch <C-r>%<C-w>new-filename<ret>

The :o method has the advantage of LSP integration. For example, when I create a new .clj file that way in a Clojure project, the new buffer is pre-populated with the appropriate (ns) form, preselected for easy deletion if I didn’t want it.

It’s about hand movement, not desk space.

The “missing” keys are on additional layers reached via a modifier key, or by overloading keys on tap/hold, or by increasingly esoteric methods the smaller the board gets: chording, tap dance, etc. They’re typically no less accessible than capital letters, while allowing you to keep your fingers on the home row.

For me, the additional keys on my larger keyboards rarely prove useful in practice. I end up mostly using the same subset available on the 60% I’m typing on now – it’s quicker and more comfortable than reaching over to the dedicated key.

It’s common niggle but, as far as I know, nobody is sure of the precise rationale for placing every key, only the broad explanations of the layout that Dvorak published and promoted. The layout wasn’t based only on letter frequency but they attempted to account also for bigram frequency, frequency of repetition within words, frequency with which words are used, and with an objective of rhythmic alternation between hands.

Consider also that it was developed in the 20s and 30s. Nowadays you could throw some moderately hefty compute at almost everything of note written in the English language and come back to an error-free analysis after lunch, but who knows how representative was the corpus they analysed, painstakingly and manually. It might have made perfect sense with their data set.

Ultimately, the English language didn’t evolve to be easy to type, there will always be compromises somewhere, and the English of today isn’t the English of a century ago anyway. I imagine you’d get quite a different layout if you based it on Gen Z text messages or something.

Personally, I can’t help but note that Dvorak’s first name was August.

I’m curious what led to that conclusion. As far as I remember, making concurrency easier to manage was always presented as one of Clojure’s primary objectives. It’s fundamental to the design e.g. a major motivation for all core data structures being immutable.

STM, atoms and agents were there from the beginning. I think futures and promises were added in 1.1. core.async is from 2013. Even popular third-party libraries like promesa and manifold are around 10 years old at this point.

I think flow promises to make it easier to orchestrate core.async, specifically, in complex applications, but the essential primitives are far from new and I don’t consider them any harder to use than JavaScript.

Caligra Workbench 12 months ago

On that page they have Cmd + Esc mapped as the shortcut for the global system menu (see “Teleport”), and it looks like the CEO is a NeoVim user[0].

I guess they anticipate users hitting escape a lot. Making it a large target doesn’t strike me as a worse use of the space than dividing function keys into blocks of 4, and more likely to be intentional than an artefact of generative AI.

[0] https://www.linkedin.com/feed/update/urn:li:activity:7353029...

I don’t think that necessarily follows. The age of the surviving fragments today isn’t the whole story.

We could presumably infer it still wasn’t “missing” as recently as a thousand years ago from later sources referring to it, even if the specific text (or oral tradition) those authors knew of hasn’t survived.

Like how we know about some of now lost Greek plays, originally written in the 5th century BC, because they were still being performed in Imperial Rome and writers of that time described them, even the details of how they were staged.