Skip to main content

Callables and signals

0.1.1

Binding a name to a function, and broadcasting to any number of listeners.

Callables

callables.sar
callable whats_the_name = name_change

func name_change(name string) string {
    return "Mr. " + name
}

func main() {
    local var name string = "Bobby"
    print(whats_the_name(name))

    local callable greet = name_change
    print(greet("Alice"))
}

A callable binds a name to a function that is already declared. callable name = function_name takes no parameter list and no type annotation: the callable carries the signature of the function it names. Calling it uses ordinary call syntax, so a callable is interchangeable with the function at every call site.

Declare a callable at the top level of a file, or inside a function with local callable. The target must be a declared function. Naming a function that does not exist reports function 'name' was not found, and reusing a name that a global or another function already holds reports name 'name' is already declared.

Signals

signals.sar
signal name_changed(name string)

func report_name(name string) {
    print(name)
}

func main() {
    local callable listener = report_name

    name_changed.connect(listener)
    emit name_changed("Bobby")

    name_changed.disconnect(listener)
    emit name_changed("Nobody")
}

A signal declares a typed broadcast. signal name(parameters) takes a parameter list written exactly like a function's, and declares no body. Signals are declared at the top level of a file only; a signal cannot be declared inside a function.

connect adds a listener, disconnect removes one, and emit name(arguments) calls every connected listener with those arguments. A listener is a function or a callable whose parameters match the signal. Emitting a signal that was never declared reports signal 'name' was not found.

Connection rules

order.sar
signal changed(value int64)

func first(value int64) {
    print("first " + value)
}

func second(value int64) {
    print("second " + value)
}

func main() {
    changed.connect(first)
    changed.connect(second)
    changed.connect(first)

    emit changed(1)
}

Listeners are called in the order they were connected, so this program prints first 1 and then second 1.

Connecting the same listener twice does nothing the second time. A signal holds each listener once, so the third connect above is ignored and first still runs once per emit. Disconnecting a listener that is not connected does nothing.

Emitting a signal with no listeners is valid and does nothing. Connecting and disconnecting during a program run are both allowed at any point after the signal is declared.