Interview With Matheus Moreira
Jul 2026 - Alex Alejandre

Matheus Moreira (blog) built lone lisp directly on Linux system calls. In this interview, he shares his knowledge of C and the Linux Kernel.


How did you get into computing originally? What was your path before discovering Lisp etc.?

I’ve always liked computers, but what truly got me into programming was video games. When I was a kid, I used to play games from a series called Mega Man Battle Network, and I ended up getting inspired by those games. They’re ultimately responsible for my learning English; I used to join forums as a non-English speaker and try to socialize. It was rough at the start but I improved! The same goes for my first language, C++.

How young were you when you started with C++?

In Brazil there are “technical schools” which is what I attended. They’re normal highschool curriculum, with extra professional classes. I’m not sure if these are common abroad, if there is a term for it. There were other courses, also: chemistry, mechatronics… As for quality, it was basic, yet pretty good for a highschool level. It did make me start learning all by myself though; within 6 months, I’d already learned the entire curriculum. Eventually they hired me as a teacher’s assistant to help fellow students.

So when I started highschool, around 13-14, I took the informatics course and started learning C++ with a very old IDE called Dev-C++, which still exists on source forge! I also browsed the tutorials on cplusplus.com. I tried making games but wasn’t very successful at it! It was pretty hard, especially because I had yet to learn all the physics I was supposed to be simulating :) What I did end up doing was learning a lot more languages. After some basic C++ proficiency, I learned quite a bit of Java, then Ruby, then Python… That eventually led me to Lisp and Scheme! I remember thinking scheme was extremely elegant when I first saw it. Ruby was my favorite language though. I wrote a few gems back then. I think one actually got a small following: Acclaim, a git-like command based argument parser.

Cool! Did you happily jump into new languages or did you first try to stay with C++?

I think I started learning more languages after I exhausted the cplusplus.com tutorials. I felt if there was nothing else for me to learn on that site, then I should probably move on, right? Sun used to have a really big Java Tutorials website back then. I think I read that entire site. That was when I learned object-oriented programming. I wrote some java code as a teenager… Some “utilities libraries”. In hindsight, it was just a badly implemented version of 1% of what Apache commons has! I think I even published it, might still be out there somewhere… I also remember experimenting a lot with Java Swing applications. I used to really like the Nimbus look and feel and made a circle/arc drawing application for my math professor once.

What motivated all of these delvings? What inspired you to keep checking out different languages and so on? Have you stuck with Ruby too?

School projects were a big motivator in my early school years, but at some point it was about curiosity, and a desire for The Right Thing. I wanted a language to call home. I stuck with Ruby the longest. It’s a really nice language. I always have it installed, and have recently started a Rails project! But it has its imperfections too. The other language that I stuck with was C. Its low level simplicity was really captivating to me.

I didn’t forget C++, but I also didn’t update my knowledge. Current C++ is essentially a completely new language, so I no longer claim I know C++. In a sense, I replaced it with C. C was always captivating for some reason, despite all the problems and legacy, but it really started getting entrenched in my mind when I started exploring the CRuby VM source code as a teenager. I had this really fun past time where I’d watch for interesting stackoverflow questions where someone would ask “why does Ruby act like X?” and I’d dig into the source code to figure it out.

A few years ago I tried to transition to Rust, but it didn’t quite stick. I’m also a huge fan of Zig and its creator. Have been since I watched “the road to Zig 1.0” keynote where he laid down reasons why people “rewrite things in C”: speed, ABI…

What pros and cons kept you with C and Ruby?

Ruby was an extremely expressive language which “just fit” with my mental model. I could often guess a method name and it would work. It has nice things like singular/plural forms of method names, synonyms. Our brains work with these words, and Ruby supports them all.

Matklad mentioned good APIs should be guessable and if he guesses stuff which don’t exist, he’ll often file a bug report saying the API demands it!

Ruby also enables composing eerily shell-like processing pipelines… items.each.with_index.map… It just keeps composing and you can do a LOT of work with very few characters.

