Emil Broman
banner
emilbroman.me
Emil Broman
@emilbroman.me
Independent Software Engineering Contractor based in Stockholm, Sweden. Currently hacking on compilers 🧑‍💻
August 1, 2025 at 7:07 AM
Agreed. Though sadly, the dominant paradigm is being referred to as OO... 🙃
June 7, 2025 at 10:24 AM
The most common way of doing things will be the thing beginners learn first. Hence, most "bad" code will be written in the dominant paradigm. Anything that challenges the status quo will therefore seem more appealing.
June 7, 2025 at 10:12 AM
Anyways, this was a rambling thread, but I thought I should try to share a bit more on the stuff that excites me! 😊
November 17, 2024 at 12:29 PM
On a more technical note, `own` types can be inlined into the stack frame or instance variable struct where it resides, such that unnecessary overhead of sending the message the actor inbox can be reduced.
November 17, 2024 at 12:29 PM
```
class X {
var own HashMap<Int, Int> cache
= HashMap new.

public doThing: Int i -> Int {
(cache at: i)
ifSome: { hit => ^hit. }
ifNone: {
// …
cache at: i put: value.
^value.
}
}
}
```
November 17, 2024 at 12:29 PM
A non-owned type is not assignable to an owned version of the same type, guaranteeing that anyone who holds an `own T` has exclusive access to the `T`.

The primary use-case is owning internal instance variables, making sure that query results are non-stale until we're ready to mutate.
November 17, 2024 at 12:29 PM
If the method sends `myX` as part of a message, the type of the variable is implicitly downgraded to a "non-owned" `X` for the remainder of the method.

But if the message type is determined to require an `own X`, e.g. if the receiver method has that type annotation, then `myX` moves.
November 17, 2024 at 12:29 PM
When an object is initialized using a constructor, the return type is marked as `own` meaning no one but the current method has a reference to it.

```
let own X myX = X new.
```
November 17, 2024 at 12:29 PM
To remedy this, we introduce the `own` type operator. It's almost like a linear type, but with implicit downgrade to a garbage collected shared reference. Like a much more easy-to-use version of a borrow checker.
November 17, 2024 at 12:29 PM
Next, the language fully embraces the Actor Model. That is, every message send is a semantically asynchronous operation.

Consider the common pattern of querying an object, then mutating it based on the result; this is now completely vulnerable to a race condition, the data structure being an actor.
November 17, 2024 at 12:29 PM
A more useful example would be an object that will proxy all messages and log messages and replies:

```
class LogAll<o> {
var o inner.

// Constructor!
init new: inner.

<o<- m> (m message) -> o (m) {
// log message
let reply = inner (message).
// log reply
^reply
}
}
```
November 17, 2024 at 12:29 PM
```
interface Identity<a> {
// For all types m being valid
// messages to a, sending m
// to this object returns the
// reply that a would give for m.
<a<- m> (m) -> a (m).
}
```

Useful? Not really, but it highlights how these features compose.
November 17, 2024 at 12:29 PM
Combining union types and the `<-` operator with type-level message sends, and adding constrained type variables to the mix, we can express a long-form type-level identity function...
November 17, 2024 at 12:29 PM
Next: union types.

By using the `<-` type operator, we can extract from a type the union of all valid messages that can be send to a type.

```
interface X { x -> String. (Int) -> Int }

type M = X<-. // #x | Int
```
November 17, 2024 at 12:29 PM
Since this pattern match can be done statically on the type level, we can also calculate what type _would be returned_ if an object received a message of a given type, allowing "type-level message sends":

```
interface X { (Int) -> Y. (String) -> Z }

type Y2 = X (Int).
type Z2 = X (String).
```
November 17, 2024 at 12:29 PM
Because the messages are just values, message types are just data types. Which means that interface types are just collections of mappings from one type to another.

Handling a message is equivalent to a pattern match on the incoming message.
November 17, 2024 at 12:29 PM
While Smalltalk is highly dynamic, my language takes a more familiarly modern route and has strong static typing.

```
interface MyObject {
handle: String and: Int -> Boolean.
}

let MyObject o = ...
let bool = o handle: "this" and: 42.
```
November 17, 2024 at 12:29 PM
But, to send a message from a variable, parentheses are used to disambiguate from sending a Smalltalk-style unary message.

```
let myMessage = 123.
myObject (myMessage).
```

In expression position, a # can be used to make symbol messages instead:

```
let x = #y.
obj (x).
obj y. // Equivalent
```
November 17, 2024 at 12:29 PM
In my language, the message part of a message send can be any type of object, like

`myObject 123`

means "send the message '123' to 'myObject'".
November 17, 2024 at 12:29 PM
Building on the message sending syntax of Smalltalk, where:

`myObject myMessage`

means "send the 'myMessage' message to the object referenced by 'myObject'", and

`myObject arg: 123 arg: 234`

means roughly "send the message 'arg:arg:' with arguments '(123, 234)'"
November 17, 2024 at 12:29 PM
We have a few great punny terms like that in Swedish. My favourite (not that widely used, though) is "killräckligt" from "kille" (boy/guy) and "tillräckligt" (enough). Like when dudes clean a room by throwing all the dirty clothes in a cupboard and doing the dishes. He cleaned up guy-enough.
February 14, 2024 at 5:01 PM