Signals system for Ajeeb, based on ES6 Generators. This package is intended to unite and supersede @ajeeb/coroutines and @ajeeb/input.
This package is a work in progress. Use at your own risk.
A signal is an object that represents a stream of events. The three1 things you can do with a signal are:
- emit a value through a signal
- await a signal's emission in a coroutine
- read a signal's most recently emitted value
These operations turn out to be really effective building blocks for the kind of asynchronous code that makes up the playful systems Ajeeb is designed for.
Historically the Ajeeb system had a coroutine system which provided a Schedule to contain and run coroutines and an input system to manage input. This was used to great effect in the many places Ajeeb was deployed but had its limitations.
Ajeeb Signals can also seamlessly consume Promise-based APIs, which Ajeeb Coroutines could not.
Signals could conceivably be built on JavaScript's Promises but they are limited in two ways
-
Little control over execution order
We need rock solid guarantees of determinism and code execution order for these systems to be usable as foundational abstractions. Promises are scheduled by the JavaScript host event loop and the exact order of evaluation between scheduled promises is not defined. This is OK when you're waiting on things like network requests but intolerable for many of the interesting use cases Signals can address, namely waiting on coroutines and other asynchronous code.
-
No way to cancel a Promise
Being able to cancel a waiting coroutine and allow it to clean up after itself turns out to be a critical feature of asynchronous systems -- and is often missing. Ajeeb Signals leverage JavaScript's
try
/finally
machinery to enable this with minimal ceremony, but Promises simply cannot be cancelled.
JavaScript is built on the notion of "events" and C# even has them built into the language. They are similar so Ajeeb Signals in that you can emit values to through them but, critically, they cannot be awaited, making them less useful for the construction of state machines.
Godot has signals and since 4.0 they are awaitable in coroutines, making them very similar to Ajeeb's signals. A difference is that in Godot signals are part of a larger engine, with object-oriented semantics and other organizational ideas, where in Ajeeb signals and coroutines are meant to be the main organizational principles that everything else is built on.
Ajeeb is free and unencumbered software released into the public domain under the terms of the CC0 1.0 UNIVERSAL license.
Attribution is appreciated but not required. When attributing a mention to the effect of "This project makes use of Ajeeb, originally by Ramsey Nasser" and/or a link to https://ajeeb.games/
is sufficient.
While this software may legally be used by anyone, it is not for everyone.
This software is the result of a great deal of joyful labor on the part of the author, and it is shared freely in the hope that individuals, students, artists, and worker cooperatives will benefit from its use and study in any capacity, commercial and otherwise. The author made this for you.
It is absolutely not intended for use in service of capital, in pursuit of profit for a minority off the labor of others, or by organizations that differentiate their owners and their workers.
If you own such an organization, know that the author believes that you are a bad person, and that you should step aside and allow your enterprise to be run democratically by your employees with equal stake and say in its management. The author did not made this for you, and holds you in contempt.
If you work for such an organization, know that the author believes that you are being exploited, and that you should start organizing towards converting your workplace into a cooperative or unionizing at the very least. The author is on your side, hopes this software lightens the burden of your labor.
We have nothing to lose but our chains and a better world is possible.
1 There are plans for a fourth operation -- to subscribe to a signal using a conventional callback