For C, the main advantage is the simplicity of the output. You write a function, it compiles to an ELF symbol and associated assembly code. They say you can see the compiler output when you write C, and it’s true. With C++ the compiler adds a lot of machinery, it’s very difficult to understand how it all fits together. With dynamic languages, it’s just the same, but I found it easier to explore the source code of virtual machines than that of compilers.

So your C++ style changed, removing sugar until you were writing C?

Yes. My style also changed as I read more and more code written by other developers. I’ve explored CRuby code, CPython code, JVM code, a bit of guile code, even a bit of V8 code… I started to really admire expert C programmers when I started reading Linux kernel source code though. It’s really good, probably the gold standard.

From the beginning, you read a lot? It’s quite rare particularly today for people to really read others’ code. How do you approach this? Any tricks or techniques?

I read a lot. I’ve always been the sort of curious person who wanted to know how the thing worked. I wasn’t satisfied with just using some library, I wanted to know what it was doing under the hood. I wanted to know how the drivers talked to the hardware. I wanted to know all the hidden fun stuff. That’s just the sort of thing that’s interesting to me. The real applications I tried to make, I’d end up digressing into these unrelated explorations. Other programmers would tell me “why waste time on that? it’s already solved” but I wanted to know how it was done, and eventually I also started to develop a sort of hubris that led me to want to reinvent the wheel, but better.

I did get the message though. I felt like I was a bad fit for a career in software development because of this quirk, so I didn’t pursue one in the end. Kept it as my hobby to this day.

When you first looked at driver code, how’d you make heads and tails of it all?

I couldn’t make heads or tails of it all… at first. It was frustrating, but I kept persisting and eventually I was able to understand some things, at least. I’m no hardware engineer, that’s for sure… But I managed to reverse engineer some of my laptop’s features. Still one of my proudest projects. My laptop is one of those Clevo barebones models. It has a pretty nice keyboard with RGB LEDs, most individually addressable. There was a REALLY bad windows app to control those LEDs. I swear it took over a minute to show a window on the screen, it was really aggravating. I used wireshark to intercept the USB packets it was sending to the keyboard and write a linux user space driver for it. I captured the packets, stared at the screen until I figured out their structure, and wrote a little C program to configure the keyboard for me. Threw it out on github and forgot about it… One day I went back there and somehow people were using the thing, one person even made a GUI for it. It was a pretty good feeling. I learned more about drivers and computer technology from trying to reverse engineer the rest of the laptop’s features. ACPI power management stuff. I didn’t quite figure everything out though, to this day.

You have an article about linux system calls, was that the moment you took the lone direction?

The code for system calls is pretty minimal, they work like normal function calls. I’d say the interesting part is that it allows you to bypass libc and target linux directly. Linux is famous for user space ABI stability; userspace components not so much. It allows people to depend on Linux kernel directly, without other things in-between.

I started with this general sense that people didn’t want me to use them. I’d read the manuals and they’d say things like “this system call is not supported by glibc”. I’d read wikipedia and there’d be an infograph is howing glibc wrapping linux, as though it was the CRT of Linux and other libcs didn’t exist. Then I read an article on the LWN about how it took like two years for the getrandom system call to show up on glibc.

CRT?

C runtime. The standard C library: glibc, musl, uclibc.

It’s that package which breaks the entire world whenever they break compatibility. Because everything depends on it. I remember the article mentioned something like “maybe Linux should have a liblinux.a with just the syscalls, then people can bypass libc when they aren’t helping by just passing -llinux to the compiler”. I thought that was a really cool project idea so I went and created liblinux, which was just that: a collection of linux system call wrappers for freestanding C programming. It turned out that it was really fun to program against the Linux system call interface. So many of C’s problems just disappear in freestanding mode.

What C problems disappear in freestanding mode?

