Idea for a minimal POLA/functional/actor DSL

40 views
Skip to first unread message

Rob Meijer

unread,
Nov 5, 2025, 4:42:06 PMNov 5
to cap-talk
As part of my (currently) pet project, I'm considering a very minimal DSL (worling name Merg-E) that combines POLA, secure defaults, functional, paralel, and actors, but without objects, so it's likely not really ocap.  Though it feels it might be close.

The last time I made a DSL it was an XML based language for a forensic framework, so I might underestimate the work needed to implement it, but I feel that keeping it feature poor, it might be doable and less work than going for language bindings  for my pet project for languages that I haven't used in any real life project yet, plus it would be great fun to write a POLA DSL.

I just posted an incomplete outline as blog post:

https://peakd.com/hive-139531/@pibara/ideas-for-merg-e-a-least-authority-language-for-web-30

I would be very much interested in feedback on my language ideas.  

One specific aspect I am interested in is the move as default or reference stealing as default for POLA idea. It's a subject that I first thought about 14 years ago and didn't do anything with since.

https://minorfs.wordpress.com/2011/05/09/hypothesis-reference-stealing-should-be-default-pola-behaviour/

But apart from that, any input that doesn't explode the minimal language idea into a full general purpose language that I'll never have the time to implement is very welcome.

If it's impossible to "fix" it without making it a full sized general purpose language, that's usefull info too because it would mean I shouldn't bother ;-)

Rob Meijer

unread,
Nov 5, 2025, 4:46:35 PMNov 5
to cap-talk
Oh, in case Mark objects to the name Merg-E because it's to be a language without objects (and thus without real ocaps), I'll just name it plain "merge" instead. 

Dale Schumacher

