> I think it's inspired by Clojure and Lua, and somehow manages to be better than both

This is exactly how I feel about Janet too. I don't think I have enough experience on Clojure or Lua to comment on them, but I got attracted to Janet almost immediately.

Working on Jwno also confirms my first impression on Janet: It's really a practical language. The tooling has some room for improvement, but the language itself can get things done - usually fast and easily.

Agreed on the need for better Janet tooling. I'm trying to be the change I wish to see with Janet LSP[0]. Issues and contributions are welcome!

[0] https://GitHub.com/CFiggers/janet-lsp

How’s the REPL/interactive editing story? I feel weird using a Lisp that is not as interactive as Racket, Scheme or Common Lisp. Running scripts from the REPL ain’t the same thing as C-x C-e an expression on a live program

> I feel weird using a Lisp that is not as interactive as Racket, Scheme or Common Lisp

I think Racket and Scheme don't belong in there because neither has a REPL as powerful and "interactive" as Common Lisp REPL. They don't support images either (but Janet and CL do).

As a Common Lisper with a Scheme background I'm gonna guess that by the interactivity of the REPL you mean the condition system with restarts? While most Schemes don't really have anything like it, I seem to recall MIT/GNU Scheme having something kinda similar. And I mean, hey, it's got Edwin, so it definitely has interactivity.

Yes, I mean the conditions and restarts system in CL. Haven't seen anything like that in Clojure and other Lisps.

Yeah, it's mind-blowing when it clicks, and makes the whole "exceptions vs. return types" discussion look like a quarrel of 3yos in a sand box. Error handling in other languages/runtimes just doesn't feel sufficient from now on.

This is, of course, just a part of a larger whole - the fact that your Common Lisp program ships with a compiler it can access and effectively always runs in an edit-and-go debugger. Embracing this fact fully leads to a different workflow of software development.

Having done a bit of that, I found plenty of drawbacks of this approach, too - mostly various consequences of breaking the assumption that code that a program is running is the same as the code it was compiled from or that it started with. The aspect that annoyed me the most day-to-day was, basically, that whenever I fixed something on the fly through conditions and restarts and eval-ing code in a REPL, I never had a nice way to go back to that solution and port it to code. It was too easy to forget about a quick fix you did without thinking.

I now realized this should be easily fixable with external tooling - i.e. in Emacs/SLIME. What I think they need is a better way of keeping an audit trail. Capturing and persisting as much of the transient interactions you did as possible, letting you revisit them after and easily transfer into code or tests.

> I now realized this should be easily fixable with external tooling - i.e. in Emacs/SLIME. What I think they need is a better way of keeping an audit trail. Capturing and persisting as much of the transient interactions you did as possible, letting you revisit them after and easily transfer into code or tests.

To some extent, undotree on neovim allows this because it offers a drastically different view on what "undo" means. But I agree with you, the lack of a git-like system is annoying. I even think this might be THE reason CL didn't catch on—companies want to keep track of things (hence all the dashboards and ticketing systems...).

That's the other thing. Version control is tricky with image-based systems. I won't say impossible, I never looked deeply into what Smalltalk/Pharo folks are doing, but since between playing with Pharo and Glamorous Toolkit I saw Git being integrated first-class into one of them, I imagine someone has some idea how to deal with the problem.

What I meant though isn't collaborative/historical tracking, I meant day-to-day ergonomics; closer to "drastically different view on what 'undo' means", except it doesn't even have to be 'undo' - I don't need the ability to rollback every single thing; I just want to know whatever the hell I actually did an hour ago when I quickly SET-VALUE and IGNOREd my way through a few random condition popups and evaluated some code in between. Being careful and keeping track of this as I go slows me down and is kind of the opposite of REPL-driven interactive development ideas; nah, I should be able to go fast now, and later be able to review all the random surgery I did on a live image.

EDIT:

> undotree on neovim allows this because it offers a drastically different view on what "undo" means

As I understand it, this "different view" is treating undo history as a tree? If so, I know this from Emacs via similarly named `undo-tree' package. But honestly, the moment I saw this I thought this is brain-dead stupid most obvious way of treating undos. It's very unfortunate that almost no software embraces this approach, instead opting for a linear history that gets trimmed the moment you undo a few steps and make a change.

If you want to see a truly different view of undo, check out what Emacs does by default. I don't even understand it fully, but best I can tell after studying the explainer in undo-tree's documentation, is that Emacs is using a linear history like everyone else, but instead of moving back through the history and discarding "the future" when you branch out, `undo' itself is an undoable operation that gets appended to undo history, so when you type some things, undo it, type something else, and keep pressing undo, you'll erase the last text, then "undo the undo" and end up with the first thing you typed...

> Version control is tricky with image-based systems

Back in the day:

"ENVY/Manager augments this model by providing configuration management and version control facilities. All code is stored in a central database rather than in files associated with a particular image. Developers are continuously connected to this database; therefore changes are immediately visible to all developers."

https://www.google.com/books/edition/Mastering_ENVY_Develope...

These days:

"Package files are simple text files, encoded for latin alphabet (ISO 8859-15) and handled without problems by GitHub. Cuis-Smalltalk uses the LF (ascii code 10) newline convention, as preferred in GitHub. This allows Git/GitHub to diff versions, and merge branches."

https://drcuis.github.io/TheCuisBook/Daily-Workflow.html

The "Back in the day" sounds better as a pattern in general.

> Yeah, it's mind-blowing when it clicks, and makes the whole "exceptions vs. return types" discussion look like a quarrel of 3yos in a sand box. Error handling in other languages/runtimes just doesn't feel sufficient from now on.

I am still waiting for a non-Lisp language with a half-decent restart system. Even compiled languages should be able to implement it (except dealing with a possible allocation failure when saving the register context to return to)

ditto jdougan

"Restart. Start execution of the current method from the beginning. You can edit a method shown in the code pane, save it, and restart it!"

https://drcuis.github.io/TheCuisBook/The-Debugger.html

Restarts in CLHS are blocks of code handling a condition (exception). CL splits the "catch exception" and "react to it" parts into handlers and restarts. The two are independent; a handler can choose any restart currently installed above it in the call stack, or ask the user to choose interactively; the stack is only unwinded up to the point of a restart to resume from. This means you could e.g. following call stack:

5. Code that signals a file read error

4. Code that installs restarts "re-read line" and "skip line"

3. Code that loops over files in line

2. Code that installs restart "re-read file" or "abort"

1. Code with the handler that intelligently chooses whether to resume from 4 by re-reading a line or skipping it, or resume from 2 by attempting to read the file again, or just bailing out.

What is the issue with the system in Smalltalks?

There's multiple dimensions you can slice and dice the Lisp family by. Images and REPL experience are two big ones, but they're almost orthogonal.

I didn't mean that Racket and Scheme aren't Lisp (they are!). I meant they don't have the images and REPL-driven development of Common Lisp.

If we're still calling Guile a Scheme (I'm out of the loop) then I don't know, it gets really bloody close. Not so much in image-based development (that I've usually found less good than a decent packaging system because the contents of my files on disk is usually more tractable than the contents of my image), but its object system and error handling are definitely up there close to CL.

I mean, Common Lisp is still the gold-standard for me, but reading about Hoot recently really made me want to check Guile out a bit more (CL does not have much in the way of lovely WASM stories right now) and, honestly, I was super impressed. I think if the interactive experience of developing in Hoot in the browser matched the interactive experience of developing in native Guile, I'd be a pretty happy convert.

Guile is certainly my favourite Scheme for standalone use.

This is how I feel about Janet too, absolutely practical. So far it's been a breeze to write the little experiments I've done so far.