Generic Class that can call Generic Functions

75 views
Skip to first unread message

harp...@gmail.com

unread,
May 20, 2013, 1:40:49 PM5/20/13
to haxe...@googlegroups.com
Hi All,

I would like to make a generic class where the type is a single parameter function.  I'd then like the class to be able to call assigned functions of that type.  As an example:

class SimpleCase<T>
{
var delegate : T;
public function new(func : T) 
{
delegate = func;
}
public function Call()
{
delegate("bar");
}
}

This code, however, won't compile:

src/sharpEvent/SimpleCase.hx:23: characters 2-10 : sharpEvent.SimpleCase.T cannot be called

Makes sense, 'T' could be anything, so can't treat it like a function.  I thought maybe if I constrained T that would produce the behavior I was looking for:

class SimpleCase<T : (String -> Void) >
{...

But that produces the same 'T cannot be called' error.

So I'm stumped.  Is there a good way to do this?

Cheers!
Caleb

As an aside, I'd just like to thank everyone for their hard work on HaXe.  It's been a real pleasure to learn.

Renaud Bardet

unread,
May 20, 2013, 2:40:47 PM5/20/13
to haxe...@googlegroups.com
Hi Caleb,

indeed that won't work, could you explain what's your practical case of this ?
I think you may rather try something like :
class SimpleCase<T:String,U>{
   
var delegate:T->U ;
   
public function new(f:T->U)
   
{ delegate=f ; }
   
public function call():U delegate("bar")
}

but again I don't know what you expect to do with it so it may not be the best answer

Dima Granetchi

unread,
May 20, 2013, 5:52:46 PM5/20/13
to haxe...@googlegroups.com

harp...@gmail.com

unread,
May 21, 2013, 12:13:53 AM5/21/13
to haxe...@googlegroups.com
Renaud and Dima -- Thanks for your replies!

Dima:  Well, that code certainly does work.  I hadn't come acros PosInfos before, but even after looking it up, I have no idea why it works.


Renaud:  I was trying to make a class to emulate C# events.  An event is defined with a function type, and then functions matching that type can be attached and called all at once.  Using your approach works, but the number of input arguments is fixed.  

My code is below.  I'm sure there is a more HaXe appropriate way to achieve this result, so feel free to point me in the right direction.

class SharpEvent<T, U>
{
private var eventListeners : List<T -> U>;

public function new() 
{
eventListeners = new List<T -> U>();
}
public function AddListener(listener : T -> U)
{
eventListeners.add(listener);
}
public function RemoveListener(listener : T -> U)
{
//in case there are multiple of them in there
while (eventListeners.remove(listener)) {}
}
public function RaiseEvent(T)
{
for (listener in eventListeners)
{
listener(T);
}
}
public function Destroy()
{
eventListeners = null;
}
public function ToString() : String
{
return Std.string(eventListeners.length) + " listeners " + eventListeners.toString; 
}
public function NumberOfListeners() : Int
{
return eventListeners.length;
}

  
Cheers!
Caleb

On Monday, May 20, 2013 4:52:46 PM UTC-5, Dima Granetchi wrote:
small trick http://try.haxe.org/#EA6D9

Renaud Bardet

unread,
May 21, 2013, 1:11:45 PM5/21/13
to haxe...@googlegroups.com
Ok I see what you're trying to do,

first a quick clarificaiton on PosInfo,
it's a very special type that cannot be instanciated but if present in a method signature will be filled at compile time :
var pos = new haxe.PosInfos() ; // build failed:haxe.PosInfos cannot be constructed

////

class Test {
  static function main(){
    Tracer.customTrace("Hello World!") ; // Test.hx:3: Hello World!
  }
}

class Tracer {
  public static function customTrace(s:Dynamic, ?p:haxe.PosInfos)
  {
    js.Lib.alert( p.fileName +':'+ p.lineNumber +": "+ s ) ;
  }
}

As you can see we use ?p:haxe.PosInfos in the method signature and call customTrace with only the first parameter,
now with every other type that would result in p being null, but for PosInfos the compiler will instead create an instance of PosInfos containing the position where the function was called

Of course if we were to pass a PosInfo instance (created from a higher call function) it wouldn't be overriden

The main use for PosInfos is for trace, you can easily setup your own trace, for a fancy/customized trace or compatibility with other loggers (MonsterDebugger, remote logger, etc...) by affecting your  customTrace function to haxe.Log.trace
haxe.Log.trace = Tracer.customTrace ;
trace("plop") ; // will show an alert "File.hx:X: plop"


Going back to your problem I think your approach is right, and I don't really know why the compiler doesn't realize T is a function but I'd rather think it as a bug/unattended behavior,
Dima's solution is ok, the Haxe world revolves around those little hacks, you could also use this :
public function Call()
{
   untyped delegate("bar") ;
}

Cheers,
Renaud

Simon Krajewski

unread,
May 21, 2013, 1:14:13 PM5/21/13
to haxe...@googlegroups.com
Am 21.05.2013 19:11, schrieb Renaud Bardet:
Ok I see what you're trying to do,

first a quick clarificaiton on PosInfo,
it's a very special type that cannot be instanciated but if present in a method signature will be filled at compile time :
var pos = new haxe.PosInfos() ; // build failed:haxe.PosInfos cannot be constructed

////

class Test {
  static function main(){
    Tracer.customTrace("Hello World!") ; // Test.hx:3: Hello World!
  }
}

class Tracer {
  public static function customTrace(s:Dynamic, ?p:haxe.PosInfos)
  {
    js.Lib.alert( p.fileName +':'+ p.lineNumber +": "+ s ) ;
  }
}

As you can see we use ?p:haxe.PosInfos in the method signature and call customTrace with only the first parameter,
now with every other type that would result in p being null, but for PosInfos the compiler will instead create an instance of PosInfos containing the position where the function was called

Of course if we were to pass a PosInfo instance (created from a higher call function) it wouldn't be overriden

The main use for PosInfos is for trace, you can easily setup your own trace, for a fancy/customized trace or compatibility with other loggers (MonsterDebugger, remote logger, etc...) by affecting your  customTrace function to haxe.Log.trace
haxe.Log.trace = Tracer.customTrace ;
trace("plop") ; // will show an alert "File.hx:X: plop"


Going back to your problem I think your approach is right, and I don't really know why the compiler doesn't realize T is a function but I'd rather think it as a bug/unattended behavior,

Please file an issue and we will have a look at it.

Simon
Reply all
Reply to author
Forward
0 new messages