The most basic one: errno. C has this notion of a “current error” which is a global variable. Every function sets it, and you’re supposed to check it. Linux just returns you that error like a normal function would. The C libraries take that value, and put it in a global variable. It’s just the way things are in C. Not in freestanding C. The legacy of C also disappears too. The C library has a lot of legacy code in it. The locale stuff, for example, is extremely problematic. It’s also global state (a recurring theme!) which can cause very subtle errors based on things like environment variables. Liblinux taught me freestanding C, and how clean C could be… If only we could delete all of its legacy. It was painful. I had to write all of my own functions. From basic bytes copying functions, to integer->string conversion functions… The problem turned out to not be as insurmountable as I imagined though, and I persisted. I knew that when in doubt, I could always read code. I could see how the giants before me did it. The glibc repository was difficult to interpret but the musl libc source code is really clean and easy to dive into. It’s been invaluable! It also stimulated a bit of creativity. For example, how could I create an automated test suite with no C library, no memory allocations, just static memory? I managed to do it in lone!

I remember I even asked Greg Kroah-Hartman on Reddit about why Linux never had an “official” C library. He replied that Linux once had a klibc project! The history of liblinux ended though: At some point I discovered Linux kernel folks were doing the very same thing! They had created a nolibc.h file that they were using internally in their own tools. I thought it was better than what I had come up with, and easier to use too. So I archived the project, and started something else: Lone Lisp. A whole programming language written in that paradigm. Deep down, I just wanted to prove to myself that I wasn’t insane to think it was possible. If I could make a freestanding lisp that ran directly on linux, it would prove that any program could be written that way.

Modern Linux user space is monstrous and labyrinthine. Linux itself is not. I found it to be a really clean system. The basis of everything is actually the Linux system call binary interface. We can actually trash the entire user space and start from scratch with nothing but Linux. We can even trash the ubiquitous GNU stuff if we want.

Why can’t we have a compiler with built in system call support? Just add a system_call keyword that inlines Linux system call code using the supplied parameters. No need for libc bullshit in the middle. No need for C or any specific language. Someone could make a language today and that single feature would make it as capable as C is for systems programming. They could write software and boot Linux directly into it. - Matheus 2021

To summarize, freestanding C removes some interesting C warts: all global state: errno, rand/srand state, locale state, strtok (not reentrant!), implicit file buffering which can occasionally bite people; badly designed APIs like gets (indefensible), atexit, signal, even malloc; lone’s allocator is much nicer. math.h can get very messy with NaN, and it gets worse when errno is involved. Some things just never leave though. C’s arcane integer promotion rules remain. Also the lack of overflow checking, but I use compiler builtins for those. I also worry a lot that I might be introducing my own warts… Hubris will no doubt bite me one day.

Do you know why the nolibc.h approach isn’t more popular?

As of now, nolibc.h has become a sprawling directory in the kernel tree, it has become an ad-hoc libc of sorts. It seems they treat it as an internal project though, something meant to compile the internal tools linux uses. I think very few people outside linux kernel development know it exists. People could totally use it to build their own projects, but I’m not sure what sort of stability guarantees Linux offers in that regard.

Relatedly, I’ve sent Cosmopolitan patches e.g. to help implement floating point parsing. I’m a fan of the project and the author. Even the people calling it a “dumb” hack are admitting that it’s a genius hack as far as I’m concerned. It’s just an amazing project that just coalesced an incredible amount of very wizardly knowledge into a single form which is the APE format. Something that manages to parse as a valid executable on various platforms with different executable formats is a very curious thing indeed. And it even does neat things on top of that, supports embedded archives in executables.

It’s important to at least be thinking about hubris and how to avoid warts, hopefully. Many never introspect… Floating point’s the only unchecked lone feature, what happens after? Do you want to build particular things in it.

As Steve Yegge said, just creating an interpreter creates a baby, a lifetime of work. Floating point is gonna be a hard one, but the work forward is literally unbounded.

Just this weekend I implemented the error handling system. It’s a Common Lisp style restartable condition system. Before that, every error path was a hard exit(255) from the interpreter. My next task is to replace all of those call sites with exceptions that can be handled within lisp. I also pushed proper tail call optimization support just now… Floating point is going to be a hard feature, if the patch I sent to Cosmopolitan is any indication. It’s something I’ll have to implement though. I also want to eventually start implementing ideas from the Erlang/BEAM system. I structured it so that there could one day be many interpreters running lisp code in parallel. Those are all language level features.

