Paolo Amoroso's Journal

Tech projects, hobby programming, and geeky thoughts of Paolo Amoroso

ChromeOS Stable 121 rolled out to my ASUS Chromebox 3 and brought with it a one-click option to upgrade Crostini.

Crostini, the Debian based Linux container of chromeOS, was running Bullseye prior to that. ChromeOS 121 popped up a notification with a button offering to upgrade to Debian Bookworm 12.4. After backing up the container I clicked the button in the notification, skipped the backup option as I had already done it, and clicked another button to start the upgrade.

The process was uneventful. ChromeOS displayed a dialog with status messages informing on the progress, then a final message confirming the successful completion.

I checked out the main Linux programs I use and they all seem to be working fine on Bookworm, as well as everighing else. Some programs actually look better as they're built on GUI frameworks that come with an updated and refreshed design.

Upgrading Crostini from Buster to Bullseye a couple of yeas earlier was less smooth. Back then chromeOS didn't provide any user interface for activating the upgrade, so I had to manually run a script. Although the process completed with a few errors, Bullseye has always worked fine on Crostini since then.

#chromeOS #Linux

Discuss... Email | Reply @amoroso@fosstodon.org

Managing Lisp code in the residential environment of Medley differs from similar tasks in traditional file based Common Lisp systems.

In a previous post I explained how the residential environment of Medley works, discussed some of its facilities and tools, and introduced a workflow for managing Common Lisp code under the residential environment. This leverages the way Medley is designed to work and minimizes friction.

In this post I explain how to use Medley as a file based environment, albeit with some friction and reduced functionality.

I show how to edit, organize, and load pure Common Lisp files, i.e. source files not under the control of the File Manager. Pure files are ordinary text files that contain only Common Lisp code, with no metadata or font control commands like the code databases the File Manager maintains.

Motivation

Letting the residential environment track and control code is the most convenient and productive way of using Medley for Lisp development.

But you can still manually manage pure Common Lisp files. For example, you may want to use from Medley some code you mainly intend to load into the environment and don't change often. This is the case of external libraries and programs developed elsewhere, which you call from new code or run in Medley.

Using Common Lisp code not developed for the pre ANSI implementation of Medley may need adaptation. So let's see how to edit source files.

Editing source files

To create or modify pure Common Lisp files use the TEdit word processor of Medley, not the SEdit structure editor. SEdit doesn't directly manipulate the arbitrary, unstructured text of pure files.

TEdit can read and write ordinary text files, but not by default. To save a file as ASCII execute the command Put > Plain-Text. Execute Get > Unformatted Get to load such a file.

The main downside of using TEdit for Common Lisp is the program is not Lisp aware. It doesn't support automatic indentation, prettyprinting, perenthesis matching, and code evaluation. Another major problem is cursor keys don't work in Medley, which severely limits text editing with TEdit. The Medley team is well aware of the issue.

An alternative is to use your favorite Lisp editor to edit the Common Lisp sources outside of Medley and then load the files from Medley.

Format of Pure Common Lisp files

Although Medley can load pure Common Lisp sources, these files do have some minimal formatting requirements. A pure Common Lisp file must begin with a semicolon ; character, otherwise the system assumes it's an Interlisp file.

Other than that a pure file can contain any Common Lisp feature Medley supports, in any order the language allows.

Loading source files

Once a pure Lisp file is available, load it in Medley with the usual file loading forms such as CL:LOAD. The way symbols are interned depends on whether the file defines or makes current any Common Lisp packages.

Let's go over the main cases: the code has no packages; a single file contains both package and function definitions; the code is split between a file for the package and another for the function definitions.

No package definition

The simplest type of pure file contains no package forms, just function definitions and other Common Lisp expressions.

In this case Medley interns symbols in the USER package without exporting them. The Medley implementation of Common Lisp is closer to CLtLx than ANSI, so it provides the standardized packages LISP (nicknames: COMMON-LISP and CL) and USER instead of COMMON-LISP and COMMON-LISP-USER.

For example, suppose this file SQUARE.LISP defines a function calc-square to compute the square of its argument:

;;; SQUARE.LISP

(defun calc-square (x)
  "Return the square of X."
  (* x x))

After evaluating (load "SQUARE.LISP"), at the > prompt of a Common Lisp Exec you call the function using the proper package qualifier:

