Signals

From Esolang
Jump to navigation Jump to search
Signals
Paradigm(s) imperative, event-driven
Designed by User:stkptr
Appeared in 2025
Dimensions one-dimensional
Computational class Turing complete
Reference implementation Unimplemented

Signals is a programming language inspired by the observer pattern (Wikipedia). Signals has two objects: signals, and listeners. Signal objects can have arbitrarily many listeners connected, including arbitrarily many of the same listener. Signals can be dispatched/emitted/fired, which causes connected listeners to execute.

Syntax

Programs are made up of signal and listener definitions. Comments can occur at the end of any line, and start with #.

signal signal_name # define a signal

# define a listener
listener listener_name {
    ...
}

Names of signals and listeners are global and cannot clash. Listener definitions cannot nest, and consist of a number of statements. Statements connect, disconnect, and fire signals.

Connect a listener and signal, causing the listener to execute when the signal fires (the order of the arguments doesn't matter):

connect listener_name and signal_name
connect signal_name and listener_name

Disconnect a listener and signal, disconnecting all occurrences:

disconnect listener_name and signal_name
disconnect signal_name and listener_name

Clear all connected listeners from a signal:

clear signal_name

Remove a listener from the listener list of every signal:

clear listener_name

Fire a signal, causing the listeners to execute:

emit signal_name

Every program has an implicit toplevel connect init and on_init followed by emit init, so programs must contain a listener named on_init in order to have anything happen.

Programs execute until the halt signal is fired, or the execution reaches the end of the on_init listener.

Extensions

A simple I/O extension:

signal print_h
# prints the ASCII character 'h'
listener on_print_h {
    emit out_0
    emit out_1
    emit out_1
    emit out_0
    emit out_1
    emit out_0
    emit out_0
    emit out_0
}

# simple cat
listener on_in_1 {
    emit out_1
}

listener on_in_0 {
    emit out_0
}

listener on_init {
    # print 'h'
    connect print_h and on_print_h
    emit print_h
    # begin cat program
    connect in_1 and on_in_1
    connect in_0 and on_in_0
}

With this IO extension there are 4 signals added:

  • out_0: push a 0 bit to the output when emitted
  • out_1: push a 1 bit to the output when emitted
  • in_0: emits when a 0 bit is pushed to the input
  • in_1: emits when a 1 bit is pushed to the input

The in signals work as interrupts. When the signals are emitted, the execution of the program is paused, and connected listeners are executed until they all reach the end of their definitions, then the program resumes where it was.

The input and outputs are handled as queue buffers. The output queue will typically output to the final destination as soon as 8 bits have been output. The input queue will fire its signals as soon as it receives bits, firing them one at a time as interrupts.

Computational class

The language is Turing complete. Proof forthcoming.

Variants

A variant where disconnecting a listener only disconnects at most one would also be Turing complete, and would be easier to implement counter machines in. A variant where signals can only have at most one of each listener connected would be in the class of finite state automata, since there would be a finite amount of state that could be stored at a given time.

In other languages

  • GDScript has an esoteric subset which is similar to Signals, but listeners can only be connected to a signal at most once