Interface method with variable arguments
Community Forums/Monkey2 Talk/Interface method with variable arguments
| ||
Is this something that could be achieved / added to MX2? The ability to specify that the implementing class must have the method defined, but the arguments are not hard coded. e.g. You can achieve this in MX1 as shown below, but it would be a nice thing to add, removing the redundant Setup definition in each class. Function Main:Int() Local ent:GameEntity = New GameFood ent.Setup() End Interface GameEntity Method Setup:Void() End Class GameFood Implements GameEntity Method Setup:Void() End Method Setup:Void(name:String) End End Class GameWeapon Implements GameEntity Method Setup:Void() End Method Setup:Void(attack:Int, level:Int) End End |
| ||
I can't see how you could keep type safety here. Example, given that item is of kind IGameEntity, which has a Setup:Void(*) declaration: Function DoSomething(item:IGameEntity) item.Setup( ?????? ) '--> Which signature to use to call this method?? End |
| ||
> You can achieve this in MX1 as shown below, I can't see what that achieves though - the GameEntity interface can't be used for anything as it only contains the void() method which doesn't actually do anything. But in general, this wouldn't be easy to do - it'd have to be done dynamically at runtime via box objects and type checking etc - the end result would be something like: Interface GameEntity Method Setup:Void( params:SetupParams ) End Class GameThing Implements GameEntity Method Setup:Void( params:SetupParams ) Local p:=GameThingParams( params ) If Not p Error "Runtime typing sucks!" ...OK to use p... End End |
| ||
You might be better off using a generic for that:Interface GameEntity<P> Method Setup:Void(params:P) End Class SetupParams ' common params go here End Class FoodParams Extends SetupParams Field name:String Method New(name:String) Self.name = name End End Class WeaponParams Extends SetupParams Field attack:Int, level:Int Method New(attack:Int, level:Int) Self.attack = attack Self.level = level End End Class GameFood Implements GameEntity<FoodParams> Method Setup:Void(params:FoodParams) Local name := params.name End End Class GameWeapon Implements GameEntity<WeaponParams> Method Setup:Void(params:WeaponParams) Local attack := params.attack Local level := params.level End End Local food := New GameFood(New FoodParams("apple")) Local weapon := New GameWeapon(New WeaponParams(1, 2)) Bounded generics would be nice here too, if you could define it as: Interface GameEntity<P Extends SetupParams> Which prevents you from doing: Class Foo Extends GameEntity<String> Something else I'd love to see is default/optional interface methods like in Objective-C and Java 8! :) |
| ||
I wasnt really requesting a catch-all for variable argument length, but instead a way to just specify that said class should implement a method of any variety. A way to enforce a pattern onto implementers. The compiler could work out if the implementing class has the method. If there is no matching method definition (but there IS at least 1) it could just ignore the call. Maybe even the nearest call is found and null values auto filled. So basically as an engine developer I can require users to Implement Setup(). The user can implement any variety of Setup() and that will count. If the compiler cant find a matching Setup(), but there is at least 1 Setup(), it can still compile. I can see this is a kind of "out there" request and not very strict. It came from writing some engine code and then implementing "Setup()" differently in each implementing class. It would be nice if there was some way to enforce the Setup() method and provide a safe way for it to be called regardless of arguments used. A boxing/unboxing of variables would work as described, but it would be quite a lot of overhead. |
| ||
Bounded generics would be nice here too, if you could define it as: Interface GameEntity<P Extends SetupParams> Which prevents you from doing: Class Foo Extends GameEntity<String> Something else I'd love to see is default/optional interface methods like in Objective-C and Java 8! :) +1 to both of these. Especially optional methods. I am sure I read that it was being added, but to argue why this is a benefit, we can create grouped delegate interfaces and then the implementer can just implement the methods appropriate for their use. |
| ||
@Skn3: I wasnt really requesting a catch-all for variable argument length, but instead a way to just specify that said class should implement a method of any variety. I really don't see the point of this though. The point of an interface is to define a solid contract such that anything that uses it shouldn't care about the internal implementation, just the method signatures. If the concrete method signatures are not known at compile time (especially if we're using reflection), all kinds of gremlins could pop up. Knowing that a class implements a "Setup" method is useless if you don't know the arguments. Local name:String = (read class name string from a file) Local ci:ClassInfo = GetClass(name) Local obj:GameEntity = GameEntity(ci.NewInstance()) obj.Setup(...) ' compiler doesn't know what concrete type it is |
| ||
Well in current monkey there is an issue that if you re extending a class and you try and use a method that exists in the base class, you then cant have a different set of arguments in the extended class. It complains that the method doesn't match any of the base implementations. My proposed idea (albeit a bit wacky) might have been a solution to that. I can see though that is probably a little dangerous. Is there another solution to this problem then? or is this a quirk that MX2 doesn't have? I had started using SetupClassNameHere() to avoid name conflicts, but this just seems a bit rough to me. |
| ||
> It complains that the method doesn't match any of the base implementations. Fixed in monkey2! |
| ||
Good news! |