EventHandler (like in C#) for Haxe

Hi there! I’m wondering if it’s possible to implement the same EventHandler API C# has in Haxe.

My initial try was doing this (try haxe link)

class EventHandler<T> {
  private var handlers: Array<T> = [];

  public function new () {}

  @:op(A + B)
  public function add(func: T) {
    this.handlers.push(func);
  }
}

class Main {

  public static function main() {
    var h = new EventHandler<String->Void>();
    h += function(str: String) {
      trace(str);
    }
  }
}

Then I receive an error, meaning that I cannot perform a += operator on different types:

Test.hx:16: lines 16-18 : Cannot add EventHandler Void> and str : String -> Void

Is this something possible to achieve? Thanks!

Classes don’t support operator overloading in Haxe, only abstracts do. The usual workaround is to rename the class to something like EventHandlerImpl and wrap it an abstract.

Here is a complete sample:

import haxe.Constraints.Function;

using Test;

class Test {
  static function main() {
    var e = new EventHandler<String->Void>();
    e += function(s) trace('$s, world');
    e += function(s) trace('$s, haxe');
    e.dispatch('Hello!');
  }
}

abstract EventHandler<T:Function>(Array<T>) {
  var handlers(get,never):Array<T>;
  inline function get_handlers() return this;
    
  public inline function new() {
    this = [];
  }
  
  @:op(a += b) inline function add(fn:T) {
    this.push(fn);
  }   
}

class EventHandlerDispatcher1 {
  public static inline function dispatch<T>(e:EventHandler<T->Void>, arg:T) {
    for(fn in @:privateAccess e.handlers) {
      fn(arg);
    }
  }
}

class EventHandlerDispatcher2 {
  public static inline function dispatch<T1,T2>(e:EventHandler<T1->T2->Void>, arg1:T1, arg2:T2) {
    for(fn in @:privateAccess e.handlers) {
      fn(arg1, arg2);
    }
  }
}

//... for whatever amount of arguments

http://try-haxe.mrcdk.com/#3562d

2 Likes

Thanks @ReallyUniqueName, this really helped me a lot! I’ve also added a -= operator based on your implementation :slight_smile:

There’s one caveat though, when defining EventHandler on another file, the compiler cannot understand the dispatch() method. Do you know how this can be fixed?

Test.hx:8: characters 4-14 : EventHandler Void> has no field dispatch

http://try-haxe.mrcdk.com/#D1980

Thanks for your time!

Instead of import EventHandler do using EventHandler: Static Extension (Language Features) - Haxe - The Cross-platform Toolkit

Thanks again! I’m now using this implementation for handling events in colyseus-hx: https://github.com/colyseus/colyseus-hx/commit/7b5206af04de8c139420fc3508a510ce0b9236b0

:hugs: