signal 1.0.2

Smart Signals implementation. Supports optional arguments and any number of arguments, strictly typed.

Released 2016-08-06.

To install, run:

haxelib install signal 1.0.2

See using Haxelib in Haxelib documentation for more information.

Current version1.0.2
StatisticsInstalled 326 times

Simple & Smart cross-platform useful implementation of Signals without any dependencies.

Build status


Compatible with targets:

  • Flash
  • Java
  • Neko
  • C++
  • PHP
  • JS
  • Python
  • Lua

C# in future plans.


Stable release: haxelib install signal.

Development version: bash haxelib hg signal

Then add to your hxml: -lib signal.


This is almost classic signals and really simple to use.

haxe // create signal with one argument:Int: var signal = new Signal();

// add listener: signal.add( function(value:Int) trace("1: " + value) );

// add "one-shot" once listener: // there second optional argument is true: signal.add( function(value:Int) trace("2: " + value) , true);

// dispatch - invoke all listeners: signal.dispatch(42); // traces: "1: 42" , "2: 42"

// dispatch again: signal.dispatch(42); // traces: "1: 42"

haxe // signals based on any types and its numbers: // signal without args new Signal()

// signal on Int new Signal()

// signal on any what we want new Signal, Foo, Bar, ?(?String -> Predicate) -> Bytes>()

And we have neat completion by Haxe compiler!


and type-checks

type checks

See tests for more examples.

Advanced Usage:

haxe // create signal from function-type: var signal:Signal Bool>; // add listener: signal.add( function(f:Int -> Bool) f() ); // dispatch: signal.dispatch( function(v:Int) return v % 2 == 0 );

haxe // create signal from function-type ending with Void: // it will expanded to Signal var signal = new Signal Void>(); signal.dispatch(42);

haxe // create signal from function-type with Optional arguments: var signal = new Signal<?Int -> ?Bool -> Void>(); signal.add( function(?value:Int, ?is:Bool) trace('$value is $is') ); signal.dispatch(); // trace: " is " signal.dispatch(42); // trace: "42 is " signal.dispatch(true); // trace: " is true"

Standard behavior:

I think I shall not describe in detail the behavior of a standard signal.

In short, we have a signal as a dispatcher. And two kinds of handlers/listeners: ordinary - lives until it is killed; once - one-shot throwaway listener.

We can add listener: ordinary: mySignal.add(myListenerFunction); once : mySignal.add(myListenerFunction, true);

We can get a typed VO named Slot when doing add the listener: haxe var slot = mySignal.add(myListenerFunction);

Also we can try to get a slot by the listener: haxe var slot:Null = mySignal.get(myListenerFunction);

Now we can remove listener: mySignal.remove(slot); or slot.dispose();

How to create the signal? or how the macro-generator works for signals

With required arguments:

haxe var s:Signal;

s = new Signal() // is signal with `dispatch()` without arguments
s = new Signal<Void>() // same
s = new Signal<Void, Void>() // too
s = new Signal<Void -> Void>() // same too (look, function type-param!)

var s1 = new Signal() // is signal with dispatch(arg:Foo) with one argument

s1 = new Signal<Foo -> Void>() // same (look, function type again!)

var s5 = new Signal() // is signal with dispatch with five argument

s5 = new Signal<Foo -> Bar -> C -> D -> E -> Void>() // same

With optional arguments - only with one Function-type parameter:

haxe var s1 = new Signal<?Foo -> Void>() // produce function dispatch(?arg:Foo)

s1.dispatch(); // we can omit opt arg

var s2 = new Signal ?Bar -> Void>() // same but two args where second is optional


It works only for single type-parameter passed to Signal< > and type should ending with Void. For example: ?Foo -> Void and not ?Foo -> Bar because method dispatch can't return anything except nothing (Void).

Signal as Monomorph (think "any Signal")

Also works really cool with Monomorph from library "quasix".

Simply add to your hxml: -lib quasix and use cool syntax. It look like a classic var m:Map<String, Float> = new Map() with omitted type-parameters in the right part.

haxe // no need params here: -----. var s:Signal> = new Signal(); s.dispatch(42, []);


haxe // .------ no need params there: var s:Signal = new Signal>(); s.dispatch(42, []);

without casting and any runtime overhead.

Special behaviors:

These things are a little slower, but they provide safety.


  • signal-stoppable enable truth stopPropagation-like behavior for method Signal.stop();
  • signal-safety helps if if its slot is disposed; if next slot is disposed; if this signal is disposed; when "one-shot" listener with sub-call .dispatch() for current signal;
  • prevent-signal-looping throw or trace exception about founded loop.
  • signal-strict more strict typing for Signal's optional TypeParams, e.g. for Signal based on ?Int -> Bool -> Void the first param should be optional in listener if strict is enabled. For example see what types we can use as listeners for Signal<?Int -> Bool -> Void>: * in case if -D signal-strict is defined - optional parameter always only optional:

    * `?Int -> Bool -> Void`
    * `?Int -> ?Bool -> Void`
    • in case if signal-strict is false/0 or not defined - listener can be: Int -> Bool -> Void ?Int -> Bool -> Void Int -> ?Bool -> Void ?Int -> ?Bool -> Void
  • signal-debug TODO: not implemented yet.

    • -

For more (complex) examples checkout unit-tests.

no more type hell!