> (user::square 3)
9

If the USER package isn't adequate for your code, on Medley CL:LOAD also accepts the keyword parameter :package to supply a package to which *package* is bound when reading the file. For example, at the > prompt of a Xerox Common Lisp (XCL) Exec you can pass the package XCL-USER with a form like:

> (load "SQUARE.LISP" :package (find-package "XCL-USER"))

You must pass an actual package object to :package, not a package designator like :xcl-user.

Since XCL-USER is the default package of XCL Execs no qualifier is required for calling the function:

> (square 3)
9

Package and definitions in one file

Not using packages may be adequate for very small files. However, typical Common Lisp programs do define their own packages.

This example file PKGDEMO.LISP defines the package PKGDEMO with nickname PD that exports the function FUN, which just prints a message:

;;; PKGDEMO.LISP


(in-package "XCL-USER")

(defpackage "PKGDEMO"
  (:use "LISP" "XCL")
  (:nicknames "PD")
  (:export "FUN"))


(in-package "PKGDEMO")

(defun fun ()
  (format t "Hello from PKGDEMO:FUN."))

The file holds both the package definition and the rest of the code. It's important that the first form in the file be in-package to make current a known package like XCL-USER. XCL-USER is the Medley equivalent of COMMON-LISP-USER and uses the LISP package with the standard Common Lisp symbols.

After loading PKGDEMO.LISP from an XCL Exec with (load "PKGDEMO.LISP") you can call the exported function like this:

> (pkgdemo:fun)
Hello from PKGDEMO:FUN.
NIL

or via the package nickname:

> (pd:fun)
Hello from PKGDEMO:FUN.
NIL

Separate package and definition files

Unlike PKGDEMO.LISP in the previous example, most Common Lisp programs split the code between at least two files, one holding the package definition and the other the function definitions. Let's rewrite PKGDEMO.LISP by storing the package in the file PKGSPLIT-PKG.LISP:

;;; PKGSPLIT-PKG.LISP


(in-package "XCL-USER")

(defpackage "PKGDEMO"
  (:use "LISP" "XCL")
  (:nicknames "PD")
  (:export "FUN"))

The function definition goes into the file PKGSPLIT-FUN.LISP that begins with an appropriate in-package followed by the rest of the code:

;;; PKGSPLIT-FUN.LISP


(in-package "PKGDEMO")

(defun fun ()
  (format t "Hello from PKGDEMO:FUN."))

Finally, make sure to load the package first with (load "PKGSPLIT-PKG.LISP"), then the function with (load "PKGSPLIT-FUN.LISP"). Loading the files creates the same objects as the single file example PKGDEMO.LISP and you can call the function the same way:

> (pkgdemo:fun)
Hello from PKGDEMO:FUN.
NIL
> (pd:fun)
Hello from PKGDEMO:FUN.
NIL

#CommonLisp #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

One of the cool features of Lisp is examining and modifying a running program.

This allows, for example, to correct a bug by inspecting, editing, fixing, and resuming a program that breaks and lands in the debugger because of an error. To gain familiarity with the process, I recorded a screencast of a Medley session in which I use the debugger to fix a bug in a running Interlisp function and conclude the computation.

Medley provides advanced debugging facilities and tools in the Break Package, including the Break Window which is the main user interface of the debugger. “Package” as in module or subsystem, not Common Lisp package.

In the recorded session I fix this broken Interlisp function to compute the square of the argument:

(DEFINEQ (CALC.SQUARE (X)
  (* Return the square of argument X.)
  (TIMES X Y)))

The bug is trivial, a typo. The call to the TIMES multiplication operator passes Y as the second argument instead of the function parameter X.

I begin the recorded session by defining the function with the SEdit Lisp editor. Next, from the Exec (a Lisp REPL) I call the function (CALC.SQUARE 3) and get the error Y is an unbound variable. Then I execute the RETRY Exec command. RETRY evaluates the latest expression and forces entering the debugger if it yields an error.

The topomost few backtrace entries in the Break Window are internal functions called by CALC.SQUARE. From the Break Window's middle-click menu I invoke the REVERT command to move the point of execution back to the CALC.SQUARE call before the error.

This selects the CALC.SQUARE frame where the bug is most likely to be. Inspecting the bindings of the frame provides a clue.

