
Janet: a lightweight, expressive and modern Lisp - galfarragem
https://janet-lang.org
======
ristos
This looks so awesome! It's got the best parts of a lot of languages. This is
what sticks out to me:

\- Really simple lisp like scheme, but reminds me of lua (and not bloated like
CL)

\- Has resumable fibers, no callcc like scheme

\- Not missing the lack of lists tbh

\- A module system that doesn't feel awkward like CL

\- A built-in package manager (unlike CL)

\- Good lua and C support

\- Threads have a shared-nothing approach with message passing (reminds me of
Erlang actors)

\- Destructuring

\- Good PEG support, encourages it over regex

\- (Im)mutable versions of data structures (ie tuples vs arrays, structs vs
tables) for maximum flexibility

\- Prototypal inheritance

\- Docs are clean and easy to read

I'll definitely have to try this out, it looks really cool.

Some stuff I'd like to see:

\- Pattern matching support (could be a library I guess)

\- Multimethods

\- Full numeric tower with arbitrary precision types

\- Javascript compilation -- I could see this language being really useful for
web and game dev

Does it have good debugging support? I'm thinking of something like slime,
swank, etc. Can I set up emacs and/or vim to work the same way I can use CL
with slime + swank?

I'm also wondering about the stack traces -- one of the downsides to CL is
sometimes the stack traces are nasty to read

~~~
armitron
I never thought I'd see a Lisp without lists. Oh wait, I didn't because this
isn't a Lisp.

I know naming is hard, but this is getting out of hand. Don't say you're a
Lisp when you're clearly not. Say Lisp-inspired. Don't use the term 'modern
Lisp', 9/10 it's signaling the wrong thing.

~~~
MaysonL
From the examples:

# A simple fizz buzz example

(loop [i :range [1 101] :let [fizz (zero? (% i 3)) buzz (zero? (% i 5))]]
(print (cond (and fizz buzz) "fizzbuzz" fizz "fizz" buzz "buzz" i)))

Is this not lisp?

~~~
nonbirithm
I'm not clear on the exact reasons, but I think some people see it as "Python
with S-expressions" rather than "Lisp". I think it's because Janet does not
use lists implemented with cons cells and historically that's just what Lisp
always used. (Janet uses arrays instead.) But by that logic Clojure isn't a
Lisp, if has no cons cells...

Another criteria used is homoiconicity.

I think the argument is about if a language satisfies the historical
definition of "Lisp" rathen than being a Lisp-inspired language with parens.

~~~
oalae5niMiel7qu
A good reason to regard this as "Python with parentheses" is because not only
does it use arrays instead of cons cells, but there's no non-mutating `append`
function. Instead, Janet has an `array/concat` function that behaves like a
Python array's `.append` method, and that's it.

And no, Clojure isn't a Lisp. Perhaps it would be appropriate to say that
Janet is "a Clojure".

------
kleiba
Okay, so when Clojure came along, it came with a strong underlying philosophy
of what the language was supposed to be/do. Among them were design decisions
such as, e.g.,:

    
    
      - VMs, not OSes, are the platforms of the future, so target the JVM
      - Object Orientation is overrated, but polymorphism is a good thing
      - Multi-core is here to stay, so use immutable data structures to greatly facilitate writing correct concurrent programs
      - Leverage the strengths of LISP but give it a modern overhaul (most notably, throw in different parenthesis)
    

Now, you may or may not subscribe to any of these but my question is just: how
does Janet compete on that front? What is the problem it is trying to address
specifically? I looked at the web page a bit but it's still not clear to me.

~~~
galfarragem
What I like in Janet (I'm just a noob so take this comment with a grain of
salt as it will sound superficial):

\- Easy to get started: one click install, great website and concise docs. No
matter what some people say, getting started in Clojure is a nightmare.

\- Lightweight and fresh. No JVM, no Node.

\- Freedom and expressivity. Mutable or immutable data structures, ultimately
is up to me. It might bite me down the road but for now it feels great.

~~~
adamkl
I've posted this quote before, but it might help explain why making Clojure
easier to get into maybe hasn't been a priority for Hickey et al.

 _So we need players. I would rant here, but I won 't. But look at this guitar