What to build with the language itself? The very first project I want to make with lone… Is a replacement for my static site generator. I write my website in a fork of pugjs which I’ve been maintaining myself. It’s my long term goal to write my own system in lone lisp to replace it. After that, I want to write my own shell. My own utilities. Start remaking the traditional Linux user space in my image.

Those were the ideas that float around in my mind while I develop lone. One of my articles even mentions an implementation of env which just dumps the environment as a lone lisp table. Lone didn’t have any iteration facilities at the time, so that was the best I could do. Now lone has generators! I can do a lot more… It’s such a good feeling when I implement something and it just unlocks a lot of other stuff. The embedded segment feature is something I designed precisely for that “linux utility” use case. The lone interpreter has a feature where it reads a special ELF segment and just runs the code there, as though it was compiled in. So I can make lone programs by copying the interpreter, adding some lisp code to the copy, and it becomes a self-contained program. It’s now got generators, delimited continuations, and I just introduced error handling.

How similar is the new error system to Common Lisp’s??

The error system is similar in many ways but without the Common Lisp API where the signaling code gives options on how to restart, options like use-value. My system builds directly on top of the delimited continuation work. Until implementing them, continuations were just one of those mystical scheme features but I discovered that everybody was already using a version of it. Exceptions mechanisms are essentially a form of continuations, they just don’t get captured into a value. And the magic is capturing the continuation. Alexis King’s presentation on delimited continuations demystified that for me, it demonstrated that in the end it was just memcpying stacks. Making a copy of the stack, then “replaying” that stack somewhere else, like a VCR. Resumable exceptions. The error signaling system turned out to be just this, with a handler mechanism on top. I had to implement the “catch ErrorType -> code for ErrorType” part. I chose a simple system just mapping, say, a symbol like 'not-found, to a lambda. So it tests the lambda’s arity and if it takes one argument: (lambda (error) ...) it works just like every other language out there. But if it takes two: (lambda (error continuation) ...) then it provides a way to resume the code via continuations.

Lone’s error system makes the throw return a value to the calling code. Each exception handler can optionally receive a delimited continuation. If they do, they can call it to resume the erroneous code by returning a value.

Did you reject any specific systems or approaches?

I tend to reject the often heavyweight ways that other languages solve these things. For example, I explicitly rejected the Common Lisp style “restart API” which lets code enumerate a number of ways to restart. I wanted everything done in terms of simple language mechanisms in the evaluator itself, so restarts simply act as though signal/throw/transfer returned a value. I also rejected “special cases” in the evaluator whereas traditional Lisp implementations have eval explicitly support special forms such as if. In lone the evaluator doesn’t have those special cases. It has support for FEXPRs, which are essentially evaluator plugins. That made certain things a lot more complicated than they had to be, just for the sake of that elegance (as perceived by me, at least). For example, tail call optimization worked for pure lisp functions, but not quite for the primitives. TCO for primitives has been fixed since then but it was buggy for a while, ultimately because of the design choice I made to factor them out of eval. I had to introduce special mechanisms for them to tail return.

I have also been generally trying to come up with in-language ways to do common things, ways that exploit the evaluator machinery. For example, I made vectors (arrays) and tables (dictionaries) callable. ([1 2 3] 0) returns 1. Then ([1 2 3] 0 4) modifies the vector so that it’s [4 2 3]. Continuations and generators are also directly callable. There are two primitives: control and transfer. Control is just like begin, but it supports continuations. Transfer breaks out of the code to the nearest control block. It returns a callable continuation value encoding the program at the point it broke out. So resuming it is just (continuation 'some-value). (control (transfer 0) (lambda (value continuation) continuation)) Then you can make that (transfer 0) call return something else by calling (continuation 'something-else). It works like a function (same calling convention) and you might be able to implement currying on top of it.

How many system calls does lone actually use?

