Entries tagged programming | Hugonweb Annotated Link Bibliography

Hedy

https://hedy.org/

A programming curriculum meant to be a step between things like Scratch and Python. It gradually introduces concepts and syntax so the student isn't overwhelmed by e.g. punctuation. It also localizes keywords to a student's language, so e.g. print and for are translated into Chinese, Spanish, etc.

How to slow down a program? And why it can be useful.

https://stefan-marr.de/2025/08/how-to-slow-down-a-program/

  • Slowing down parts of a program can trigger hidden race conditions
  • Slowing down all parts except a part you plan to optimize can be used to estimate the impact of the optimization

SIMD instructions considered harmful

https://www.sigarch.org/simd-instructions-considered-harmful/

Interesting how vector instructions can be more performant than SIMD instructions. Also nice to not have a million SIMD instructions as registers grow in bit-width. It seems like a clear win to use vector instructions for RISC-V, so the vector registers can vary in size between implementations.

Notes on structured concurrency, or: Go statement considered harmful

https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/#nurseries-in-practice

The origin post about Trio. I first saw this a few years ago and think it's the way to do async.

Code smell: boolean blindness

https://runtimeverification.com/blog/code-smell-boolean-blindness

This post points out that it's often difficult to tell what a function does when passed true (or false). The given example of the ubiquitous "filter" function is great; does true or false make you keep a list element? Renaming filter to "select" and/or "discard" makes the boolean clearer.

The author points out that substituting a function that returns the Haskell Maybe type makes makes more sense in some "filter" scenarios.

mapMaybe :: (a -> Maybe b) -> [a] -> [b]

builds a list with only entries where the given function returns Just b

See Data.Maybe.mapMaybe for lists and the more general Data.Witherable.mapMaybe.

Related: the wrong abstraction

Faster RANLUX Pseudo-Random Number Generators

https://christoph-conrads.name/faster-ranlux-pseudo-random-number-generators/

RANLUX is highly regarded in the particle physics simulation community, but as far as I remember, we used the Mersene Twister in the Compact Muon Solenoid experiment. It must have been because it was faster.

The linked post is an effort to modernize RANLUX and make it faster.

Simplify: Move code into database functions

https://sive.rs/pg

Keep as much logic in the database, using constraints, stored procedures, and functions (Postgres even lets you write them in Python) as possible.

This reduces duplication of logic between the DB and external code, and allows the external code to change without issue.

Types as assertions

https://jerf.org/iri/post/2025/fp_lessons_types_as_assertions/

Using custom types wherever there is some concept of validity can help make a codebase free from checking validity everywhere. It only must be done in the constructor and errors handled by the caller of the constructor.

So look through a codebase for functions that take string, int, and float!

The one ring problem: abstraction and our quest for power

https://www.tedinski.com/2018/01/30/the-one-ring-problem-abstraction-and-power.html

image

"Design is figuring out how to find a point in the middle."

You cannot make an abstraction more powerful without sacrificing some properties that you used to know about it. Necessarily. You cannot require a new property be true about an abstraction without sacrificing some of its power and flexibility. Always.

The mistake is to forget this. Nearly always, this error happens in one direction. To look on a design, see what cannot be done with it, and attempt to “fix” it. To make it more powerful, and forget that it necessarily becomes more meaningless.

Designing type inference for high quality type errors

https://blog.polybdenum.com/2025/02/14/designing-type-inference-for-high-quality-type-errors.html

A bunch of things to note in designing a type system to make error messages better. I think the examples of bad error messages in languages being due to the type system (C++!) are broadly interesting.

When type annotations are code too

https://blog.polybdenum.com/2022/04/25/when-type-annotations-are-code-too.html

Type annotations affect runtime behavior in statically compiled languages, but not ones where types are bolted-on after the fact (Python).

This makes runtime behavior depend on the type inference algos and can be difficult to reason about.

The example in Haskell is wild!

Common mistakes to avoid in PHP

https://stackoverflow.com/collectives/php/collections/76822501/common-mistakes-to-avoid-in-php

List of Stack Overflow questions about mistakes to avoid in PHP

(The only proper) [PHP] PDO tutorial

https://phpdelusions.net/pdo

A nice tutorial on PDO, the built-in SQL interface for PHP.

In particular, the official documentation doesn't say much about querying, but it's covered well here.

The other pages on the site are good too.

How to Specify It!: A Guide to Writing Properties of Pure Functions

https://research.chalmers.se/publication/517894/file/517894_Fulltext.pdf

A guide to writing property-based tests. The author, John Hughes, co-wrote QuickCheck in Haskell, the first package for property-based testing.

Published conference paper: http://dx.doi.org/10.1007/978-3-030-47147-7_4