player with blisters. A harpist has blisters, a base player with blisters.
There's this barrier to overcome for every musician. Imagine if you downloaded
something from GitHub and it gave you blisters._ \- Rich Hickey (Design,
Composition and Performance)

Clojure seems more concerned with power, expressiveness, and reach, rather
than ease of use. Does this alienate new users, sure, but the Clojure
community seems OK with that as a trade-off.

~~~
rfrey
I am full to my neckline with Clojure kool-aid: I love the language and
programming experience. But the "getting started" your parent is referring to,
IMO, is getting the tooling set up, getting the repls connected, figuring out
what a full-stack app looks like with its 2 distinct repls and toolchains and
lein config mashups, hooking up an editor... and then having it break the next
day. After 5 years of Clojure I still get frustrated if I'm away for more than
a month.

It's like you were getting blisters from _stringing_ your guitar. You buy a
guitar, get home, and it takes three days to open the case. Then another week
to figure out which strings go where. God help you when you realize you have
to _tune_ the thing.

Two, five, seven days pass and you haven't played a note. I don't think that's
what Hickey meant.

That said, it's worth it.

~~~
tartoran
Spot on with your amusing guitar analogy. Getting to play notes seems like an
afterthought, but when it does it plays for you as if it reads your mind to do
so. The problem is the setup and that's the part that I dislike these days,
the patience to to configure the tools is not there, a lot of the tools are
like black boxes, something goes wrong and it isn't visible or or it is too
complex to enjoy the process.

------
emmanueloga_
I'd love to hear more from the author (can someone interview him for a podcast
please? :-). He also has another programming language called Fennel [1] which
compiles a lisp like language to Lua.

Both Fennel and Janet seem to orbit around Clojure ideas.... interestingly one
of Fennel's main contributors [2] is also the author of Clojure's most popular
build system, Leiningen.

