Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using functions as map keys in Haxe

Tags:

haxe

I want to use functions as keys in a Map like this:

var timers : Map<Void->Void, snow.api.Timer>;

But Haxe won't compile:

Abstract Map has no @:to function that accepts IMap<Void -> Void, snow.api.Timer>

Is there a way to do this ?

like image 990
Vianney Thurotte Avatar asked Nov 25 '25 04:11

Vianney Thurotte


2 Answers

It's easy to write a custom implementation:

import haxe.Constraints;

class FunctionMap<K:Function,V> implements IMap<K,V> {
  private var _keys : Array<K>;
  private var _values : Array<V>;

  public function new () {
    _keys = [];
    _values = [];
  }

  public function get(k:K):Null<V> {
    var keyIndex = index(k);
    if (keyIndex < 0) {
        return null;
    } else {
        return _values[keyIndex];
    }
  }

  public function set(k:K, v:V):Void {
    var keyIndex = index(k);
    if (keyIndex < 0) {
        _keys.push(k);
        _values.push(v);
    } else {
        _values[keyIndex] = v;
    }
  }

  public function exists(k:K):Bool {
    return index(k) >= 0;
  }

  public function remove(k:K):Bool {
    var keyIndex = index(k);
    if (keyIndex < 0) {
        return false;
    } else {
        _keys.splice(keyIndex, 1);
        _values.splice(keyIndex, 1);
        return true;
    }
  }

  public function keys():Iterator<K> {
    return _keys.iterator();
  }

  public function iterator():Iterator<V> {
    return _values
        .iterator();
  }

  public function toString():String {
    var s = new StringBuf();
    s.add("{");
    for( i in 0..._keys.length ) {
        s.add('<function>');
        s.add(" => ");
        s.add(Std.string(_values[i]));
        if( i < _keys.length - 1 )
            s.add(", ");
    }
    s.add("}");
    return s.toString();
  }   


  private function index(key:K) : Int {
    for (i in 0..._keys.length) {
        if (Reflect.compareMethods(key, _keys[i])) {
            return i;
        }
    }
    return -1;
  }}

http://try.haxe.org/#DdF31

like image 192
RealyUniqueName Avatar answered Nov 28 '25 00:11

RealyUniqueName


I just tried this in try.haxe.org, and the compiler doesn't seem to like it, so I'm guessing the answer is "no."

You could get around this with some cleverness:

class Test {
    static function main() {
        var map:Map<VoidVoid,String>;
        map = new Map<VoidVoid,String>();
        var thing = {func:foo};
        map.set(thing,"bar");
        trace(map.get({func:foo}));  //fails
        trace(map.get(thing));       //succeeds;
    }

    static function foo():Void
    {

    }
}

typedef VoidVoid = {
    var func:Void->Void;
}

But that's not an ideal solution because wrapping it in a typedef like that will make it fail if it's not the exact same instance, even if the value inside is the same.

I also tried making a Map<Dynamic,String> since you can stuff function references in those, but that didn't work either.

At this point I should ask, what problem are you trying to solve this way? Perhaps it could be better solved some other way.

like image 38
larsiusprime Avatar answered Nov 28 '25 01:11

larsiusprime



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!