unread,
Nov 6, 2025, 12:25:35 PMNov 6
to cap-...@googlegroups.com
About 15 years ago I found myself wanting to write pseudo-code for "minimal POLA/functional/actor" programming. A simple language that focused on the Actor semantics with as little extra distraction as possible. Eventually the pseudo-code was formalized into the Humus programming language (which you can play with at https://dalnefre.github.io/humus_js/).

Humus implements the "Classic" Actor semantic model (https://dalnefre.com/wp/2024/04/classic-actor-semantic-model/).

I would describe it as an "ocap" language, although the Objects are Actors and the only type of Capability is asynchronous one-way message-send. In addition to the actor primitives (that cause transactional effects), there is a pure-functional (no mutation) expression language for computing immutable values. Functions are invoked synchronously and infallibly produce a value. Actors may use "become" to mutate their local (private) state and behavior, essentially replacing the closure used to react to subsequent messages.

I've read your language outline. There seems to be a lot of complexity in managing safe access to potentially shared mutable state. Encapsulating mutation inside actors (instead of objects) and making functional values immutable, as Humus does, greatly simplifies the language semantics. As a result, Humus is a very small language.

You've given a lot of consideration to a module system for composing large systems. Humus could use an extension along those lines. I'd be happy to collaborate on this or other language issues. I've thought a lot about providing a more familiar sequential-imperative model for describing actor behavior, but mutation would have to be limited to local actor state.


--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/cap-talk/12e563f2-8958-4f98-b0b7-9dc733964455n%40googlegroups.com.

Rob Meijer

unread,
Nov 13, 2025, 3:37:02 AMNov 13
to cap-...@googlegroups.com
Looks good. In my current draft actors are a wrapper around a "Scope" plus either a "function" or a "def", where a def and a function are close to the same things but they have slightly different definitions syntax because of import contract needs. 

I haven't gotten to working out the exact details yet for actors, but I'm definitely going to take a deeper look at your implementation to see if there are things I should change on my end.

I took some time to work out details for Scope/scope and the scoping rules on different levels and how they relate to the low assumption parallelism, plus some other details including the import (merge) that I think might interest you. Please borrow anything you like from that.

The details on the actors bit, as well as the details on attenuation and decomposition and possibly a less minimal strictly POLA exception handling setup, still need working out.

I'll definitely look deeper into your work before working out the actor details, also looking at ideas for what to do with exceptions because that is the only part where strict POLA as it is in the draft now feels constraining.

I'm currently restricting exceptions to a few dozen raw stateless types in an exception hierarchy that the user can't extend, and non cought awaited exec scope exceptions bubble up without even a message, while non caught exceptions from an exec scope not bound to an awaitable go straight to the main level error scope.

No message, no stack info, no state. Not really happy about that,  but right now anything beyond this minimal and very strict design feels tricky in terms of being sure cought exceptions can't escalate privileges. 

I hope to gain some insights on how to expand on this by looking at your and possibly other least authority languages.

If you have any direct insights you can share on this, it would be very welcome.

Here is a blog post with some worked out details. It's mostly on scoping, but includes the importing contracts but too.


I hope that bit can give you inspiration for implementing something like that in your DSL.



Matt Rice

unread,
Nov 13, 2025, 7:03:07 AMNov 13
to cap-...@googlegroups.com
On Thu, Nov 13, 2025 at 8:37 AM Rob Meijer <pib...@gmail.com> wrote:
>
> Looks good. In my current draft actors are a wrapper around a "Scope" plus either a "function" or a "def", where a def and a function are close to the same things but they have slightly different definitions syntax because of import contract needs.
>
> I haven't gotten to working out the exact details yet for actors, but I'm definitely going to take a deeper look at your implementation to see if there are things I should change on my end.
>
> I took some time to work out details for Scope/scope and the scoping rules on different levels and how they relate to the low assumption parallelism, plus some other details including the import (merge) that I think might interest you. Please borrow anything you like from that.
>
> The details on the actors bit, as well as the details on attenuation and decomposition and possibly a less minimal strictly POLA exception handling setup, still need working out.
>
> I'll definitely look deeper into your work before working out the actor details, also looking at ideas for what to do with exceptions because that is the only part where strict POLA as it is in the draft now feels constraining.
>

I'm not really certain exceptions with strict POLA must feel constraining.
in fact a decade ago harper gave a characterization of exceptions in
standard ML as shared secrets. They've formed the basis for many
sealer/unsealer implementations in that language.

https://existentialtype.wordpress.com/2012/12/03/exceptions-are-shared-secrets/

I somewhat feel that there is some mixing of authority in the SML
characterization of exceptions. This largely follows from the
"balance" of introduction and elimination rules in logic in the sense
that because "matching" and "constructors" are linked what harper
calls a "raiser" and a "handler" in other words it is impossible to
separate the ability to raise from the ability to handle. He also
discusses "wild-card handlers", I would characterize these as a 3rd
form of authority. Essentially a wild card handler is the authority
to observe that an exception occurred. If I were going for a "least"
POLA account of exceptions I would start with separating these 3
authorities

1. raise (basically is just sealing along with a channel between stack frames)
2. observation (may not be able to unseal but can observe that a
message was sent)
3. decode (unseal)

He gives this the formal treatment in his book PFPL, but it's by no
means an easy read that you can just pick up and expect to glean
anything from without first from without spending time understanding
his entire formal structure.

I've sort of skipped over all the topics that usually come to mind
when people mention exceptions (the control flow/goto-esque
implications), presumably control in actor/capability language
shouldn't be restricted to a single channel for "return" values, my
feeling is that aspect is already gone by the time you're using
message passing so I won't dwell on it.

This isn't really taking into account capability OS mechanisms like
seL4's async notifications
which are a form of signaling akin to observation since they cannot
carry state/values but I feel should stop here before I manage to test
everybody's patience.

But what I seek to get across is that the standard ML account of
exception values tend to look alot like sealing/unsealing except
sealing and unsealing are bi-implicated (having a sealer implies
having an unsealer and vice versa) plus observation, signaling and
some control flow aspects. But I don't feel like it is out of reach of
pola/capability system, On the contrary these are all pretty
fundamental aspects of some modern capability systems.
> To view this discussion visit https://groups.google.com/d/msgid/cap-talk/CAMpet1UMh6-TemKRv%3DZZT3ym-L36GkuZpOAXu7ke36EgSzR5FQ%40mail.gmail.com.

Dale Schumacher

unread,
Nov 19, 2025, 2:02:49 PM (9 days ago) Nov 19
to cap-...@googlegroups.com
I'm concerned that the context in which your DSL is meant to operate may be substantially different than the context Humus was designed for. In addition, there is significant potential for confusion based on the assumptions that may come from different categories of actor languages. I've found the paper "43 years of actors: a taxonomy of actor models and their key properties"[1] to be extremely valuable in clarifying these important distinctions. The paper describes four primary categories of actor systems:
  1. Classic Actor Model (Humus, Rosette, ...)
  2. Processes (Erlang, Kilim, ...)
  3. Active Objects (SALSA, Orleans, ...)
  4. Communicating Event-Loops (E, AmbientTalk, Spritely Goblins, ...)
It's not clear to me which category best describes your language, but it appears to be Communicating Event-Loops. Humus (and my more-recent work on uFork) fits the Classic Actor Model, and meets the criteria described in https://dalnefre.com/wp/2020/01/requirements-for-an-actor-programming-language/

Your work on typed semantics, and further discussion from Matt Rice, communicates an important point about using types to negotiate contracts between independently-developed modules. Professor Harper has much to say about this. I would like to disentangle the discussion of "exceptions" from the discussion of types.

In a recent Stanford Security Lunch talk, the head of cybersecurity for Microsoft noted that a frequently productive channel for exploitable leaks of sensitive information is the data divulged by inducing an exception. Naturally useful for debugging, this channel can expose lots of "private state", even in a POLA system.

Humus takes a much more strict approach to handling so-called "exceptions". The pure-functional sub-language of expressions, which produce immutable values, is infallible (modulo non-termination, since it's Turing-complete). All functions are made total by including a designated "undefined" value as a possible result. Expression evaluation cannot result in an "exception". Since the expression sub-language is only used to define the effects caused by an actor message-event, the scope of most functions is quite limited.

When an actor is processing a message-event, it accumulates a set of effects. These effects are isolated, not visible outside the actor until and unless the actor performs a "commit" (ending its transaction). Problematic message-events, such as those containing inappropriate data or unrecognized requests, can "abort" the transaction. This is what happens when a Humus program executes a THROW statement. The message-event is consumed and any pending effects are discarded. Note that an actor may also respond to a valid recognized message by ignoring it (committing no effects). This "exception" mechanism cannot be used for flow-control, or abused in other ways typical of exception-handling in other languages. Humus THROW provides a value (infallibly calculated, of course) that may be made available over a secure connection to a privileged debugger (not exposed to users).

In summary, Humus doesn't need much of an "exception handling" mechanism because actors can't "crash". Expression evaluation always produces a value, and message-event handling can result in "no effect".

One common difference between Classic Actor Model systems and Communicating Event-Loop systems is that the former generally assume asynchronous one-way messages, and the latter generally assume a request/response protocol which leads to promise-values (possibly with pipelining) and the potential of broken promises raising exceptions in the caller's context. In Humus the effects of an "exception" are limited to the actor in which it occurs, and the actor continues to process subsequent messages.

[1]
Joeri De Koster, Tom Van Cutsem, and Wolfgang De Meuter. 43 years of actors: a taxonomy of actor models and their key properties. Proceedings of the 6th International Workshop on Programming Based on Actors, Agents, and Decentralized Control (AGERE 2016). ACM, 2016.

Reply all
Reply to author
Forward
0 new messages