December 22, 2024 1:43 PM
"Printer's Error" Numbers
35 · 1482 · 9760 = 3514829760
This is known as a printer's error. If the typesetter misses the superscripts in a printer's error, the value printed is still correct.
This page lists all kinds of printer's errors, including generalizations across bases, shifting digits, and the like. Much fun.
Hat tip to Futility Closet, which I am happy to have active again in my newsreader after a one-year hiatus back in 2022-2023.
December 06, 2024 1:54 PM
The Google Vision API Gets Me
Someone on Mastodon posted a link to They see your photos. According to the site, Your photos reveal a lot of private information. To demonstrate this, the author uses the Google Vision API to describe the content of any photo you upload.
I was curious. I uploaded the professional headshot I use on my relatively new home page (*). There doesn't seem to be any negative implication in using this photo for an experiment, as it is already out on the public web and available for anyone, or any program, to see.
Here's the image:
What do you see when you look at that image? Here's what Google Vision had to say:
The image shows a headshot of a person against a plain white background. The foreground is dominated by the individual, who is the clear focal point. The background is simple and uncluttered, drawing all attention to the subject. The overall setting appears to be a professional portrait studio or a similar controlled environment.
The person in the image is a middle-aged man with light skin, appearing to be of European descent. He wears glasses and a light blue polo shirt. He seems friendly and approachable, with a gentle smile. His expression suggests confidence and approachability. The image seems to be taken in the daytime judging by the lighting, likely for professional purposes such as a LinkedIn profile picture or corporate directory. The camera used appears to be a high-quality DSLR or professional-grade camera, considering the sharp focus and detail.
The slight greying at the temples of his hair and fine lines around his eyes subtly indicate his age and perhaps his professional experience. The simple yet neat background and his attire are consistent with someone who holds a professional position, suggesting a stable economic status and a mature, possibly traditional lifestyle. The image shows no additional objects or accessories, keeping the focus entirely on the person.
Wow. It is not wrong.
I would be happy for someone who sees that image, or who meets me in person, to think "He seems friendly and approachable, with a gentle smile. His expression suggests confidence and approachability." Friendly and approachable are certainly attributes I would like for others to see in me, both professionally and personally. I'd also like to project a humble confidence.
Is it wrong for me to feel flattered by the assessment of a piece of software? I can only hope that people see me the way Google's image processor says they might.
~~~~~
(*) I created this home page last summer while preparing for my second offering of our web development course. Four months old isn't particularly new, but it seems quite new when compared to the thirty-year run of my previous home page, which had changed only in dribbles over its lifetime.
November 30, 2024 8:49 PM
A December Adventure
This is the time of year when many people in my world are gearing up for Advent of Code, an annual communal celebration of daily programming challenges that begins on December 1 and ends on Christmas. Many folks use the event as an opportunity to learn or practice a new language. If you are truly impressive, you solve each day's puzzle in a different language, as Matt Might did in 2022.
Advent of Code looks like a lot of fun, but I have never fully participated. Some years, I drop in for the first day or two, solving the problems in a familiar language, like Racket or Python. Those early problems sometimes make useful examples when teaching functional programming in my spring course. I mentioned one such case back in 2016, when I turned Matthew Butterick's solution to one of the 2015 problems into an extended homework assignment.
However, early December constitutes the last two weeks of semester of our fall semester, which is followed by finals week, undergrad research presentations, and grading. I don't want to have to carve out an hour or more each day for three and a half weeks to work on these problems, no matter how much fun they might be. That feels like too much pressure, and just another kind of work.
Maybe that's why I was so pleased to read about December Adventure, a lower-key community programming event with a simple goal: to write a little code every day of the month. Now, I write code most every day for class or for work, so for me December Adventure is about taking at least a few free minutes each day to program for my own purposes.
Last week, before I read about December Adventure, I took an
unintentional test drive of the idea. I recently discovered
Alex Chan's blog
and read about
their adventure writing emptydir
.
This is a script that deletes all directories that are essentially
empty: they contain only files we don't care about, such as stray
__pycache__
and .venv
files or, on Macs,
the ubiquitous .DS_Store
.
emptydir
solves a problem I have all the time. Git
tracks files, not directories, and when I sync repos across my two
main machines, files sometimes get moved or deleted. The directory
that once contained them is now empty... except for
.DS_Store
. So macOS keeps the directory, even though
for my purposes it is now empty.
This is the complement of a problem I mentioned
in September,
in which directories I create on one machine do not get synced by a
a git push or pull because they are empty. To solve that problem,
I wrote a script called touch-empty
that leaves a
0-byte file git will track for me, keeping the folder alive.
Anyway, Chan's Rust program was the prompt I needed to write
rm-empty
, my own version of emptydir
. I
skimmed their Rust code and then put my own twist on the idea in
Python. It came together quickly, in programming bursts of a few
minutes each over three nights. The code itself wasn't too bad,
though I had to learn a bit more about the os.walk
function to make it work the way I wanted. However, as you might
imagine, testing a program that deletes folders and files calls for
extra attention!
I had fun writing rm-empty
, and December Adventure
gives me a chance to extend of the mood. I'll cobble together a
few minutes each day to write code that I want to write, only
because I want to write it.
Rather than noodle around with no higher focus, I'm going to write a little app I've been obsessed with since I read about it earlier in the month on Mastodon:
Recently I've started listening to my music library using an app I call "an html file in the root directory of my music library, which is regenerated using a shell script, consists of a js searchable/sortable table of all the tracks, and switches the content of an audio embed at the top". Honestly, it's better than quite a few of the so-called apps out there.
Of course, I've been writing JavaScript this semester in my client-side web development course, so this piques my interest in two directions: learning a little more JS, and polishing my HTML and CSS skills in an app where I myself care about the look and feel. Who says the world doesn't need an in-browser replacement for iTunes? And even if it doesn't, I might be happy to run my own app in its stead.
The goal of my December Adventure is to keep expectations low and have fun. I'm not going to place any demands on the exercise, other than to spend at least a few minutes each day working on the project. If all I can manage is a new test case one day, or a quick bug fix, that's fine. If I can set aside more time for design or implementation, that too will be fine.
If I end up creating an app that pleases me enough to use on a daily basis, great. If instead I get to the end of the month and don't have a functional page yet, that will be okay, too. I will have had thirty-one days of fun working on it. I can decide then whether I want to keep working on it. With any luck, the fun is habit-forming and I stick with the daily recreational coding, whatever the target.
I'm also using December Adventure as a blogging prompt. I've been wanting to write a post or three all month... but instead I always find myself writing code for class or working with students. This was a break week, with extra free time, but I ended up using my freest day doing some work on the next issue of Transactions on Pattern Languages of Programming (TPLoP), of which I am an editor. Maybe this blog post and the programming challenge of December Adventure will keep me moving, on both code and blogging.
According to the countdown on the Advent of Code home page, my December Adventure begins in 2 hours, 15 minutes, and 9 seconds — and counting. Tomorrow, I create the repo and make my first commit.
October 27, 2024 8:50 AM
Not a Birthday Reflection
Today is my birthday. I won't tell you how old I am, and I promise not to pull a Gwyneth Paltrow. Trust me; no one wants that.
I do not have a birthday essay planned, or any deep reflections on the passing of time. Birthdays have never been times of deep reflection for me. As I grow older, they have not yet started to mean anything different to me, even as I realize that they will be fewer and fewer. I mostly think of them as a time to relax, think on the good things in my life, and get on with living it.
It's just as well that I have no birthday essay planned. My friend Daniel Steinberg wrote about his birthday a few weeks ago, and I cannot improve on what he said. Daniel turned 65 this year, a milestone in a culture that emphasizes youth. Daniel, though, is still learning and teaching us what he learns with his books and presentations. He notices now that the other attendees at the conferences where he speaks are much younger than he is:
I'm the same age or older than their parents.
I'm sure they see me as old.
For the most part, it is much worse in my head than in theirs.
I know this feeling. I work with college students every day. I'm older than all their parents now, and probably not that much younger than a few grandparents. I'm sure they seem me as old, but how much of that is in my own mind?
I have a few years before I reach sixty-five, but it's close
enough that I've been told I should start thinking about
retirement and investment accounts and a different kind of life.
But I'm of the same mind as Daniel: "Retire to do what?
Travel? Do things I'm interested in? I do all that now."
The life of an academic, at least one fortunate enough to have
found a steady, secure position, is good: we read, write, and
teach the thing we love. As long as I can do these things
well enough and enjoy them, I will.
2024 has been, in some ways, an eventful year. My dad died unexpectedly this summer. A couple of months later I learned that one of my college mentors died around the same time. Those were times of reflection for me. On a more uplifting note, my wife and I got to visit our daughters in Boston this spring and spend time with our favorite people in the world. Later we took a 48-hour break mid-summer to visit Minnesota and ride the full length of the Sakatah Singing Hills State Trail and back in one day. Riding 85 miles gives you plenty of time to enjoy the beauty of the world. (That's a blog post I've been meaning to write for three months...)
This is a milestone birthday for me, too, as counted by the rest of the world. However, a few years ago, I started enumerating my birthdays in hex (base 16), a shrewd move for a computer scientist. That means I am still comfortably in my 0x30s, young enough to keep doing the things I love to do.
October 15, 2024 3:33 PM
People Love Things That Are Not Like the Internet
Andrej Karpathy loves his calculator, and I like his post about how he loves his calculator. I was planning to quote the beginning of one paragraph as a teaser, but I could not decide where to clip the passage. Each sentence is worth seeing. I hope he does not mind that I show you the entire paragraph with encouragement to read the entire post:
Let's put this in perspective to the technology we increasingly accept as normal. The calculator requires no internet connection to set up. It won't ask for bluetooth permissions. It doesn't want to know your precise location. You won't be prompted to create an account and you don't need to log in. It does not download updates every other week. You're not going to be asked over and over to create and upgrade your subscription to the Calculator+ version that also calculates sine and cosine. It won't try to awkwardly become a platform. It doesn't need your credit card on file. It doesn't ask to track your usage to improve the product. It doesn't interrupt you randomly asking you to review it or send feedback. It does not harvest your information, for it be sold later on sketchy data markets, or for it to be leaked on the dark web on the next data breach. It does not automatically subscribe you to the monthly newsletter. It does not notify you every time the Terms of Service change. It won't break when the servers go down. The computation you perform on this device is perfectly private, secure, constrained fully to the device, and no running record of it is maintained or logged anywhere. The calculator is a fully self-contained arithmetic plugin for your brain. It works today and it would work a thousand years ago. You paid for it and now it is yours. It has no other master. It just does the thing. It is perfect.
You paid for it, and now it's yours.
My favorite pieces of software and favorite creators of software embody this ideal, at least as much of it as they can given the constraints of the modern tech world. Audio Hijack from Rogue Amoeba comes to mind and Acorn from Flying Meat come to mind.
That said, I loved calculators long before the web existed at all. Young Eugene had many hours of pleasure noodling on a calculator, playing with numbers. I first learned about rounding errors and limits by typing in a number and repeatedly hitting the square root key until the display showed a 1. I computed batting averages and winning percentages for my favorite teams and players. Eventually I was computing chess ratings by hand, until I sensed what a computer program could do for me. That would become the first program I ever wrote out of passion.
Even after learning to program, I never really lost the joy of tinkering with an old handheld calculator. It just does its thing. It is perfect.
October 10, 2024 9:14 PM
TIL Two New HTML Tags
Today I learned that HTML's <strike>
tag has
been replaced by two tags, <del>
and
<s>
.
I knew that <strike>
had been deprecated but
had never needed to learn its replacement, or that a replacement
even existed. I used it occasionally back in the days when
dinosaurs roamed the web, but only rarely since. When I used
it, browsers always displayed the text as expected, so I took
the easy route and kept on using it.
Two things have changed since the last time I used
<strike>
. I taught web development for the
first time last fall and decided that I wanted to write modern,
compliant HTML and CSS whenever possible, both as a good example
for my students and as a way to up my web game to the 2020s.
The second change was more abrupt: I used
<strike>
today and encountered a browser that
no longer supports it.
At first, I figured I'd just write a little CSS to simulate the
desire behavior with a class. That's the sort of thinking that
knowing CSS makes possible. But I also know that HTML includes
a remarkable set of elements and that we should prefer native
HTML whenever possible. So I looked <strike>
up in
the MDN documentation.
As they say, RTFM! The documentation enlightened me.
The two replacement elements have different semantics for the act of striking through text:
-
<del>
is for information that has been deleted -
<s>
is for information that is no longer correct
Now I have to think about which of these I mean when I decide to strike text in a page. But I don't mind this at all. I'm a big fan of HTML's semantic elements. What we write should express our intent, and these elements help us encode meaning and structure directly into our documents.
Even better, browsers and screen readers can use the structure of a document to present it more accurately, which means that using semantic elements makes our web pages more accessible to visually-impaired readers.
Further, using semantic elements also makes our pages more ready for futures that don't exist yet. I love the story in this blog post about how pages written with semantic markup displayed properly on the Apple Watch, even though they had been written well before the product launched. (If you'd like to jump directly to that story in the post, search for "NEW TYPES OF DEVICES".)
To bring my story to a close: I decided to use a
<del>
tag in the page I was writing for my
students. The text in question was a bad idea, so I marked it as
deleted. Whenever I open up this page in the future, the markup
will include a hint as to why the text has been stricken.
Posted by Eugene Wallingford | Permalink | Categories: General, Software Development, Teaching and Learning
September 29, 2024 9:23 AM
Two Quotes That Aren't About Teaching But, No, They Really Are
First from French writer André Gide, in Le Traité du Narcisse (1892):
Everything has been said before. But since nobody listens we have to keep going back and beginning all over again.
Every teacher knows how Gide feels.
Then from Bruce Springsteen, in a New Yorker interview I've lost track of:
This music has not been heard at this moment, in this place, by these faces. That's why we go out there.
Springsteen said that when asked how he could still sing "Born to Run" with so much energy after decades of performing. I think something similar to myself on many teaching days. I love the thing I am teaching and, even though it's old hat to me, it's new to my students, and I want them to love it, too.
I've always been a sucker for quotes that aren't about teaching, or programming, but could be. Making that sort of connection can motivate me on those days when I need a little pick-up.
But I also realize that making connections to other disciplines is a big part of how we teach or write programs at all. Metaphors are everywhere in both. Consider this line from Zach Tellman in a recent issue of the newsletter about his book in progress, "Explaining Software Design":
The queue is a useful metaphor because it makes us ask useful questions.
We create analogies and metaphors because they help us ask useful questions. They help us see our own objects of study, or own activities, in a new way.
I guess this is my way of saying that I'm okay with my irrational fondness for applying quotes out of context to my own world. Doing so occasionally helps me ask better questions. Even when they don't, I get to smile.
Posted by Eugene Wallingford | Permalink | Categories: Patterns, Personal, Software Development, Teaching and Learning
September 28, 2024 8:51 AM
The Thrill of a Script
I decided to scratch an itch this afternoon with a trivial bit of code.
My students use a homegrown system to submit their work in my
courses. After the assignment is due, I scp
the
assignment's directory from the server to my machine and add
it to the course repository. This directory contains one
subdirectory for each student, holding their individual
submissions.
I use a few scripts and a couple of manual steps to review student work, write up notes for them, and send them the reviews. Most of the scripts iterate over the subdirectories. For many tasks, it is simplest to assume one subdirectory for each student in the class.
I do all this work on two machines, one at home and one in my office. I use git to keep the repos in sync.
It's always been the case that, for any given assignment, one student might not submit anything. That's not a problem when I'm running my scripts on the same machine where I downloaded the submissions. But on the other machine, which gets the data via a git push or pull, the empty student subdirectories — poof! — disappear. git tracks files, not folders.
I'm sure there is a mechanism somewhere in git for handling
this sort of thing (isn't there a mechanism for
everything somewhere in git?), but in the past I've
done it by hand: I glanced at the subdirectory listing and,
when I saw an empty folder x, I typed
touch x/_nosubmit
.
When there is only one empty student folder, this is quick
and easy. But as the number of empty student folders goes
up, it becomes tedious. Two developments over the last few
semesters have driven the tedium to an uncomfortable level.
First, I've noticed that the number of students who miss the initial submission deadline rising. There are a variety of reasons that this is happening. I am happy to work with students who need to submit later, but this means more empty directories when I make my first pass reviewing submissions.
Second, I am trying to give students many more low-stakes opportunities to write code and get feedback. Instead of grading one assignment per week, I may now be evaluating submissions for three different tasks.
Put these two factors together, and I rapidly grew tired of
scanning subdirectory listings and touch
ing
empty files.
Sounds like time for a new command. At first I tried to do
it in a single line of bash, using xargs
, but
that didn't work. (My intuitions about
xargs
often fail me.) So I wrote a simple for loop:
for entry in $(find "$1" -type d -empty)
do
touch "$entry"/_nosubmit
done
Stash that loop in a file, chmod +x
, move it
to ~/bin
, and the discomfort goes away.
It occurred to me almost immediately that I should have made
the name of the file to touch an optional second argument,
using _nosubmit
, my placeholder of choice, as
a default. But you know what? YAGNI. If I ever find
myself in need of more flexibility, I'll add a fifth line
of code to initialize a FILENAME variable and use its value
in the touch
line. For now, simpler is good
enough.
As I wrote on Mastodon :
Several decades on, I still get a great thrill from writing a four-line shell script to automate a common task.
Simple pleasures for a simple programmer.
Posted by Eugene Wallingford | Permalink | Categories: General, Software Development, Teaching and Learning
September 21, 2024 8:41 PM
Back to the Web with... a Ph.D. Dissertation
Really. Lea Verou mentioned in this blog post that she hopes to write another blog post soon explaining...
How I used web technologies instead of LaTeX to write my PhD thesis (and print it to PDF for submission), with 11ty plus several open source plugins, many of which I wrote, an ecosystem I hope to one day free more people from the tyranny of LaTeX (which was amazing in the 70s, but its ergonomics are now showing their age).
I wrote my Ph.D. dissertation in WordPerfect (yes, I am old). The idea of writing a document as large and complex as a Ph.D. dissertation in HTML and CSS is both intimidating and intriguing, a challenge worth tackling — if only I hadn't already been facing the challenge of completing my research and, you know, writing a dissertation. For me, trying to write a simple midterm or final exam for one of my courses using only HTML and CSS usually results in me banging my head against a surprising number of walls followed by an hour or so of making tedious small changes to the stylesheet to get everything Just Right.
Verou had the advantage of deep expertise in web technologies and having done her research on the same. Even so, I am impressed and may take a peek under the hood of her website to see some of her best tricks.
This reflection is a convenient way for me to preface the fact that I am teaching web development again this fall. As I wrote in an earnest appeal for assistance last spring, this is an introductory course for non-majors, covering HTML, CSS, and a little interactivity using JavaScript. The course went reasonably well the first time around, though my coverage of JavaScript fell flat with most everyone in the class, especially the non-majors. I'm still working on ways to do better when we reach JS in a month or so.
After only a few weeks, though, I have been impressed with my students' eagerness to put their new web knowledge to use. On the first real homework assignment, I asked students to create a web page using a bunch of the HTML elements we had learned. I suggested possible pages they might create but left it open for them to create any page they wanted. As you might imagine, most students like this kind of freedom.
A couple of students wrote fan pages for their favorite musical artists (*). For me, that was shades of 1995. Another student used his assignment to create an instructional guide for the dog walker he and his significant other were hiring. He apologized for creating a page he didn't think I'd care to read, but I was very happy, and told him so.
I remember how much fun I had learning to write HTML back in the early days of the web and then writing all sorts of pages about things that I cared about. That's what knowing how to write can do for you, and knowing how to write for the web means being able to share what you write with anyone who cares to read. My students are using what they're learning to write about things they care about.
That makes me happy. And I think that Verou would be proud, too.
(*) Taylor Swift really is popular... A couple of my students were surprised and a little impressed that I like Swift, too. My daughters and I have bonded over music since they were toddlers, and they love to share their musical interests with Dad. Swift is one of many artists they've turned me on to over the years.
September 01, 2024 12:44 PM
Knowing Enough That You Can Wait to Decide Later
I sometimes half-jokingly tell my students that, whenever they write a new piece of code, they should have at least two alternatives in mind; that way, at least they know they aren't doing the worst possible thing. (They always laugh.) That's an old Kent Beck line, which I memorialized in a blog post many years ago.
It's part joke because it's cold comfort even to experienced programmers, and because students often don't trust themselves to generate alternatives, let alone evaluate their quality. But it's also quite serious, because it can be the first step novices take on the path to becoming a reflective practitioner.
That old story came to mind obliquely yesterday when I saw this Mastodon post by Kent, which ends with:
Next time you hear, "But we have to make this decision *now*!" ask yourself, "What skills would we need in order to *not* have to make this decision until later? How can we learn those skills?"
This seems to be an instance of a question useful to ask oneself more generally. What data, knowledge, tool, or skill would I need to be able to make this decision later?
We shouldn't fetishize postponing decisions, of course. Looking for a reason to wait to make every decision could become a recipe for not making any decisions. Further, this fetish can paralyze novices, who doubt their own abilities to evaluate choices. They can find themselves in a spiral of infinite postponement.
Fortunately, as long as we don't turn this mindset into a pathology, waiting to make a decision is rarely going to be a speed bump to writing programs. There are always plenty of decisions to make, so being able to delay some is a favorable option to have in hand.
In such a world, there is great value to be found in viewing a seemingly forced decision as an opportunity to learn.
It is almost never good to be in a position of having to make a decision right now, to have no alternatives from which to choose. We shouldn't settle for that condition without doing a little work first.
~~~~
Kent has a knack for making me think more deeply with an aphorism or a simple story. I've always admired that. This post is yet another example.