X has the expected value 3 and I confirm it by evaluating X at the debugger REPL. But Y, the variable the error references, doesn't show up in the stack frame. Evaluating Y yields the same error. It's a hint Y shouldn't probably be there and is likely a typo. Therefore, I execute the debugger's EDIT command to open the code of the current function in SEdit. From SEdit I fix the typo and evaluate the modified definition.

The new definition is now in the Lisp image and the current stack frame is still the CALC.SQUARE call in the backtrace. The OK debugger command continues execution from the point of the break, letting the program run the corrected code. The Exec from which I originally called the buggy function finally returns the expected value of the square of 3: 9.

The REVERT, EDIT, and OK commands may be typed at the debugger REPL but I invoked them from the menu to make the menu itself and its options explicit. Similarly, the Done & Close SEdit menu command has the associated keychord C-M-x.

#Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

My exploration of Medley as a Common Lisp development environment proceeds with setting up a workflow for writing and saving code.

The workflow consists of a series of steps in a specific order using appropriate Lisp REPLs and tools. It supports writing the simplest type of Common Lisp software, i.e. programs or libraries in a single package that exports some symbols. I'll eventually extend the workflow to more complex cases such as programs with more than one package.

Since the steps are not intuitive, especially for Medley novices, in this post I'll describe the workflow in detail. But first there are a few concepts to introduce.

Why do you need a workflow in the first place? Because the differences between Medley and modern environments constrain how and in what order Common Lisp code may be written and managed. Before examining the constraints let's describe the differences.

The residential environment of Medley

Writing single package programs is straightforward in modern file based Common Lisp environments. In a new file you just define the package with DEFPACKAGE, then in the rest of the file or at the top of a new one you place a matching IN-PACKAGE followed by the code.

Although it's technically possible to do the same in Medley this doesn't take advantage of its facilities, and you may actually need to fight the system to accomplish what you want. Indeed, Medley is not an ordinary environment. Not only it predates current Common Lisp implementations, it supports a different development process.

In file based Common Lisps you directly edit source files and evaluate or load the code into the running Lisp image.

Medley instead is a “residential environment” in which you edit and evaluate Lisp objects that reside in the image — hence “residential”. Then you save the code to files that are more like code databases than traditional source files.

You don't edit the code databases, which Medley calls “symbolic files”. Rather, you use the SEdit structure editor to modify the code in memory and the “File Manager” to save the code to disk. The beginning of a symbolic file defines metadata, the “file environment”, which describes the Common Lisp package and readtable associated with the code.

The File Manager, also known as “File Package” (not to be confused with Common Lisp packages), is a facility that coordinates the development tools and code management tasks. It notices the changes to Lisp objects edited with SEdit or manipulated in memory, tracks what changed functions and objects need to be saved to symbolic files, and carries out the actions for building programs such as compiling or listing them. The File Manager has some of the functionality of Unix Make.

Figuring what changed is easy in modern Common Lisp environments, as you know which files you edited and need action like saving or compiling. System definition tools like ASDF can track this for you. In Medley it's the File Manager which tracks the changes that take place in the running image and need to be synchronized to disk.

Motivation

How do the peculiarities of Medley constrain writing Common Lisp code and require a tailored workflow?

The functions and objects of Interlisp programs usually live in the same namespace of Interlisp and its tools. As a consequence, functions and Lisp objects may be mostly defined in any order and accessed without package qualifiers. No special handling is necessary with the File Manager either.

With Common Lisp code, however, a subtle complication arises due to packages and exported symbols.

A good explanation of why things are different, and how the File Manager and file environment interact, is in the documentation of TextModules, a tool for importing Common Lisp code created outside of Medley. Although in the context of TextModules, these remarks give an overview of the same issues the File Manager faces with other Common Lisp code. The TextModules chapter of the Lisp Library Modules manual says on page 311 (page 341 of the PDF):

It is important to separate the environment of the file from its contents because the File Manager (not TextModules) first reads all the forms in the file, and then evaluates them. Text based source files sometimes change the package as needed. This cannot work for the File Manager since the file's forms are all read and then executed, i.e. the package changes would not occur until after the entire file had been read, and forms after any IN-PACKAGE form would have been read incorrectly.

In other words, unless you define packages and access symbols in the proper order, you'll get subtle errors. The solution is a workflow that avoids such errors.

