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

To install, run:

haxelib install signal 1.0.2 

See using Haxelib in Haxelib documentation for more information.

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!

1 year ago

All libraries are free

Every month, more than thousand developers use haxelib to find, share, and reuse code — and assemble it in powerful new ways. Enjoy Haxe; It is great!

Explore Haxe

Haxe Manual

Haxe Code Cookbook

Haxe API documentation

You can try Haxe in the browser!

Join us on Github!

Haxe is being developed on GitHub. Feel free to contribute or report issues to our projects.

Haxe on Github