When lone starts, there’s just an execve system call by the parent process. Then about a dozen mmap system calls for internal memory management. Then it reads the script file from standard input, runs it, then exits. Minimal. As it executes, it might also cause more Linux system calls to fire internally, mmap, munmap, mremap (!). The module system also uses openat and close. Of Linux’s wide repertoire of 300+ system calls, lone uses a small fraction. It provides a system-call primitive at the lisp level, though. So lisp code can do anything. Many of those system calls also require kernel data structures. Support for creating/manipulating those C structures is also pending. For example, ioctl is an important system call that will require that structure support work. It’s what allows things like getting the terminal’s size.

How far away do you think those things are from right now? Are you thinking of expanding the “roadmap”?

I don’t know to be honest. I’m not very good at organization. Though I got a lot better with AI help. I’ve been using Claude as a manager of sorts. The work is unbounded, but the language itself is nearing its complete feature set. The most valuable thing Claude’s been doing for me is… Code review and project management. I’ve been programming pretty much solo for over 15 years. Having another set of eyes on my project, critiquing my code, spotting problems, underdeveloped areas, was just world changing for me. I frequently point Claude at the entire lone codebase and tell it to be harsh and point out all issues, identify areas of future development. Discussing ideas with the AI is also really useful, it enabled me to refine my ideas on several instances. I improved the garbage collector and memory allocator a lot because the AI was able to teach me much improved algorithms. I still don’t trust it to write code for me. I care too much about lone not to scrutinize every line that makes it into it. Actually writing the code myself is often educational for me too. But I’m definitely guilty of pointing Claude to my Javascript-based static site generator and have it vibecode entire features.

When I ask Claude to review the entire codebase, it spots the problems and also suggests future directions, then it compiles them into documents. “User wants X”, “User has rejected approach Y”, it’s been great for managing a lot of this ephemeral context that exists only in my mind. It’s essentially automatically managing a todo list for me. I’ll often say something like “We won’t do this now, make a note of it for the future” and Claude will store it in the project’s memory. For example, one of my planned features is support for GCC/clang compiler APIs. The most basic one is the stack protector functions. I have a note stored with everything known about those APIs.

What else inspired the language? You use “modern” Lisp syntax which seems universal now.

Ruby and Scheme inspire me. I remembered how great it felt to write Ruby, and also how clean Scheme was as a language. I wanted to mix both and see what I got. It also helped a lot that lisp was really easy to parse. I hand wrote the parser and suddenly had all those nested lists I could play with, which is what I was really interested in. I didn’t truly understand lisp though until I implemented FEXPR support in the evaluator. Something about the function just receiving the lists themselves, made it finally click.

I think [1 2 3] for arrays and {k v} for dictionaries is very intuitive and nice. Besides Clojure and newLisp, Ruby, Python, Javascript all have that syntax as well. Not adopting that syntax could be a problem! It would add a lot of needless friction for programmers familiar with popular dynamic languages. The Common Lisp literals are also somewhat ugly: #(1 2 3) is a list but not quite due to the #?

What’s good coding style to you?

My C style is a modified version of the Linux kernel’s style. I tend to follow it closely, but break out my own conventions in some instances. For example, they really like uniform code to make it visually easy to parse. I like aligning and decorating the code a lot more. My Ruby style favored lack of punctuation. method 'arg' instead of method('arg'). The idea was to make the code read more like English prose. Well designed APIs also had this property: collection.each.with_index { |item, i| ... }. It might be too early for me to have an opinion on Lisp style, but I’ve been developing a strong preference for less syntactic nesting. Simple example: let. In lone, let works like this: (let (a b c d ...) body...) rather than the time honored (let ((a b) (c d) ...) body...). My reasons for doing it this way mirrored the function application implementation. ((lambda (x y)) 10 20) -> x 10, y 20. Using a (x 10) and (y 20) list just felt unnatural, they aren’t really pairs, they felt more like an ordered sequence to my brain: x 10 y 20.

What’s performance like?