1: [https://fennel-lang.org/](https://fennel-lang.org/)

2: [https://technomancy.us/186](https://technomancy.us/186)

~~~
aasasd
I kept thinking that in the ‘small scripting Lisp’ category, a startup-
time/performance comparison with Fennel would be apropos, as the latter is
blazingly fast and thus well suited for scripting in interactive contexts.

------
phoe-krk

        janet:1:> (cons 1 2)
        compile error: unknown symbol cons on line 1, column 1 while compiling repl
        janet:2:> (list 1 2)
        compile error: unknown symbol list on line 2, column 1 while compiling repl
        janet:3:> (vector 1 2)
        compile error: unknown symbol vector on line 3, column 1 while compiling repl
    

I certainly need to learn the basic idioms of this dialect; it looks nothing
like Common Lisp under the hood.

~~~
pjc50
Is it really Lisp without cons?

~~~
phoe-krk
Yes, it seems so. Try the REPL available at the website.

~~~
oblio
I wonder if his question was not rhetorical, as in: It is _really_ Lisp if it
doesn't have cons?

~~~
lispm
Is it really Lisp without 'lists'?

[https://janet-lang.org/api/index.html](https://janet-lang.org/api/index.html)

that does not mention list in meaningful ways. It seems to prefer to work with
other data structures (like arrays) - which is okay, but then I won't call it
a List Processor dialect.

~~~
jonathanstrange
I don't understand why somebody downvoted you, I've seen a number of languages
that look like Lisp, but are based on vectors or arrays, and that changes the
language drastically. So I'm wondering, too. I was trying to find out whether
Janet programs are lists or something else like arrays, but didn't find it in
the docs.

~~~
bakpakin
This does change the language drastically - source code is represented as
tuples usually, although all of the core data structures have literal forms.
This means writing macros is still easy, although certain idioms like consing
are usually replaced by splicing, which is like unquote-splicing in Common
Lisp but more general.

~~~
hexmiles
as someone who dosen't know the theory what is the difference between list and
array? consing and splicing?

is there a pratical difference in the way you write programs or is more of
theory/implemetation detail?

~~~
bakpakin
A list refers to a singly-linked list, while tuples are implemented as
immutable arrays. The former is flexible in that multiple lists can hare
structure, and prepending to a list is an O(1) operation that does not change
the original list (consing). This property allows all sorts of interesting
data structures which at their core are simply lists of atoms and other lists.

Janet on the other hand just uses tuples, which are easier to pack densely
into memory so usually have better cache performance on reads (clever lisp
implementations can sometimes can make lists fit densely in memory, but
usually they take about twice as much memory as a tuple).

splicing is the like the spread operator in JavaScript or the splat operator
in Ruby. This turns out to be very useful in a language without cons for
manipulating tuples in macros, even though it is not as efficient as a cons.

~~~
hexmiles
thank you!

------
pjc50
1) How is this different from other Lisps or Schemes?

2) When promoting a new programming language, _always_ provide a nontrivial
example. Couple of pages of code. Mandelbrot generator, desk calculator,
notekeeping app, that sort of thing.

~~~
augustk
And the motivation for designing the new language. What problems does it solve
better than existing languages? How does it promote the creation of
maintainable programs? Etc, etc.

~~~
phonebucket
> What problems does it solve better than existing languages? How does it
> promote the creation of maintainable programs?

I broadly agree that widespread adoption probably requires answering some sort
question like these.

But sometimes people create languages just because they are fun to create, and
they think other people might enjoy using them.

~~~
pjmlp
Just taking into consideration that most engineering degrees have of some of
compilers design course, there are thousands of programming languages born
every year across the globe.

So it needs more than just _" grammar + semantics + basic library"_ to
actually be relevant.

However that is how many nowadays mainstream languages have started, so luck
also plays a big role.

------
w0utert
Lisp languages should be great for embedding into games to implement game
logic, instead of more straightforward solutions such as embedding Lua. I've
always wanted to explore this for my iOS side-project game, which now uses an
event-based system inspired by ReactiveX, implemented in Lua. This works
pretty well but is very hard to debug.

The main thing holding me back to try to replace it with something Lisp-like
is that I have zero experience in Lisp programming. I know some FP theory (in
fact the Lua-based event system lends some concepts from it), but when I try
to reason about common subproblems I really have no idea how to map them to
something like Lisp. For example how to efficiently implement a message bus
with observers that can register themselves, using state-based functions to
execute when certain events are received, scheduling events, async/await to
suspend processing until some event is received, etc.

Does anyone have pointers to books or websites to learn 'real-world' LISP
programming? In other words not yet another introduction that shows the same
old forced examples that just show you how to evaluate an expression or use
higher-order functions to solve artificial toy problems, but resources that
teach you how to be productive in a Lisp language?

~~~
phoe-krk
> but when I try to reason about common subproblems I really have no idea how
> to map them to something like Lisp. For example how to efficiently implement
> a message bus with observers that can register for certain events.

I think that's a badly posed question. The main benefits of using Lisp are its
introspection and interactivity. You can use the REPL to inspect your message
bus at runtime, you can modify parts of it as it runs, you can interactively
debug errors as they happen, but none of that is directly related to "how to
_implement_ a message bus".

I think that is more of an ADS question that it is a Lisp question; an
efficient message bus, no matter whether you implement it in Lisp or in C or
in Haskell, needs some synchronization primitives from the programming
language core that are likely backed by OS primitives, as well as some data
structures that need to be cleverly designed to be fast. Neither of these is
language-specific - only means of implementing and using those might be
language-specific.

In other words: Lisp makes it possible to be more productive by means of
dramatically reducing the time of feedback loop and by means of providing in-
depth language introspection, but it doesn't solve the problem of actually
needing to figure out how to design programs and data structures. That's why
e.g. SICP is not a Scheme tutorial, despite using Scheme throughout the whole
book.

~~~
pjc50
This is a very classic Lisp answer in that "productivity" is considered in the
pure abstract, and that the specific question of how to do a specific thing -
the actual productive result - is uninteresting. Who would expect the classic
book on Scheme to teach you how to write Scheme programs?

~~~
phoe-krk
Regarding productivity, I don't consider it abstract. I feel a concrete
efficiency boost from the two things I mentioned, which are interactive and
incremental development with a very short feedback loop (no time wasted while
waiting for the toolchain to do its work) and the ability to introspect and
debug the live system (since I do not need to bother with external debugger
and tooling).

What exactly do you mean by "uninteresting"?

~~~
pjc50
The original post complains of not knowing how to solve their particular
problem in Lisp, and gives an example:

> how to efficiently implement a message bus with observers

You say:

> I think that's a badly posed question

But it isn't! It's the specific thing that person is trying to do and is
having trouble with, the act of translating structures and designs they
understand from other languages into the Lisp language.

This is the barrier to Lisp adoption. You can cite iterative development and
live debugging all you want, but they only benefit after you've actually
written a program, which is the barrier the potential users are struggling at.

~~~
phoe-krk
> but they only benefit after you've actually written a program, which is the
> barrier the potential users are struggling at

No, you miss the point. There is little benefit in interactive and incremental
development once a program is written. The very benefit that this such
incrementality provides is noticeable during the _process_ of writing the
program, not after it; when a program is written, it's written, and from some
point it doesn't really matter if you've done it by mutating an image-based
programming language or by linking together compiled C objects.

~~~
pjc50
Programs are never finished. Most work is incremental modification and
debugging of existing systems. The "getting started" bit of going from a blank
editor to something that starts to be useful is a small part of the process.
But it's the very beginning that is a surprisingly hard barrier to cross. The
starting to write a program in the first place. Which is where the OP has got
stuck. And is dismissed as irrelevant?

------
mapcars
2020: a programming language is named Janet; a child is named X Æ A-12. How
did we come to this.

~~~
oblio
It's not really something new. Ada
([https://en.wikipedia.org/wiki/Ada_(programming_language)](https://en.wikipedia.org/wiki/Ada_\(programming_language\))
) was created 40 years ago. Kids with crazy names is a long standing
tradition, going back millenia :-)

~~~
mhd
Also Amos, Haskell, Idris, Joy, Miranda or Yorick. Arguably Dylan or Pascal.

I'm more confused by a name starting with a capital "J" not being associated
with Java, as once was custom.

As for kid's names, definitely[1].

[1]:
[https://www.youtube.com/watch?v=Jg9w0YSMLHY](https://www.youtube.com/watch?v=Jg9w0YSMLHY)

~~~
iLemming
And don't forget Swift, named after the biggest philosopher of our time -
Taylor Swift.

------
thanatropism
Not mentioned here: Hy (hylang.org), a Lisp that manipulates/converts to the
Python AST and therefore is fully interoperable with the whole vast Python
ecosystem.

Although the language is still somewhat short of 1.0, it has stopped changing
(after a fairly dramatic turn circa 18) and I’ve been writing more Hy than
straight Python for a while now. When I started using Streamlit (and then you
can’t have a main.hy function that it will recognize, although you can import
arbitrary Hy modules) I started writing straight Python again for my weekend
project and boy, do I regret it. I’m seriously considering pausing everything
to port to Hy.

~~~
mark_l_watson
I certainly agree that if you need the Python ecosystem, then Hy makes
development much more enjoyable, at least it does for me. I look at Hy in the
same way as Armed Bear Common Lisp: as a great tool is I need the Java
ecosystem.

------
mr_custard
Many people seem to be comparing Janet and Clojure here as if one had to
choose to use only one or the other.

Most of my daily work is done in Clojure or ClojureScript and that will
continue to be true. However, I am excited by what I've seen in Janet and I'm
already thinking that I'd love to call this from bash scripts to do system
tasks (devops for example) that don't need the JVM cranked up.

I'm choosing both :-)

------
technoplato
Please tell me this was somehow inspired by “The Good Place”...

~~~
Witoso
Yep.

> Janet is named after the almost omniscient and friendly artificial being in
> The Good Place.[0]

[0][https://github.com/janet-lang/janet#why-janet](https://github.com/janet-
lang/janet#why-janet)

------
dleslie
I'm not really clear why I would use this and not one of the small embedded
Schemes that have srfi-18 support.

Chibi and S7 are both "drop some C into your project" levels of trivial to get
running, and reasonably zippy.

And there's an upgrade path by using the standard: you can move to Chicken,
Gambit, Guile, Racket or Chez and keep your code.

------
orwin
I'm beginning to create a lisp webserver using sbcl for a personal project.

I find this interesting but i'd like to know if a webserver library exist for
janet yet, and how does it perform compared to sbcl performance-wise (x2 to x5
does not bother me, anything beyond that would not be great).

I'd like to know if a slime/swank can be used with janet (although this is
really not a requirement)

[edit] i just thought that creating a webserver would be a nice introduction
to the language.

Also can you compile janet into wasm?

~~~
srle
It’s right on the bottom of the page my dude, just scroll down or C-f circlet

~~~
orwin
wow i stopped at "try it". thank you.

------
eggy
I like it, and I am considering using it as a scripting language.

It was clear and easy how to build it for my Windows 10 box, and it is
relatively small.

I have always like the small Lisps like PicoLisp, but PicoLisp is not Windows
friendly; it's very POSIX-dependent. I haven't had great experiences with
Cygwin. PicoLisp works on WSL/WSL2 though.

~~~
kmwr
Have you seen [https://janet-shell.org](https://janet-shell.org) ?

~~~
eggy
I had, but it is for unixes, and I am primarily on Windows. I have a Linux
box, WSL2, and an iMac, but all of my paying work is on Windows. I like them
all, and I like Janet a lot!

------
rcarmo
Janet is quite nice, and I was playing with it only the other day:

[https://taoofmac.com/space/blog/2020/05/10/1300](https://taoofmac.com/space/blog/2020/05/10/1300)

However, nobody here seems to have mentioned Joker, which is a Go
interpreter/linter for Clojure:

[https://joker-lang.org/](https://joker-lang.org/)

I'm rather torn between Janet and Joker, but am considering using Joker
instead (even though it is single-threaded and lacks SQLite support) because
it's closer to Clojure syntax.

------
mlatu
This sounds awesome!

I was about to try and extend a software-product with graalvm to extend it
live in clojure.

But Janet sounds like a couple less hoops to jump through.

Also, I won't have to deal with Oracle at all :D which is really the main
reason I haven't begun work on this project yet.

------
augustk
How does this language compare to, say Scheme?

------
macleginn
I looked at the first two libraries listed on the landing page, and they seem
to be mostly implemented in C. (The same goes for the 3rd lib, but it's SQLite
bindings, which makes sense.) This is a bit discouraging.

~~~
prirun
I have been looking at Nim, Go, and D lately, as a follow-on to Python. Good
SQLite support is something I need for HashBackup (author).

Nim has a direct interface to SQLite's C API and a higher-level db_sqlite
interface. The higher-level interface doesn't support prepared queries so
Nim's SQLite performance on a small test is slower than Python using the
sqlite3 API which automatically compiles and caches queries.

The Nim binding replaces all parameters, specified with ?, with quoted values.
That means:

\- you can't have a null-valued parameter

\- numbers get inserted as text (I think)

\- blobs are string quoted and get changed to text instead of using SQLite's
X'(hex)' blob notation

All returned values from db_sqlite are strings. If you want integers, you have
to parseInt() the column.

I do like that Nim's db_sqlite interface is very simple so that you can still
use the lower-level sqlite interface with the same db connection. So at least
I could cache prepared queries if I wanted, but I have to do the work.

Checking out Go's SQLite interface, there are some issues posted on the repo
(mattn/go-sqlite3) about performance problems because Go uses cgo for SQLite.
Haven't test that yet.

Since the SQLite module was listed on the front page of Janet's site, I
decided to check it out. It, like all the other C code I looked at in the
project, is rather beautiful, and that's not a compliment you see very often
about C code, my own included.

The SQLite interface handles multiple types, including nulls, blobs, and
numbers (everything is a float, I'm guessing because that's how Janet
implements all numbers).

It appears to not cache prepared statements (that would probably be a big
performance boost), but does allow parameter substitution by name.

If you want to see some really nice C code, check out this project!

------
firepoet
So, I do a lot of string manipulation using regular expressions, and Janet
doesn't support that, in favor of PEGs, which I've never heard of. Does anyone
know of a "PEGs for RegEx addicts" resource or something similar? :-)

What an interesting project! I'm sorely tempted to examine it more closely for
one of my side projects I've been working on in Clojure.

~~~
firepoet
While I'm asking for help.. does anyone know of any crypto bindings? I've been
working with libsodium lately, and there is a Clojure library that binds to
it.

------
Koshkin
For those who would prefer a more traditional albeit possibly less
“lightweight” alternative there’s always Embeddable Common Lisp.

~~~
flavio81
Or, since Janet is a bytecode interpreter with a download size of <2MB,
there's CLISP which also fits that criteria, while providing the full power of
Common Lisp and a nice FFI with C.

------
Jaruzel
There is already a JANET in the computing place, please rename your project:

[https://en.wikipedia.org/wiki/JANET](https://en.wikipedia.org/wiki/JANET)

Next time, actually Google your proposed name before you use it.

------
gozzoo
Is it compiled or interpreted? If interpreted does it use existing
interpreter? The description mentions Lua, does it use the Lua engine? Does it
have JIT? If it is compiled is it based on LLVM?

~~~
anonymoushn
I don't know much about Janet (all I've done is complain that create-fiber did
not work the way the docs say it did), but I'm pretty sure it uses its own
bytecode interpreter.

------
Sawamara
For what it's worth, the win x64 installer died on me at "creating desktop
icons", not exactly the most confidence-inspiring start, but lets see again.

------
pixelrevision
Wow a lot of care was put into making a complete out of the box readable
library but not including too much fat. Looking forward to my weekend.

------
shirian
Wow, this is exactly what I've been looking for. Also, I'm not a C-programmer,
but I think the source code is good-looking.

------
billfruit
How does this compare with Carp?

------
oknoorap
Any tutorial about Janet?

~~~
jbritton
The Janet documentation is sufficient to get going. It reads pretty much like
a tutorial. At least if you have any lisp/scheme experience. [https://janet-
lang.org/docs/index.html](https://janet-lang.org/docs/index.html)

I downloaded a couple weeks ago. I really wanted to build an executable, but I
couldn’t. It seemed all the docs on this aspect were out of date or my build
was broken in this respect.

~~~
oknoorap
oh okay, freecodecamp course would be great :-D

------
lenkite
Can't find the tutorial or language manual.

~~~
hanche
I see no tutorial either, but did you try clicking the prominent link near the
top labeled “Documentation”? The language manual seems to be all there. Once
you're inside the documentation, there is a hamburger menu exposing a
comprehensive table of contents.

~~~
lenkite
I am an idiot. Somehow I went to the API documentation and examples instead on
the github site. Thanks.

------
pauljurczak
Call me when you modernize parenthesis out. ;-)

~~~
pauljurczak
Touchy subject. As expected, downvoted by the Brotherhood of Defenders of a
Holy Round Bracket.

------
frankpf
I don't use lisp languages, but one basic difference this has from other lisps
is that functions accept multiple expressions, e.g.:

    
    
        (defn greet [firstname lastname]
          (def fullname (string firstname " " lastname))
          (string "Hello, " fullname))
    

In other lisps, you'd have the last expression nested inside a `let` block:

    
    
        (defn greet [firstname lastname]
          (let [fullname (string firstname " " lastname)]
            (string "Hello, " fullname)))
    

which makes the code hard to read and edit IMO. Languages like Haskell and
OCaml suffer from a similar problem too.

~~~
nathcd
> which makes the code hard to read and edit IMO. Languages like Haskell and
> OCaml suffer from a similar problem too.

That's interesting, I've always really loved the "return last expression in a
block" syntax. (Ruby and Rust can be added to your list as well.) That syntax
just reads really naturally to me.

~~~
frankpf
I like that too, but both Rust and Ruby allow multiple expressions/statements
before the last expression. In Haskell and OCaml IIUC you need to use things
like `let x = ... in <expr>` or `<expr> where x = ...`, so you still have a
single expression in function bodies.