More information on dealing with packages in Medley is in the sources referenced in section “Documentation” of my post on using Common Lisp on Medley.

The workflow

How does the workflow order the development tasks to achieve its goal?

At any one time the workflow accesses only defined symbols and ensures the running Lisp image stays synchronized with the symbolic file. It's not the only or the best possible workflow, just one that works. I put it together after extensively reading the documentation and experimenting.

As I said in the overview of Medley as a Common Lisp environment, when coding in Common Lisp I use two Executives (Lisp REPLs), a Xerox Common Lisp (XCL) Exec and an Interlisp one.

The former is for testing, running, and evaluating Common Lisp code. I use the Interlisp Exec for running system tools and interacting with the File Manager. Since the tools and File Manager facilities are in the Interlisp package, referencing them from a Common Lisp Exec would require qualifying all symbols with the IL: package.

What follows assume you're familiar with basic Interlisp and File Manager features such as SEdit, file coms, FILES?, and MAKEFILE. If not I recommend reading the Medley primer, particulary Chapter 7 “Editing and Saving”. Also, unless otherwise noted, you should carry out the steps in sequence in the same Medley session.

Let's start.

Defining the file environment and a minimal package

Suppose you want to write a Common Lisp program or library stored in the file SINGLEPKG. The package SINGLEPKG, nicknamed SP, will export the two functions FUN1 and FUN2.

From now on, denotes the prompt of an Interlisp Exec and > that of a Xerox Common Lisp (XCL) Exec. Sometimes I'll tell you in which Exec to evaluate expressions.

The first step is to define the file environment. At an Interlisp Exec evaluate:

← (XCL:DEFINE-FILE-ENVIRONMENT SINGLEPKG :PACKAGE (DEFPACKAGE "SINGLEPKG" (:USE "LISP" "XCL")) :READTABLE "XCL")

For now don't use other packages or export any symbols, just enter the form as is.

Although the file environment references package SINGLEPKG, the package doesn't exist yet in the running image. To synchronize the image with the file environment evaluate the definition of a minimal package from an Interlisp Exec:

← (DEFPACKAGE "SINGLEPKG" (:USE "LISP" "XCL"))

Next, from an Interlisp Exec evaluate (FILES?) and, when asked where the SINGLEPKG file info should go, respond yes, enter SINGLEPKG as the file name, and confirm the creation of the file.

Defining the first function

Everything is ready to define the first function FUN1. At an Interlisp Exec call SEdit with (ED 'SINGLEPKG::FUN1 '(FUNCTIONS :DONTWAIT)) and select DEFUN from the menu. Enter the code of FUN1:

(DEFUN FUN1 ()
  (FORMAT T "Hello from FUN1."))

Save and exit with Ctrl-Meta-X and test the function at an XCL Exec (an Interlisp Exec will do too):

> (SINGLEPKG::FUN1)
Hello from FUN1.
NIL

It works, so at an Interlisp Exec evaluate (FILES?) to associate FUN1 with the file SINGLEPKG.

Completing the package definition

The Lisp image contains the new symbol FUN1 in package SINGLEPKG but there's no symbolic file yet, let alone an exported symbol in the file. Therefore, to keep things in sync you need to update the package definition by exporting the function name. This is also an opportunity for adding the SP nickname to the package.

At an Interlisp Exec evaluate (DC SINGLEPKG) to open the file coms in SEdit. Just after the XCL:FILE-ENVIRONMENTS form enter:

(P (DEFPACKAGE "SINGLEPKG"
     (:USE "LISP" "XCL")
     (:NICKNAMES "SP")
     (:EXPORT SINGLEPKG::FUN1)))

Both colon characters : are required in the function name. The P File Manager command tells the system to execute the following Lisp expressions at load time, so loading SINGLEPKG will define the package and export the symbol.