There is one benchmark lone wins: startup speed. It can start and finish a program faster than Ruby can load Rubygems. Ad-hoc benchmarking has revealed that lone is about 10-100x… slower… than Python. They’re in different performance categories though: lone is a list-level interpreter, like SICP’s chapter 5.4. Python and Ruby are bytecode interpreters. I’m bravely resisting the bytecode compilation, just because I feel that I’d lose the essence of lisp if I convert the lists into bytecode. Is it really list processing if the evaluator isn’t processing lists?

I remember reading one article about how CPU branch predictors are getting so sophisticated even normal naive interpreters are becoming fast, they can apparently predict through the indirect branches now. That gave me some hope! My long term plan for performance was to keep the C interpreter as the ultimate baseline for bootstrapping, then write a JIT compiler inside lone itself. I can just mmap in some executable pages and emit instructions. That’s when the compilation will begin… Python is routinely shamed for its poor performance so I’m afraid lone will end up getting bullied even more. But the truth is… It should be surprisingly viable for user space work. I ran some ad-hoc benchmarks against bash and absolutely crushed it, which people use all the time! (Though that might be a testing artifact as recursive fibonacci isn’t exactly bash’s strength and it may be spawning new processes on each iteration or something…) But for scripts, startup speed matters a lot. You can’t have a virtual machine that takes half a second to bootstrap and lone really shines here.

I can improve lone’s startup further too. For example, the Ruby VM will run quite a lot of code to bootstrap itself. It will do things like initialize hash tables all over the place, things like environments mapping some variables to Ruby objects. For lone, I’m gonna have to add a buildstep to precompute all the hash tables and compile them to C initializers! Then Linux will mmap in the executable and it’s ready to go, just like that! Great for scripts! Zig’s comptime would make this really easy, but I didn’t really know zig when I started lone.

Lone has a few “intrinsic” modules; the top-level environment contains exactly two symbols: import and export. From there, all modules bootstrap their environments. Even things like if and quote have to be imported because I wanted users to have full control over every single name in their environments. You have to import everything besides lists, literals and the function call mechanism. It’s all very spartan at the moment; I’ve just implemented the stuff I needed for the implementation itself e.g. flatten. In total, there are perhaps 50 functions right now, primarily in the lone module which contains the language features: if, let, begin, control/transfer, intercept/signal

How does mmap work exactly?

mmap is essentially a function that asks the kernel to give you “pages” of memory. It’s a lot like malloc, but lower level. Each page is (most commonly) 4096 bytes of memory, you can ask for multiples of that. And you can ask for specific protections in those pages. Readable pages, writable pages, and executable pages (which is what JIT compilers use). Memory allocators build higher level interfaces on top of it because asking for 4 KiB when you need 16 bytes wastes a lot of memory. So the allocators ask for like 128 MB and then cut it up into chunks to serve the program’s needs.

In the tests, you have various examples, but there’s no language documentation yet (just implementation stuff). How will you approach that when the time comes?

It’s very incomplete, but the truth is I’m running out of things to add to the language; I’ll have to work on the standard library soon. I’ll look at Ruby and Scheme for inspiration. Ruby’s standard library is unmatched in my opinion, while I also enjoy Scheme’s naming scheme. The iteration protocol is the next on the list. It’s gonna be something like (for (each collection) (lambda (item) ...)). I have some each functions already, tried to copy Ruby there. They’re due for a redesign though. They should all return generators. Then string manipulation functions. Even a basic string builder that allows efficient string concatenation would go a long way to make lone useful. I bet if I add this, and complete lone’s iteration story, I could write a hiccup style web framework in lone.

I’m in danger of being plagued by ADHD when I reach that stage though. Right now I’m working on all this fun low level stuff. Once that’s done and it’s “oh now I just gotta make the standard library” I might have trouble managing it… I’ll get Claude to whip me into shape when the time comes.

I consider APL and Lisp to be simpler and try to evangelize, to empower and show how accessible things are… I rarely succeed. I try to awe people with “oh that’s just X Y Z”, as though it was really simple, but I get the opposite effect, it intimidates instead.

