Closed shohei909 closed 4 years ago
Two questions:
this
)? This can get confusing when the function actually has parameters. . Please complete the Util.set()
function in this example. I'm personally not sure if its a good idea to allow such static access.interface XY {
var x:Int;
var y:Int;
function set(x:Int, y:Int):Void {
this.x = x;
this.y = y;
}
}
class Util {
public static function set(scope:XY, x:Int, y:Int):Void {
// this?
IPoint.set(scope, x, y);
// or this?
IPoint.set(x, y, scope);
}
}
super
in both the interface (when extending) or the overridden function in the concrete class? and can you add examples how that looks like?I don’t think this will work. I recommand the abstract class proposal, for a few reasons:
extends
and implements
becomes purely formal (you would have to use implements
, and yet it would actually be the same as an extension if you just changed the interface
to a class
).Is the first or the last argument of the interface function automagically the instance (this)?
The first argument should be (this), like abstract (https://try.haxe.org/#dbEde).
So (scope, x, y)
is correct.
Can you still use super in both the interface (when extending) or the overridden function in the concrete class? and can you add examples how that looks like?
I think calling interface methods with super.method()
should not be allowed. Allowing it will cause confusion, when extending a class and implementing interfaces have same name method which have bodys.
interface N {
public function sample():Void {
trace("N");
}
}
class M {
public function sample():Void {
trace("M");
}
}
class O implements N extends M {
public override function sample():Void {
// `super.method()` should be only for class method.
super.sample(); // M
}
}
- If some method of an interface can have an implementation, it implies all of them also can. In those cases the distinction between extends and implements becomes purely formal.
In other hand, abstract class may not have implementation for all methods, and we will not able to use implements
. I don't think both of them are much of a problem.
- previous point implies with default implementation in interfaces, multiple inheritance would then be allowed (you can implement several interfaces); so I don’t think it’s possible.
It is actually possible. The Conflict section is the solution.
This seems like an anti-feature to me... I don't want implementation details in my interfaces. I also don't want multiple inheritance (at least not as a default/first-class behavior). I'd really like interfaces to be simple "contracts".
If we need multiple inheritance in a library, I'd like it to use some other keyword/pattern so that the behavior there is clearly specified. Multiple inheritance code requires you to better understand the field resolution patterns at work for the resulting class. I don't want to worry about all this every time I see the "implements" keyword.
I'm with Justin on this and share the same concerns.
My proposal seems too short to respond to the concerns. I'll make some additions to this proposal.
I don't like this feature and I think interfaces should be pure contracts.
I can agree with one valid use-case for this: backward compatibility and I know C# recently added such feature exactly for this case, but they made it very explicit and awkward to use as a general "mixin /multiple-inheritance" feature to discourage people from abusing it. And I don't think Haxe needs this at the moment as we haven't reached .NET level of ecosystem complexity yet :) So for now, "there's a macro for that". (c)
One part that I think is somewhat useful is real static
functions within an interface - it would be nice for the "factory" methods that return one or another implementation of an interface.
I added detail.
An important point is @:using
for interface. I want to hear how do you think about it.
As I remember, this feature was already rejected by the team: https://github.com/HaxeFoundation/haxe-evolution/pull/54
We have decided to reject this proposal in our haxe-evolution meeting yesterday.
The reasons were already stated: We don't like having code in interfaces because it mixes concepts. While there might be some merit to this in the Java world, it is not a good fit for Haxe.
Interesting -- I have no comment on the implementation as proposed, but I do love my DefaultImplementation
macro. It's one of my favorites, I'd hesitate to do a project without it.
tl,dr: I like def impl, it has its place, but it's workable as a macro (vs getting everyone to agree on one implementation.)
As for "the interface should be separate from the implementation / pure contract" -- that's one use case of interfaces. I'd suggest "the interface implies (some set of) the implementation" is a distinct and equally valid use case, that's more DRY. Whatever you call it -- decorator / mix-in / default implementation -- it's deciding that some features don't fit neatly into a class hierarchy. And interface defaults is DRY while retaining Haxe's type-safe features.
e.g. I have an IDisposable
interface the provides a set of destructor features to any class I want. There's no hierarchical implications (no common base class necessary). They all provide the same interface, but the boilerplate code exists in just one place. Interfaces may be partially default-specified, leaving some functions to the class. The interface may define function implementations as @:final
, whereby the class is not allowed to specify that function.
My events / pubsub classes, my controller classes, my display classes -- all implement IDisposable
-- why would they have any common base class? Or, why would I want to paste the same boilerplate code into each?
It's really quite tidy. But, it works fine as a macro, and naturally, I'm partial to the way I did it. :wink: :stuck_out_tongue:
why not implement partial interfaces, but require explicit definition this would solve the problem of interfaces being contracts, as normal interfaces are contracts, but would still allow partial interfaces to be implemented. As jcward states, this makes DRY code easier. making DRY code shouldn't require installing an external library.
@:partial
interface Example {
public function doSomething():Void {
trace("does something");
}
}
Thinking about this after learning haskell and rust, this turns interfaces into traits, which I think would be a very good thing. Traits in general imho are a better model for inheritance as it allows multi inheritance.
why not add traits? yes, I know this is a huge feature, but that seems like the only hope for a feature like this getting in
An alternative to abstract class(#69).
Rendered version