@oofoe (sourcehut) is a REBOL-refugee comes from animation and now works on precision instrument software. He makes puzzles in Decker and games in Janet (using his Janet->JavaScript transpiler) and Racket and Racket and, again, Racket and Racket and even visual novels.
Do you know of any resources to set up additional targets in %project.janet?
This can be good, but what’s the %?
Oh, sorry… The % business is a holdover from REBOL that I took up with. They indicate file paths to the parser with a leading percent sign. So you can say things like write %survey.csv data and you don’t need quotes around the path like most other languages. REBOL had something like 20+ types that the parser understood. REBOL was my first introduction to PEG (which led me to Janet…)
Oh! Please shill REBOL! This is now an interview.
REBOL had four things really going for it (in my opinion). It had a very simple, concise syntax. It had PEG and it had an AMAZING declarative GUI library. It was very self-documenting.
Janet has surpassed REBOL in the PEG category because of how it handles the grammar. And it’s not too far behind in the self-documenting sweepstakes. Syntax… Well, Janet’s a Lisp and REBOL took inspiration from SmallTalk and Forth.
As far as GUI… Janet has no “decent” GUI bindings yet. Probably a difficulty of making threading work? I once put together a REBOL style declarative GUI package for Python, so have considered doing that for Janet with RayLib. But haven’t gotten around to it.
Here is a GUI digital clock in REBOL:
view layout[origin 0 t: h1 red black (to string! now/time) rate 1 feel[engage: [t/text: now/time show t]]]
Now, that’s a purposely code-golfed example, but it gives you an idea of how small you can go.
I used REBOL to build (among other things) a visual video editor, tools to ingest and process stuff into a professional editing package, lots and lots of utilities that could have nice interfaces because they were so easy to do in REBOL.
This is a simple visual flow-based compositor that I did for a contest at work a while back: https://hg.sr.ht/~oofoe/tc
Why did Sassenrath quit?
I really loved REBOL. It was tragic that Carl Sassenrath (the guy who invented it) decided to quit (and run a vineyard) before taking it to 64bit, but on the other hand, maybe it was the right decision, because his idea of “programming in the small” had a hard time finding a receptive audience, even though he was right on.
Programming in the small?
Wikipedia has a bit about it, but here’s his manifesto. “Programming in the small” is the idea that programs don’t have to be big and complex to be useful and robust. Part of that philosophy was achieved by having lots of useful data types in REBOL (e.g. 16:34 is a time, 2021-05-19 is a date, 34x994 is a coordinate and so on. You didn’t have to do anything special (like import libraries), you could just use them. The other part is stuff like “global variables are good enough” and not worrying too much about side effects. You’re making a small program that does a limited set of things, it doesn’t have to be a big interoperating thing (like anything in Java), or have lots of ceremony, like C++.
I favour human-sized, in the sense of Carl Sassenrath’s “programming in the small”. Giant edifices of code are rarely justified (or justifiable) and often obviated by reframing the questions you’re trying to answer. (Yes, exceptions – a state of the art optimized graphics renderer probably won’t be less than 500 lines (ha!) and if you want a feature-complete reimplementation of Micro$oft Word, well…) However, even when doing somewhat complex things (render farm control software, multi-user studio management system, etc.) I try to make the data control the flow so that the code itself is fairly simple and “obvious” once you’ve seen the data.
“Proper” Forth development consists of creating the vocabulary required to solve your problem, but you don’t have to throw away the rest of Forth. In Forth, a DSL is basically an emergent property of the language – you have all the same tools as the language implementor at your disposal. Things do generally have a “forthy” feel to them when you’re done (although some people have implemented FORTRAN, BASIC and even C in Forth…), but that’s generally no defect when you’re working in an environment that supports it. For whatever reason, DSLs in other languages seem (to me) to require an extra mental step because they’re divorced from the language proper. Like, say, Racket. You can do other languages and syntax in it, but it’s such a bother?
That said, most of my Forth programs have been fairly small by the standards of ray tracers or word processors. My render-farm controller was Forth-based, but it had a fairly simple job once I reframed the assumptions. I suspect I would approach word-processing the same way – i.e. it wouldn’t look like Word. ; - ) I used to joke that all the programs I’ve written in my career would fit on a single 1.44MB floppy. I don’t think that’s true any longer, but I try.
Forth also likes global variables. Chuck Moore said local vars are dangerous.
Forth uses the stack for what people would typically use scoped function local variables for. E.g. def add(a, b): return a + b in Forth would be : add + ;(where : starts a function definition and ; terminates it). Where’s the variables? That’s the thing in Forth – they’re put on the stack by whatever calls add and it immediately operates on them, so they’re simply not needed.
Well… He’s not wrong… They’re definitely an extra thing that has to be managed. However, he’s the only person I know of that could implement an MPEG decoder without them! So, for lesser mortals, sometimes they’re useful.
I knew Forth before I took up with REBOL, but REBOL really made it clear how a concise notation and rich data types were worth an extra 30 IQ points (paraphrasing Alan Kay). That’s one of the things that really frustrates me with “modern” software development. REBOL shows the way to a world where you can program interesting things quickly, almost like building stuff on the fly with your (say) C64 back in the day with the built-in BASIC. To me, that’s “vibe-coding”, not the AI thing. Just starting with a blank screen (or editor buffer) and seeing where it takes you.
The Jester transpiler I did for Janet was kind of that – I had the germ of an idea, “could I translate this Janet to JavaScript with a PEG?” And then I started adding stuff to it until I could write whole programs! Janet’s not REBOL, so there are a few parenthesis mixed in, but it worked very well – almost stream-of-consciousness. (The code reflects that, of course, I keep meaning to clean it up a bit, at least for error checking.)
How did you discover Forth?
Ooooooh boy… Cast your mind back to 1981. I had my first computer, that I bought with all the proceeds from my summer job – a shiny black plastic Sinclair ZX81. The ZX81 was actually kind of an interesting machine, very compact (and cheap) and from what I understand its BASIC actually influenced Python to some extent. However, while it was a very clever design, it was slow. Like really slow.
I saw an article about a thing called “PluriForth”, which was a replacement ROM for the ZX81 that turned it into a complete multitasking machine. But it was a hundred bucks. I couldn’t afford that. But I could get ZX-Forth, which came on cassette. It was completely alien to me, coming from BASIC, and not too friendly. But I found Leo Brodie’s Starting Forth in the library and things got better from there. The thing that absolutely sucked me in with Forth was that, unlike BASIC, it wasn’t a black box. You could pull the pieces apart and see what was going on.
As I love Forth, I was keeping an eye out for Forth(ish) languages when I ran across a GUI clock implementation:
clock: layout [
origin 0
clock-face: banner 140x32 rate 1
effect [gradient 0x1 0.0.150 0.0.50]
feel [engage: func [f a e] [set-face clock-face now/time]]
]
view clock
I was hooked. I wound up writing several substantial programs with it, including a video editor and a 2D graphical network compositor. I got a lot done with it until the word came down from management that henceforth, all development would be in Python… (Not that I don’t like Python too, it’s just that REBOL was extremely effective for doing small-to-mid size GUI apps.)
What was that render-farm controller you mentioned?
A friend of mine got a job in California at one of the big studios. I got to talking to him about how their render farm worked (because I was working on mine) and he described how the different projects would have “render wars” to try to get more compute for their renders. They would hack other user’s accounts and de-prioritize (or delete!) their jobs, change the size of their render pools so they could “steal” more machines, that sort of thing.
So, I decided I was going to have none of that on my render farm… Instead of the traditional render farm thing where you would set the number of machines your jobs could use (the pool) and then assign each job a priority (how likely it was to get rendered – 1000 was “immediate”, 1 was “whenever”) I made it a hybrid… You could ask for any number of machines you wanted, and give your jobs the highest possible priority, all without hacking. HOWEVER! If you asked for more machines than another project, their jobs got priority over yours!
So, let’s say we have 100 machines. For project “A”, their render wrangler might ask for 100 machines and run the jobs through at mid priority. However, project “B” could nip in and ask for only (say) 20 machines and even at lowest priority, they would get red-carpet service. Now, once “B” was done, “A” would get everything to itself. There were some other wrinkles, but the idea was to reward people for asking for a reasonable amount of resources instead of trying to glom them all.
As I recall, it served us for several years and saved us hundreds of thousands in licensing fees, up until our second major theatrical production where it was unceremoniously replaced by a commercial solution because they gave a company official a free trip to some island paradise somewhere… ; - )
You’ve used Racket, NewLisp and Janet, how’d you get into Lisp?
So, a long time ago, I did civil engineering things. Technical drawings and some light design work. I started out doing drawings with precision ink pens on poster-sized semi-transparent mylar sheets, which we would reproduce by running through a stinky ammonia contact-printing process. After enough of this, company management decided to dip a toe into the new computer aided design stuff. They got a top-of-the-line PC – 16Mhz 386 processor with mathcoprocessor – with an early version of AutoCAD. I got really, really good at using it. And I wanted to do even more.
AutoCAD was primarily architected by a supersmart guy named John Walker and he came from a very traditional computer science/mainframe background (like UNIVAC mainframes). He often thought about things at a higher level than many of his grass-roots California compeers and he was very interested in embedded scripting languages (his seminal ATLAST was absolutely formative in my development as a programmer). He pushed to integrate an open-source Lisp interpreter deeply into AutoCAD.
It was an amazing forward-looking feature. Unfortunately, while it was very capable and flexible, there was almost no documentation in the main AutoCAD manual. Just a half page blurb with a short demo program (written in the Don Lancaster style) and an offer to get the AutoLisp programming manual for the cheap, cheap sum of more money than I had. Well, I thought sure I could figure it out, but I had NO idea what was going on. There was no Internet. No peers, no user groups. Nobody I could find knew what was going on or how to use it. Or even cared. So… no Lisp.
I left civil engineering and got into VFx. The studio I was at did a lot of business in Mexico. This was great until the Mexican government engineered themselves into the peso crisis. We had already been experimenting with using the nascent commercial Internet to deliver preview footage to clients to save on FedEx fees. Now without the clients, we turned on a dime and became a local internet service provider. And the timing was great – we were sitting there ready to go when Netscape Navigator dropped and the public web was born.
Back in the day, becoming an ISP wasn’t a turnkey operation. There were a whole lot of crazy technical things you had to figure out on your own. One of those things was web hosting. Simple static sites were easy enough, but people were starting to want the database-backed good stuff. I read everything I could find by Philip Greenspun, the culmination of which was a SmallTalk-like browser-based environment for building web applications in Perl. This wasn’t just a site-by-site thing like a local WordPress install either – it was a complete “web operating system”. There was nothing else like it. Well, almost…
Around this time, I found Paul Graham’s essay about Viaweb, the e-commerce startup he helped found. They programmed using Lisp. I wasn’t that impressed with his claims for flexibility or expressiveness (after all, we were already using Perl, right? ; - ), but some of the capabilities he described (closures!) sounded like black magic. Much like when I was paddling around the shallows of AutoCAD and my kicking foot had smacked into the rugose body of XLISP, I wanted to know more.
I found CLISP and CMUCL and others in short order. I was ready to unlock all this cool Lisp stuff. I did actually do some stuff with it, like my studio’s website and a few utilities. Unfortunately, I just couldn’t make Common Lisp “click” for me. The underlying concepts were elegant, but it seemed to be all strangled by no end of janky cruft that seemed to do the same thing ten different ways, but with no roadmap to picking which to use. And, let me tell you, the Common Lisp HyperSpec was no help at all.
But, I got Emacs working and I started figuring out elisp. And I also ran across the Toronto Lisp Users Group. And then… I found NewLisp.
NewLisp had some warts and for some reason a lot of people got upset that it called itself a “lisp” when it didn’t meet some imaginary criteria for lisp-dom. However, for me, it was a total breath of fresh air. Things were named rationally and purposefully – I could often guess the name of a built-in function instead of needing to look it up. There were some great usability features, like implicit structure accesses. And it had a cross-platform GUI library. But most of all, it had excellent documentation!
NewLisp was a launchpad. It wasn’t perfect, but the language itself made sense and I finally had good, coherent documentation. Among other things, every function in NewLisp had an example program you could just type in and run. This, more than anything, gave me a jet assist when learning. I wish more language authors would understand this.
I took NewLisp pretty far. I never really got around to doing a video game or anything in it, but I did almost everything else. My first “useful” GUI program with it was an aviation weight and balance calculator, which helped with the tedious calculations before a flight: https://hg.sr.ht/~oofoe/wb. I also experimented with a Twine-like 2D writing tool (https://hg.sr.ht/~oofoe/storytrace) and an implementation of Jef Raskin’s computer programming teaching platform (https://hg.sr.ht/~oofoe/flow).
But there were a few flies in the ointment. One, there wasn’t a good way to package (compile) a program. And two, if you wanted a GUI, you needed to have Java. As Oracle began “altering the deal” on Java, this was becoming less and less attractive. So, I started looking for a new place to land.
I had played with DrRacket before, but always kind of dismissed it because I didn’t really get along with the IDE. It could certainly do some powerful things though. However, in 2018, I finally bit the bullet. I had found out about the Lisp Game Jam on itch.io and I wanted to participate. Since I still didn’t have a way to “compile” anything with NewLisp and I wanted to make an executable, Racket looked like the best choice.
The experience wasn’t perfect, but I actually made it to the end of the jam with a complete game. Not a very complicated or interesting one (Castle Monsterous), but it worked and I could ship it. I moved all my lisping to Racket.
I used it almost exclusively for my recreational (and some work) programming for the next several years, learning about various arcane facets of the language. The “universe” simulation/game framework was instrumental in shifting my thinking to where I could envision my “Canned Heat” not-a-game-engine, and the language creation facilities of Racket led me to my next step – Urlang. Using it, I made the most polished one I’ve done recently “Class 6” which kind of rips off “Helltaker” (just based on a let’s play I saw of it). Art is placeholder for the most part, but it does make a complete game with an actual ending!
Now, Racket could compile, but I was starting to get dissatisfied with what it compiled. I was running Windows, and, despite everything, it’s a popular platform. However, a lot of people in the game jam weren’t, so unless they wanted to recompile from scratch (one of the conditions of the jam is releasing the source), they couldn’t play my games. What was available to almost everybody? A web browser. JavaScript was supposed to descend from Lisp, there should certainly be a way to do Lisp on the browser, right?
The answer at the time, was not so much. There were some things that looked promising, but most of them had a really high tool cost – other runtimes, other compilers, Node (shudder!) and so on. Then, finally, I found what I was looking for, almost right on my front door. Urlang is a Racket package that compiles Lisp to JavaScript. It uses all the standard Racket compiler machinery (including macros) and you can edit with the Racket IDE. My next several games, including my best ever placing, were all done this way. But I’m most proud of zode-tripper, my first one with music (working with some very talented Brazilian musicians). It was also where I first started coming to the realizations about how to architect games.
This was good for game jams and I was really excited by the expanded reach, but not so great for all-round programming. After a brief investigation of Julia, I ran across the Janet language. Janet ticked a bunch of boxes for me. It had some features, like implicit structure access, that I sorely missed from NewLisp. It had built in PEG parsing, like REBOL. And it was lightweight and you could compile an executable.
I’ve now used Janet for a number of interesting projects. Among these are bog-standard file and text transformations, an art training tool (real-time interactive interface), network utilities, device simulators and even a scientific/industrial monitoring and control tool. That last has now been released as a commercial product. One of my more recent projects was using the Janet PEG parser to build another Lisp->JavaScript transpiler.
From a forum post I made about Janet:
With multiple network connections, GUIs and long running processes, multitasking of some sort is a must. Janet provides several flavours. The simplest is a “fiber”, which is a kind of in-process green thread. Then, threads (of course), and finally actual multiple process synchronization. So far, I’ve only needed fibers, but it’s been more than enough to handle multiple data streams for simulating and controlling scientific instruments.
And compiling. If you’re on Linux (or Mac, I think), it works like falling off a log. If you’re on Windows it’s annoying (thanks Micro$oft), but still doable. It uses a two stage compilation that allows you to control what gets compiled in your source (like C macros, but much nicer). Compared to Racket (or even other scripting language compilers, e.g. Nuitka?), it produces a tiny result (1.7MB for a commercial product where I compiled in all the resources and even the user manual to a single executable).
However! I would never have gotten to Janet without NewLisp. Its simplicity, complete documentation and friendliness to an uninitiated seeker are what brought me into the Lisp fold to stay. I hope it will always remain available for others to discover. - https://newlispfanclub.com/index.php?topic=5295.msg25390#msg25390
So, that’s where I am with Lisp.
You’ve used Decker quite a bit, how have your experiences with it and been?
Although I have poked at various array languages, I am not really competent to advance any significant opinions at this point… Lil in Decker was fairly convenient to work with – I appreciated that it offered english words and a fairly conventional event-driven architecture. I really like the ideas of array languages, but I often seem to trip over their idiosyncrasies – APL, very elegant looking until you want to name your own function, etc.
However, I always regretted missing out on HyperCard from Mac (I was totally PC). I tried a couple of the various successors that would run on the PC, but they were usually disappointing. One of the big features of HyperCard was the built in drawing tools and often they didn’t have that, just telling you to use PhotoShop instead. And of course, they often had some brain-dead scripting language that was supposed to evoke HyperTalk. Decker is the first one I’ve tried that captures the magic for me – it’s small and fast, has drawing tools (you can even write scripts in Lilt to add new features). Lilt took some getting used to, but once I figured out how to persist data (in a control) it started to fall into place.
Decker may fall short of what you need for “serious” development, but for doing quick sketches or janklications it works great! I’ve used it for pixelly illustrations, GUI mockups and, of course, the odd little game. The great thing about is that you don’t have to use all of it. It’s fine as a sketchpad or little language environment to try things out.
How did you get into VFx?
I started in TV repair (remember when that was a thing?) then my high school drafting teacher recommended me to a local civil engineering company. I started old-skool with ink on mylar, but after a year or two, they got some AutoCAD stations along with some software for doing presentations. Well, of course, the first thing I wanted to do on it was make a movie…
I was pretty interested in the cinematic possibilities of computers and experimented with AutoCAD and early PC paint and slideshow programs, but I didn’t really get anywhere until I managed to get myself hired by a fledgling computer graphics firm started by a Hollywood expatriate. He’d brought his family over from California to a small industrial town in the Tennessee mountains. I just happened to be in the right place and looking for work, because I had just moved to a small industrial town in the Tennessee mountains. Funny how that worked out!
He’d brought over a chunk of surplus iron (DEC VAX 11/750 and a Silicon Graphics 3130 workstation) and set up to serve the Mexican(!) market. He was advertising for someone with art, CAD and C programming experience. I figured that two out of three wasn’t bad (I had no idea how to program in C at the time) and called him up. I took a tour through his basement facility (all the giant computers were installed in his actual house so he was working from home before “wfh” was even a thing) and I was hooked. Within a week I was working on an exploding toothbrush for a tv ad for Colgate Palmolive.
The coolest thing about VFx is that cheating is allowed. You animate “to the camera”, meaning that the only thing that counts is what the viewer sees, not how you made it happen. You can commit what would be unpardonable sins in any other discipline that valued probity and correctness. But with VFx, you’re frequently doing the impossible (a man can fly!?) under impossible time and budgetary constraints. Cheating is the law!
WRT the render farm controller, you have to remember that back in the day, being able to dynamically distribute computer jobs to disparate processors was a big hairy deal. You only needed that sort of capability if you were doing serious weather simulations, a-bomb work, or VFx. The software for this was selling for millions. But, one night, while meticulously hand feeding a collection of four computers render jobs for an IMAX project, I started thinking about how I could get the worker computers to dynamically, asynchronously pick up jobs to work on. There may have been some hallucination involved, because I was very low on sleep.
At that point, most render-farms I had seen were “command-and-control” affairs. A controlling server would contact free machines and start render jobs on them, and keep track of each one itself. This usually used a mechanism like rsh or something. It did not scale well. However, I came up with a client-server architecture where the controller machine (server) just kept a list of available jobs and clients would contact it and request something to do that matched their capabilities. I know this is so trivial today – it’s like I’m describing how to flip a power switch! – but back then, it was earth shattering, I was standing the established order on its head.
I wrote the client and server in Python (which I had recently introduced to the company). For the server, I wrote a simple Forth implementation that the clients would connect to and issue commands. The server was also a web server – the render queue was controlled by a web interface that you could connect to over the same port! At its height, it was managing around 600 machines. If you’re interested, I can talk more about it – the prioritization algorithm was amusing, for instance.
Could you talk more about the IMAX project?
So, I needed some class credits to graduate college. A friend mentioned in passing that a nearby planetarium he worked with was interested in new show ideas. Once I learned more about the planetarium, I was pretty interested too – 40 foot dome, Zeiss stellar projector, eight panorama projectors, a flying spot mirror… If I wanted to make some images big, this was the place! I talked my department heads into approving three independent studies, which coincidentally carried the remaining credits I needed to graduate.
And I earned every single credit. I had the idea that instead of being just a dry recitation of “star facts”, this would actually be a dramatic presentation. I came up with a story about a kid touring a space station. I wrote the script, directed voice actors and did over five hundred glass slides worth of 256-colour digital art (mostly drawn with a mouse). The friend who’d gotten me interested, for his sins, supplied a dynamite soundtrack, audio processing work and one of the voice actors (his son, for the main character).
The planetarium staff were very helpful and supportive – even when they had to tell me to include more star facts in the script – and we put together a nice show. There were other tribulations – a lightning strike the night before I was due to show it to my professors took out half the projectors! We had to scramble to source RS232 driver chips to get most of them working before the show. The show itself went off without a hitch. I was thrilled I managed to complete it. And it was big… Way bigger than the biggest television, more immersive than a flat movie theatre screen. I figured that would be the closest I ever got to IMAX.