Save and exit with Ctrl-Meta-X and, at an Interlisp Exec, save the file with (MAKEFILE 'SINGLEPKG) to reflect the updated definitions. This creates the file SINGLEPKG on disk.

Before doing anything else it's better to make sure the package is properly defined and the function exported.

The most reliable way is to exit the Medley session with (IL:LOGOUT), start a new session and, from an Interlisp Exec, evaluate (LOAD 'SINGLEPKG). If there are errors you will have to go back and check whether you went through all the steps correctly. You may need to delete the latest or all versions of the file SINGLEPKG.

Assuming there are no errors the package is properly defined and the function exported. To double check, from an XCL Exec call the exported function like this:

> (SINGLEPKG:FUN1)
Hello from FUN1.
NIL

Since it works you may proceed development by editing the existing function or defining new ones. In the former case you employ SEdit, FILES?, and MAKEFILE as usual. Just make sure to pass to ED the package-qualified function name like (ED 'SINGLEPKG:FUN1 :DONTWAIT).

Things change if you want to define new functions.

Defining more functions

As planned you proceed to define a second function FUN2 exported from package SINGLEPKG. If you're still in the Medley session in which you've just loaded the file SINGLEPKG, continue from there. Otherwise start a new session and load the file with (LOAD 'SINGLEPKG) from any Exec.

At an Interlisp Exec define the new function with (ED 'SINGLEPKG::FUN2 '(FUNCTIONS :DONTWAIT)) and select DEFUN from the menu:

(DEFUN FUN2 ()
  (FORMAT T "Hello from FUN2."))

Save and exit with Ctrl-Meta-X and test the function at an XCL Exec:

> (SINGLEPKG::FUN2)
Hello from FUN2.
NIL

Call FILES? to associated FUN2 with file SINGLEPKG.

As already done for FUN1 you need to modify the package definition to export the new function. At an Interlisp Exec edit the file coms with (DC SINGLEPKG) and add the symbol FUN2 to the export clause, which will now look like this:

(P (DEFPACKAGE "SINGLEPKG"
     (:USE "LISP" "XCL")
     (:NICKNAMES "SP")
     (:EXPORT SINGLEPKG:FUN1 SINGLEPKG::FUN2)))

SEdit replaced the double colon of SINGLEPKG::FUN1 with a single colon as in SINGLEPKG:FUN1. But you still have to type :: for FUN2 because FUN2 hasn't been exported yet.

Save and exit with Ctrl-Meta-X and, at an Interlisp Exec, save the file with (MAKEFILE 'SINGLEPKG).

To synchronize the Lisp image with the symbolic file, which will allow to call the exported function as (SINGLEPKG:FUN2), either load the file SINGLEPKG from a fresh session or, just after editing the file coms, evaluate a revised package definition at an Interlisp Exec:

← (DEFPACKAGE "SINGLEPKG"
    (:USE "LISP" "XCL")
    (:NICKNAMES "SP")
    (:EXPORT SINGLEPKG::FUN1 SINGLEPKG::FUN2))

Either way, to check that everything works evaluate at an XCL Exec:

> (SINGLEPKG:FUN2)
Hello from FUN2.
NIL

Success!

For every new function or Lisp object you want to export from the package, go through the steps of this section again, making sure the Lisp image and the symbolic file stay synchronized. The steps are, in order:

  1. edit the new function
  2. call FILES? to tell the File Manager about the function
  3. edit the file coms to update the package
  4. save the file with MAKEFILE
  5. evaluate the revised package definition

That's all, you're finally ready to develop single package programs. This workflow may seem convoluted at first but things will come more natural as you gain experience with Medley.

#CommonLisp #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

Now that I'm back to Lisp I'm actively exploring Interlisp as a Common Lisp environment too.

But to code in Common Lisp also on my Crostini Linux system, the Linux container of chromeOS I use on a Chromebox, I'm setting up a suitable development environment. In addition to console programs I want to write GUI applications with McCLIM.

The Common Lisp implementation I chose, SBCL, is a no brainer given its features, performance, and active maintenance. As for the development environment I won't go with the default on Linux, Emacs. Although I used Emacs for years and loved it, now it feels overkill and I'd prefer not to re-learn its intricacies.

Instead I'm using Lem, a great Emacs-like IDE written in Common Lisp with a user interface and keybindings similar to those of Emacs and SLIME. Thus my familiarity with Emacs is enough to get me up to speed. A nice side effect of Lem's implementation language is the IDE can be configured and extended in Common Lisp, which I feel more at home with than Emacs Lisp.

Despite some initial installation issues Lem works well on Crostini, is fast, and has a nice SDL2 backend. I really like the IDE.

If I need to write or run some Common Lisp code on my Raspberry Pi 400 I can easily replicate this setup there.

#CommonLisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

Forty years ago these days, in November of 1983, my book Saturno: nubi, anelli e lune was released by the small Italian publisher Italy Press. Early that year I had started writing this astronomy book about the planet Saturn.

The paperback book "Saturno: nubi, anelli e lune" (Saturn: clouds, rings, and moons) by Paolo Amoroso, Italy Press, 1983.

Such a traditional publishing deal, my first and only one, was a stroke of luck.

While most debut writers collect dozens or hundreds of rejections before landing a deal, I got mine easily at the first try. I was a kid almost old enough to sign a contract and, when I pitched the idea, the publisher agreed with no objections. What's even more remarkable is the publisher trusted not just one kid at his first book writing experience, but four.

Along with three friends of similar age we pitched the idea of a series of astronomy books. I picked the one on Saturn and my friends did the others.

The book proved a success as the print run of 4,000 copies was distributed throughout Italy and sold well. It earned me roughly one fifth of what top science writers were paid for for similar work at the time.

#publishing #books #astronomy

Discuss... Email | Reply @amoroso@fosstodon.org

A few days ago I blogged on why I cancelled my paid plan to Replit.

It was a short personal note to record my decision as I often do to document my experiences with tools and products, possibly of interest to the few dozen regulars per day who read my blog.

A day on the home page of Hacker News, over 170 votes, almost 150 comments, and nearly 20,000 views later, it became clear I underestimated the impact of the post. I should have expected mixing parting ways with a product by a red hot startup like Replit, and a red hot technology like AI, could generate some attention.

The discussion in the comments on Hacker News is pretty interesting and I can't do more than reply to a few. But I'd like to address a couple of issues raised in the comments.

Some readers wondered whether I feel entitled to great products at little or no cost, thus making it difficult for companies to survive and innovate. I'd actually be happy to pay for Replit at the new higher price. But my shift to Lisp, and the diverging direction of Replit's evolution, widen a gap between cost and benefits that reduces the value of Replit to me, possibly even at the old lower price.

Others pointed out I'm a niche user while Replit caters to an audience of mainstream developers with different needs. This is true. Replit's features make it a great value for those users such as web developers. For example, deploying a web app by just listening to a port is beyond magical. But this is not what I need.

Replit cofounder Faris Masad also read my post and invited me to a video call. He gave me the opportunity — thanks! — to elaborate on the issues raised in the post and share my feedback on what Replit is missing for Lisp. Faris listened carefully, as he said improving Lisp support can improve the experience also with other languages.

This conversation and the other feedback convinced me to follow more closely the evolution of Replit and reevaluate my decision.

#development #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I cancelled my annual Replit Hacker plan and I'll let it lapse at the end of December of 2023.

Replit is a popular and growing multi language development environment in the cloud. I've been subscribing to the Hacker plan for the past few years and it worked well for my Python projects, as such an online environment is a good match for my chromeOS lifestyle. But two changes made me reconsider the value of the product.

The first is Replit changed its paid tiers by raising the price of my plan and removing some features. I actually saw it coming when Replit began receiving massive funding by major investors, who are likely pressuring the company to reduce costs and turn profits. Still, this left a sour taste as it felt like a bait and switch.

The other change is my shift of focus back to Lisp, the programming language I love most and know best.

Replit doesn't work well with a highly interactive language like Lisp. It doesn't directly support any Lisp dialects and its default code editor provides little or no integration with a running Lisp image. Moreover, the files created or uploaded outside of the editor are often not preserved across sessions. If I have to install and maintain a full Lisp system in the Linux shell of a Replit workspace, I might as well install it locally on my desktop computer.

Finally, like other development tool vendors, Replit is doubling down on AI coding features which affect the cost of paid plans. But I'm not interested in this as the whole point of my hobby programming is to write all the code myself and learn from the experience.

Update

This post was shared on Hacker News and I blogged about the reactions.

#development #Python #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

Medley is the first Lisp system I experimented with on my new Raspberry Pi 400, here is the AArch64 version on the Raspberry Pi OS desktop:

SDL version of Medley Interlisp on a Raspberry Pi 400 under Raspberry Pi OS.

The online version of Medley runs well and smoothly enough in Chromium. There are no major or unexpected performance differences between the Pi 400 and my Chromebox.

But the AArch64 .deb package of the prebuilt Medley distribution is really, really slow on the Pi 400. For example, when launching the program I can see the characters being printed one by one to the Exec window. The problem is the AArch64 release is built for X-Windows, which on the Wayland based Raspberry Pi OS Bookworm goes through Xwayland with degraded performance.

Therefore I built from source the SDL version of Medley that doesn't rely on X-Windows.

Building everything, i.e. compiling Maiko and making the loadups, takes less than five minutes on the Pi 400. Although the process is simple, it took me some trial and error to figure the exact steps from the limited documentation. Nick Briggs helped me troubleshoot the build and advised on how to create a missing makefile.

The SDL version is snappier than the default AArch64 Debian package. Now Medley starts up almost instantly. The only inconvenience common to both versions is they don't recognize my Italian keyboard as they work only with the English US layout.

#Interlisp #pi400

Discuss... Email | Reply @amoroso@fosstodon.org

I bought a lovely little computer, a Raspberry Pi 400, and two accessories, a 64 GB Samsung Pro Endurance microSD card to hold the file system and a very cheap Full HD webcam for video calls.

Raspberry Pi 400, Samsung Pro Endurance 64 GB microSD card, and Full HD webcam product boxes.

I always wanted a Raspberry computer but assumed the components and cables would take up too much space at my work station.

Recently though I carefully inspected the layout of my desk, the HDMI ports of my HP Pavillon 23cw monitor, and the nearby electrical sockets. Researching the Raspberry Pi 400 convinced me I could set the device on the desk with minimal inconvenience and little space.

This is not a full review but a collection of early impressions and usage notes after working with the device for a week.

Motivations

Although I have possible uses for the Pi 400, one of the reasons why I got it is not technical: the computer has a delightful form factor.

My daily driver, an ASUS Chromebox 3, is a high end desktop system. But the opportunity of using a different device with a nice form factor is a welcome and refreshing context switch that helps productivity and makes things fun. It's like writers spending time at Starbucks to get some work done instead of sitting and typing at their desk at home.

Another reason for getting the Pi 400 is I always loved Linux. Since switching to chromeOS in 2015 I've been thinking of how to set up a Linux box as a secondary computer within the constraints of my work station. The Pi 400 finally enabled this possibility.

Another major consideration that drew me to the Pi 400 is it's a full, native Linux system specifically designed as a combination of hardware and software to run Linux. Raspberry Pi OS is tightly integrated with the hardware and well supported, which will hopefully spare me the nightmares of Linux updates frequently breaking X-Windows back in the day.

Finally, I wanted a computer for experimenting with various computing technologies, such as ARM on the desktop. And, of course, I wanted an extra computer to play with Medley and other Lisp systems.

The Pi 400 is a member of the Raspberry family at the heart of countless electronics and IoT projects. But, since I'm not a hardware guy, I'll use it mostly as a desktop productivity and software development environment.

Reviews

I extensively researched the Pi 400 and a key theme of what I learned is performance.

The reviews describe and evaluate performance through a wide range of experiences that doesn't make it easy to figure what to expect. Perhaps because the specs place the device at a spot of the performance spectrum along the transition between realizing responsiveness is suboptimal, and not noticing anything unusual about the way the system reacts.

Therefore, given the affordable price, I accepted the small risk of disappointment and went with the Pi 400.

What I think the reviews don't highlight enough is that, even at the lower end of the performance spectrum, Raspberry absolutely nailed the combination of form factor and price of the Pi 400. It sits at a local maximum in the product space that delivers tremendous value for the money.

Hardware

The Italian keyboard of my Pi 400, which makes up the entire device, has nearly the same size as the TedGen keyboard of my Chromebox. The keys of the Pi 400 are actually slightly larger than those of the TedGen and support well my typing speed, which is not much.

I feel at ease with the Pi 400 keyboard because I prefer short-travel chicklet units. The plastic feel and feedback aren't an issue for me as, again, the mechanics and build don't interfere with my relatively slow typing.

Although not as smooth and precise as the Logitech mouse of my Chromebox, the Pi 400 one is acceptable despite the occasional lower than average responsiveness.

The Pi 400 instantly recognized the new Full HD webcam as well as my Mixcoder E9 Bluetooth headphones and Brother HL-L2340DW wireless printer. The webcam delivers a smooth feed with Google Meet and good image quality for the price.

Software

I've been using Unix since the early 1990s and Linux since the mid 1990s, so the Raspberry Pi OS desktop and system look mostly familiar.

I personalized the desktop environment to make it look similar to my Chromebox. I set a similar background color, moved the taskbar to the botton like the chromeOS shelf, and set Chromium as the default browser with a matching tab layout.

This is what my Raspberry Pi OS desktop looks like:

Raspberry Pi OS desktop on a Raspberry Pi 400.

Since my daily driver on the desktop is a Chromebox I mostly live in the browser, with a number of tabs often open on Google products. On the Pi 400 Chromium works well enough with Google web apps. But I can't synchronize my extensions and settings with chromeOS as Google removed the functionality from Chromium.

Although most of the programs I need are available, I haven't found an easy to install screencasting tool with Wayland support.

Usage

I don't leave the Pi 400 permanently on the desk but set it up on demand.

Whenever I need the device I bring it out, set it on the desk, and connect the cables. One of the cables goes into the HP monitor which the Pi 400 shares with the Chromebox. I can use either computer by switching the monitor input signal with a button.

The only Ethernet wall socket close to the desk is permanently hooked to the Chromebox. The Pi 400 accesses the network over Wi-Fi at up to 70-80 Mbps.

Setup and configuration

To initially set up the Pi 400 I connected it to the Ethernet socket so the required large file downloads and system updates could go faster.

For installing the operating system on the microSD card I originally planned to run the Raspberry Pi Imager tool on my Chromebox under the Debian based Crostini Linux. But, although Raspberry Pi OS is derived from Debian, the only binaries of such an essential tool are available only for Ubuntu. Raspberry does provide instructions for building a package for Debian but network installation on the Pi 400 seemed simpler.

I selected the 64-bit version of Raspberry Pi OS Bookworm desktop and recommended software.

Despite the simplicity of the process, which can complete in less than a quarter of an hour, it took me three reinstallations and a couple of hours because of a subtle Raspberry Pi Imager bug.

I also configured SSH and headless access to the Pi 400 from my Chromebox with the recommended VNC client TigerVNC, the only one that supports Wayland on Raspberry Pi OS Bookworm. But the Pi 400 is just too slow and laggy over VNC with my setup, which makes it viable in a pinch.

Performance

The Pi 400 is no gaming rig but delivers enough performance for most ordinary tasks without the feel of constant wait and lag.

This supports well the kinds of tasks I ordinarily carry out such as running a browser with half a dozen tabs, a terminal, and another program or two. I don't consume much media.

The most noticeable manifestation of performance limitations is that programs don't start up instantaneously. For example, Chromium comes up in about 4 seconds. But once programs start, they run with mostly instantaneous responsiveness for common tasks.

YouTube streams consistently smoothly over Wi-Fi at 1080p and full screen, but entering or leaving full screen mode freezes the browser for a few seconds.

I don't mind the overall experience as I'm used to systems with similar architecture like cheap Android tablets and Chromebooks. The Pi 400 actually feels snappier than my Lenovo Yoga N26 Chromebook.

Although not architecturally similar to the Pi 400, the 8-bit single board computers I use for my retrocomputing projects, such as the Z80-MBC2, deliver a comparable feel that's part of the expected experience.

Speaking of retrocomputing, one the reason I got the Pi 400 is to run Medley, other historical Lisp systems, and emulated classic computers at a level of performance closer to the originals. Running Medley on powerful desktop systems or in the cloud is much faster, thus limiting the appreciation of certain design decisions, features, or workflows the systems imposed back in the day.

The more I use the Pi 400, the more the perception of not operating a powerful computer is fading away as I focus on the tasks I use it for.

An example can express and synthesize this perception. As I said earlier, I configured the desktop environment of the Pi 400 to look similar to that of my Chromebox. The Pi 400 often feels so smooth I forget I'm not on the Chromebox.

Conclusions

it's been a week since I unboxed the Pi 400 and I love it.

The product has the perfect combination of features, form factor, and price for my needs. This surprisingly capable little computer is one of the rare lovely products that encourage to use it, be productive, and have fun.

#pi400 #linux

Discuss... Email | Reply @amoroso@fosstodon.org

Enter your email to subscribe to updates.