Some quotes:

"Avoid replicating your code in your tests," because it's lot of work and likely to contain the same errors as your code.

"Test your tests," because if your generator and shrinker produce invalid values, everything else will fail too.

Validity testing

Validity testing consists of defining a function to check the invariants of your datatypes, writing properties to test that your generators and shrinkers only produce valid results, and writing a property for each function under test that performs a single random call, and checks that the return value is valid.

Postcondition testing

A postcondition tests a single function, calling it with random arguments, and checking an expected relationship between its arguments and its result.

Metamorphic testing

A metamorphic property tests a single function by making (usually) two related calls, and checking the expected relationship between the two results.

Inductive testing

Inductive properties relate a call of the function-under-test to calls with smaller arguments. A set of inductive properties covering all possible cases together test the base case(s) and induction step(s) of an inductive proof-of-correctness. If all the properties hold, then we know the function is correct–inductive properties together make up a complete test.

Model-based testing

A model-based property tests a single function by making a single call, and comparing its result to the result of a related “abstract operation” applied to related abstract arguments. An abstraction functions maps the real, concrete arguments and results to abstract values, which we also call the “model”.

Inverting a dictionary of lists in Python

https://stackoverflow.com/questions/35491223/inverting-a-dictionary-with-list-values

I've needed to do this countless times in particle physics data analysis and other areas.

What I've done before:

data = {'a' : ['alpha', "beta"], 'b' : ["alpha"]}
result = {}
for key in data:
    for value in data[key]:
        try:
            result[value].append(key)
        except KeyError:
            result[value] = [key]

and the simpler solutions suggested in the link:

data = {'a' : ['alpha', "beta"], 'b' : ["alpha"]}
result = {}
for key in data:
    for value in data[key]:
        result.setdefault(value,[]).append(key)

or

from collections import defaultdict

data = {'a' : ['alpha', "beta"], 'b' : ["alpha"]}
result = defaultdict(list)
for key in data:
    for value in data[key]:
        result[value].append(key)

dict.setdefault and collections.defaultdict are new to me and useful!

Stop writing Python __init__ methods

https://blog.glyph.im/2025/04/stop-writing-init-methods.html

The idea is to just set members in object constructors to keep them simple. Any complex data conversion, or side-effects should be moved to a class-method.

This seems like a great way to deal with constructors taking multiple different inputs.

I do think using traditional constructors has the advantage of following a widely used convention (the principle of least surprise in API design) and can be simpler to use.

ASCIIFlow

https://asciiflow.com/

A web-app for drawing ASCII diagrams.

Choose boring technology

https://mcfunley.com/choose-boring-technology

Author: Dan McKinley

The idea is that the more new, exciting, "poorly-understood" things you choose, the more complex and difficult to deal with your system becomes. He advocates for a company to pick three or less non-boring technologies and to pick them where it maximizes your competitive advantage.

This whole article is great!

What counts as boring? That’s a little tricky. “Boring” should not be conflated with “bad.” There is technology out there that is both boring and bad (we often casually refer to the boring/bad intersection of doom as “enterprise software,” but that terminology may be imprecise). You should not use any of that. But there are many choices of technology that are boring and good, or at least good enough. MySQL is boring. Postgres is boring. PHP is boring. Python is boring. Memcached is boring. Squid is boring. Cron is boring.

The nice thing about boringness (so constrained) is that the capabilities of these things are well understood. But more importantly, their failure modes are well understood.

Emphasis theirs:

One of the most worthwhile exercises I recommend here is to consider how you would solve your immediate problem without adding anything new. First, posing this question should detect the situation where the “problem” is that someone really wants to use the technology. If that is the case, you should immediately abort.

The wrong abstraction

https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction

A good sign of an abstraction, e.g function, that needs to be replaced by copy-pasted code is one with boolean flag parameters. It's probably better to "inline" the code back to the call site, and then see what parts of it, if any, are still shared and make a new abstraction.

Haskell conditional for

https://entropicthoughts.com/non-obvious-haskell-idiom-conditional-for

To only perform a monadic or applicative action if a value exists, you can use

for_ value $ action

So for example, if x is a Maybe String, you could print it if it exists with:

for_ x $ putStrLn x

I think that's the beauty of Haskell, this thing with a name from lists, when generalized to (Traversable) Applicatives, can do useful things for all kinds of things.

Since for_ is just traverse_ with it's arguments flipped, you could also do:

traverse_ (action) value

Keep in mind for_ and traverse_ are in Data.Foldable and not present in the Prelude.

Also, oddly, is the linked blog post scheduled to be published in the future?

Haskell guard sequence

https://entropicthoughts.com/non-obvious-haskell-idiom-guard-sequence

