Mike Samuel 🟣
banner
mvsamuel.bsky.social
Mike Samuel 🟣
@mvsamuel.bsky.social
I solve large software systems problems with programming language techniques.

Previously, I was the first frontend engineer on Google Calendar, and was a security engineer who worked on the industrial-strength Mad Libs undergirding Gmail.
Yeah, without that context from the précis that it's when performing a high-risk task, the 40% stat is meaningless.

E.g. high risk: generating a database query from an untrusted input which can lead to SQL injection.
Low risk: pure math, like compute compound interest.

arxiv.org/pdf/2108.09293
November 25, 2025 at 8:37 PM
I vaguely remember a biography of Helen Keller talking about how learning language at the age of 7 revealed internal vistas.

I can't vouch for the below but it matches my recollections.
November 25, 2025 at 3:20 PM
November 24, 2025 at 4:54 PM
We can make breaking changes now!
So if you have ideas on what would make the language really great for standards work, the sooner we know the more accomadating we can be.

And if you have ideas about how to spec something standards-related, we can help with advice and/or implementation work.
November 20, 2025 at 9:28 AM
Programming languages go through stages.

We're in the early adopter stage.

We've got the language functional. It's usable today, but we are reworking some significant parts.

Lots of work still to do.
November 20, 2025 at 9:27 AM
Here's the six PLs we support today.

We've been slow rolling backends to get the foundation right, but have been trying to get a spread.

We've done initial investigation on a whole lot more.
November 20, 2025 at 9:26 AM
We've been at this for six years.

Two understanding the problem space.
Four on the compiler frontend & backends.

There're a lot of competing requirements. It wasn't obvious 6y ago that there are non-interfering solutions.

But we've got a nice, useful language.
It's getting to be fun to work in.
November 20, 2025 at 9:24 AM
Almost done
November 20, 2025 at 9:22 AM
It's very convenient for us to have a distinct name for each method/function.

But adding an overload to a language is only backwards compatible if it doesn't introduce ambiguity, which languages have very different rules about.
November 20, 2025 at 9:21 AM
Overloads allow convenient APIs: the same abstract idea via different concrete inputs.

That works for typed languages.
For dynamic languages you do things differently.

Temper needs to allow for specifying groups of related operators while still translating to both language groups.
November 20, 2025 at 9:20 AM
I mentioned this complicator, core type conflation in dynlangs, earlier.

Temper has lots of restrictions on casts.

But we provide a workaround. Sealed SUM (slide is wrong) types are castable.

If you really need to cast something up and later back down, sealed wrappers given you the tools you need
November 20, 2025 at 9:17 AM
Sub-typing allows for over & under specified types.
Casting lets devs work around that.

Only up-casts can be proven safe by compilers.

Erasure: not all runtimes have enough info to prove casts safe at the time the value is known.
November 20, 2025 at 9:14 AM
Strings need to work consistently.

What does it mean to get the i-th "character"? What even is a character?

That table shows two main groups: some byte-based, some UTF-16. But there're outliers.

Temper is like Swift: code-point based by construction which lets us be consistent & efficient.
November 20, 2025 at 9:13 AM
We need to mix and match to get safe abstractions.

Coroutines & promises.
but can extend to actor model allowing mediated shared memory.

Need to be careful about global mutable state.
Can allow threadsafe cache types and atomics at the top level.

Extra type declaration checks for sharable values.
November 20, 2025 at 9:11 AM
Concurrency lets parts of a complex task proceed independently.
Start sub-tasks before others finish.
It's important in an SDK, a library that fetches URLs from a service.
Can't predict response arrival order.

But there's a lot of difference across PLs.
And mistakes can lead to memory corruption.
November 20, 2025 at 9:10 AM
If tail is mutable, you can change a list to point to itself.

Now the .tail loop has < instead of <=, and is red.

If the < edges don't form a cycle, there's an order in which ref-counted records destruct.
But if a node has to be less-than itself, contradiction, there's no deallocation order.
November 20, 2025 at 9:08 AM
Here's a generic, recursive type: a cons list.

We generate a graph from it that shows what can point to what.

A cons list can point to another via its tail.
And it could have a head that is a different list type
bit the type definition says that an F cannot point back to Cons<F>.
November 20, 2025 at 9:07 AM
Our solution isn't ideal, and we still need to integrate the checks. It leaks implementation details, but I think the main feature is that if you stick to OCaml record discipline, it just works.

If you're writing generic collection libraries, it will kind of suck.

Goal: ref-counting is safe.
November 20, 2025 at 9:04 AM
Memory. There's no great choice here.
But our target audience is everyday devs, not only people who habitually think about ownership.

So we bit a bullet: you can provide cyclic looking APIs, but without actual cycles.
November 20, 2025 at 9:03 AM
Temper needs to distinguish between ints & floats; that's important to systemsy PLs.

Dynlangs like Perl, PHP and JS don't.

It's complicated when these operations appear inside type-polymorphic functions.
We've put a lot of design work into a way to get semantic consistency here.
November 20, 2025 at 9:02 AM
Languages often support generic operations, like comparison and stringification, that apply to many types. But they are often specialized for each.

Here, comparison is different for numbers and strings.

And the trend in modern languages if for it to distribute through collections.
November 20, 2025 at 9:00 AM
Code needs to switch from doomed code paths to paths that recover or compensate.

Exceptions & result checks are the main approaches.
We need to be idiomatic here; surprises lead to failures & hard debugging.

Strangely, results translate well if results aren't inputs or stored in temporaries.
November 20, 2025 at 8:59 AM
Optionality allows representing optional inputs, unavailable outputs, etc.

There're two main approaches: null values & option types.

But as the slide shows, they aren't equivalent.

Temper uses checked null syntax, but translates to either.
Extra compiler checks ensure consistent semantics.
November 20, 2025 at 8:58 AM
You need to translate them to a place. That same diamond diagram now no longer has a top module. You need to know that there's a common referent for the other three modules when you compile any of them separately.
November 20, 2025 at 8:56 AM
Nominal types are when a PL names types.
A type like X is declared in some source file, A.
Other files, B and C, can depend on it.
And if yet another depends on B and C, it can use an X value from one with the other.
November 20, 2025 at 8:53 AM