I just enjoy having these insights, right? Like continuations. Oh, it’s just copying stack frames around. It was magical before, now it’s a normal thing. I have the feeling people don’t enjoy such insights, because ultimately they don’t care. Deep down, one of lone’s missions is to inspire people to have their own systems and explore. The people writing the manuals told me I couldn’t. You can’t use this syscall stuff, it’s not for mortals like you. I want to use the forbidden stuff, I want to be the guy making the libraries, not just consuming them. I want lone to inspire others to do the same. One reason why I think people don’t do it is the responsibility. To have your own system, you gotta own it. If it breaks, you gotta fix it. People think they already have too many responsibilities in life and computers would just add one more. I would like more people to choose that responsibility and enjoy all the rewards it brings.

Writing lone gives me full control, even over the names I’m surrounded with. It feels like computing is so full of legacy. All of this entrenched code, it’s wrong, it’s ugly, but nobody touches it because it’d break everything if you deleted it. I’d like to see people get emboldened and start deleting the bad stuff. Maybe it won’t be me who’ll remake linux userspace, maybe it’ll be the Rust or Zig folks. I got rid of libc, they warned me it’d break stuff, it’d break DNS, it’d break everything. I could have been intimidated but I pressed on. I just want to show the world, look, there’s nothing to be afraid of. You can peel away all these layers. It’s safe. And a fun journey too! Even if lone doesn’t amount to anything, if I at least inspire that, I’ll be happy.

I love this message of taking radical ownership of the whole stack, because you can. It’s the same inspirational fire of Decker or Fennel and its games.

Yeah. I really like the free software’s values of user empowerment. Computers are world changing technology, we should own them, we can’t let corporations or governments have control. I get pretty sad when I see people not caring about ownership, letting companies “manage” their computers for them. Thus the general purpose computers become appliances, something lesser. A lot of people hate projects like systemd but in a way, they’re doing the exact same “reimagining” of Linux user space that I want to inspire. Maybe more heavy handed than I’d like, but I can’t argue with how good systemd is. They reinvented it, and it was great. I want to see what else people are going to come up with, once they break away from the traditional *nix system. It’s important to pick one’s battles too. If I tried to make lone a bare metal lisp, I’m not sure if it would ever have booted. I’ll let someone much smarter than me do that one. jart’s sector lisp is a good example… Lisp in under 512 bytes of bootsector code.

I use Termux on a daily basis to automate a lot of things. Would you believe it if I told you lone was born inside Termux? I wrote a lot of it on my phone. Although Android blocks quite a few syscalls (statx was the one that bit me), lone runs on Android and the test suite passes 100%!

You decided against a software career, what do you do?

I’m a doctor. I graduated medical school in 2019. It started with AI. In highschool, I started liking biology because I was reading about programming neural networks. Some days I work 10 to 14 hours straight, practicing medicine. Other days I don’t work at all. Today is one such day. Schedule is clear, no appointments today. Medicine affords a bit of freedom to make one’s own hours. Many career paths to choose from. Surgeons practically live in the hospitals. I wanted a more lighthearted lifestyle because I need time to unwind. I work at a popular clinic with electronic records. It’s really efficient, especially for a techie like me. Even when the system is slow or doesn’t have features, I make up for it with my own skills. Even some small templates saved to the computer speed things up by 100x. Thus I can have quick consults and maintain a good relationship with patients. Even the ability to touch type helps! I can type in everything while looking people in the eye! My peers can’t! The rails project I mentioned earlier is exactly this. I’m making my own electronic patient records system to scratch my own itch. Even if it fails, I’ll be well served.

There are precious few non-professional programmers. You of course started early, but why do you think more professionals don’t scratch their own itches?

I think many don’t actually like computers. To change this, we’d have to interest them in computing, how awesome computers can be. It does take effort to learn but most people’s mindset seems to be focused on results. I already saw that attitude in highschool among people who chose to attend the programming classes. Curiosity is necessary to care about things beyond just the results, to dig into how the sausage is made. I’m not sure how to inspire that in people. If you find out how to do it, I’d like to know.