guard condition *> action -- Perform action if condition is true else fail
guard condition $> value  -- Return value if condition is true else fail
value <$ guard condition  -- Like the 1st line, but switched around

This can effectively make sure a condition is true before doing something or returning a value.

Keep in mind "failure" can mean lots of things depending on the surrounding Applicative. It could mean returning Nothing, or raising an exception.

You will need the following imports to do this:

import Control.Mondad (guard)
import Data.Functor ((*>),($>),(<$))

Picking glibc versions at runtime

https://blogsystem5.substack.com/p/glibc-versions-runtime

How do you test code against a different version of libc than the system default one? You can't reliably use an alternate libc by putting it in LD_LIBRARY_PATH. It will often crash.

You might think that the kernel is somehow responsible for dealing with dynamic libraries, but that’s not the case. Dynamic libraries are a user-space concept and this is precisely where the [ELF] interpreter [ld-linux.so] comes into play.

To summarize, glibc ships both the ld-linux.so dynamic linker and the libc.so.6 shared library. The two are closely coupled. Running a binary against the C library without also using a matching dynamic linker can lead to crashes. But running a binary directly with a specific dynamic linker ensures that the binary picks up the matching C library.

At compile time, you can include the interpreter ld-linux with:

bash gcc -o myexe -Wl,--dynamic-linker=/wherever/ld-linux-x86-64.so.2 mycode.c

At runtime, you can use patchelf to replace the reference to the interpreter in the binary:

bash patchelf --set-interpreter /wherever/ld-linux-x86-64.so.2 myexe

Keep in mind that glibc backwards compatibility means a newer glibc will work with code compiled with an older version, but not the other way around.

The Night Watch

https://www.usenix.org/system/files/1311_05-08_mickens.pdf

Funny musings about how systems programmers are hard-core.

Excerpts:

The systems programmer has traced a network problem across eight machines, three time zones, and a brief diversion into Amish country, where the problem was transmitted in the front left hoof of a mule named Deliverance

A systems programmer will know what to do when society breaks down, because the systems programmer already lives in a world without law.

Listen: I’m not saying that other kinds of computer people are useless. I believe (but cannot prove) that PHP developers have souls. I think it’s great that database people keep trying to improve select-from-where, even though the only queries that cannot be expressed using select-from-where are inappropriate limericks from “The Canterbury Tales.” In some way that I don’t yet understand, I’m glad that theorists are investigating the equivalence between five-dimensional Turing machines and Edward Scissorhands. In most situations, GUI designers should not be forced to fight each other with tridents and nets as I yell “THERE ARE NO MODAL DIALOGS IN SPARTA.” I am like the Statue of Liberty: I accept everyone, even the wretched and the huddled and people who enjoy Haskell. But when things get tough, I need mission-critical people; I need a person who can wear night-vision goggles and descend from a helicopter on ropes and do classified things to protect my freedom while country music plays in the background. A systems person can do that. I can realistically give a kernel hacker a nickname like “Diamondback” or “Zeus Hammer.” In contrast, no one has ever said, “These semi- transparent icons are really semi-transparent! IS THIS THE WORK OF ZEUS HAMMER?”

When you debug a distributed system or an OS kernel, you do it Texas-style. You gather some mean, stoic people, people who have seen things die, and you get some primitive tools, like a compass and a rucksack and a stick that’s pointed on one end, and you walk into the wilderness and you look for trouble, possibly while using chewing tobacco. As a systems hacker, you must be prepared to do savage things, unspeakable things, to kill runaway threads with your bare hands, to write directly to network ports using telnet and an old copy of an RFC that you found in the Vatican.

Nothing ruins a Friday at 5 P.M. faster than taking one last pass through the log file and discovering a word-aligned buffer address, but a buffer length of NUMBER OF ELECTRONS IN THE UNIVERSE.

You might ask, “Why would someone write code in a grotesque language that exposes raw memory addresses? Why not use a modern language with garbage collection and functional programming and free massages after lunch?” Here’s the answer: Pointers are real. They’re what the hardware understands. Somebody has to deal with them. You can’t just place a LISP book on top of an x86 chip and hope that the hardware learns about lambda calculus by osmosis.

That being said, if you find yourself drinking a martini and writing programs in garbage-collected, object-oriented Esperanto, be aware that the only reason that the Esperanto runtime works is because there are systems people who have exchanged any hope of losing their virginity for the exciting opportunity to think about hex numbers and their relationships with the operating system, the hardware, and ancient blood rituals that Bjarne Stroustrup performed at Stonehenge.

OWASP Security Cheat Sheets

https://cheatsheetseries.owasp.org/index.html

Cheet sheets on all kinds of security, from C-based toolchain hardening to HTTP headers.