-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Polymorphic this
types
#36
Conversation
I added a link to the rendered version so one can easily view the proposal markdown document. |
As a first thought, isn't this what static extensions are supposed to solve? Why would that mechanism be insufficient? (https://try.haxe.org/#01b82) using Test.Calculator;
class BasicCalculator {
public var result = 0.0;
public function new () {}
public function add(a: Int): BasicCalculator {
result += a;
return this;
}
}
class Calculator {
public static function sin(c:BasicCalculator): BasicCalculator {
c.result = Math.sin(c.result);
return c;
}
}
class Test {
static function main() {
var calculator = new BasicCalculator();
var result = calculator.add(2).add(3).sin().result; // <-- Totally possible in current Haxe
}
} |
@EricBishton I agree that you solved this specific example with a static extensions. In general it is not the same though: you cannot override a method in BasicCalculator. You can also just add methods, not properties. You could not extend BasicCalculator with a static extension like in this example: enum Mode {
RAD;
DEG;
}
class Calculator extends BasicCalculator {
public var mode: Mode;
public function sin() {
if( this.mode == RAD)
this.result = Math.sin(this.result);
else
this.result = Math.sin(this.result/180*Math.PI);
return this;
}
}
class Test {
static function main() {
var calculator = new Calculator();
calculator.mode = DEG;
var result = calculator.add(2).add(3).sin().result;
}
} Also static Extensions do not help in creating Extern definitions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed 2 little bugs in the code examples.
I wonder if this should be a type inference feature, if you leave out the return type definition, it works? Then |
@markknol Actually we do NOT have that now. Currently the return type By providing |
Just want to mention that @andyli once wrote this very nice article: But I'd love to have polymorphic this type too, I use a lot of chaining too. |
@markknol thanks for the link. Did not even see that before. So this is actually a pretty "ok" workaround for this case. |
Feel free to take it to the cookbook. I'm glad that little post is still useful. :) |
I'd like to also be able to do this: class Some {
static function doSomething():this {
var inst = new this();
return inst;
}
static function doAnotherThing():Class<this> {
return this;
}
} Which will allow to:
Maybe make it a reserved class name |
We discussed this proposal and came to a conclusion it could be useful. However, @Simn has no clear vision how to implement it and needs to do a research first. |
The link is dead. Did anyone ever add this to the cookbook? I couldn't find anything related. |
@fullofcaffeine the site is up again, please PR it for the cookbook 🥇 |
this
types
What happens if the "this" class has type parameters? |
I suppose it would always be the same as the "context"? $type(foo) == $type(foo.getThis()); // for all concrete T
class Base {
function getThis():this;
}
class Foo<T> extends Base {} |
I don't like method chaining, so I didn't care much about this proposal, but I just stumbled upon a piece of code where polymorphic class BaseButton {
function setClickCallback(cb:This->Void);
}
class TabButton extends BaseButton {
function someExtraApi();
}
// and then
var button = new TabButton();
button.setClickCallback(onTabClicked);
function onTabClicked(tab:TabButton) {
tab.someExtraApi();
} |
We didn't reach a consensus on this one in our haxe-evolution meeting yesterday. There's agreement that this would be useful, but how to actually implement it remains unclear. I don't want to accept a proposal if I don't know to actually implement it, so for the time being this will remain open. |
I also find this useful, but I can see a few unresolved questions:
// currently this doesn't work because function arguments are contravariant
interface Base {
function set(v:Base):Void;
}
interface Derived extends Base {
function set(v:Derived):Void;
}
// Does that mean the compiler will reject the following?
interface Base {
function set(v:This):Void;
} Possible solution: only allow
class Base {
public function get():This {
return new Base(); // is this valid? If yes, it will break in derived classes, and they must override this method. Can the compiler detect this though?
}
}
class Derived extends Base {
public var derived:Int;
}
new Derived().get().derived; // runtime error: instance of Base has no field derived Possible solution: only
interface Base {
function get():This;
}
class BaseClass implements Base {
public function get():BaseClass; // is this implementation valid? and how about derived classes/interfaces again?
} Possible solution: Implementations must exactly match |
lean-reject: too many unanswered questions |
We have rejected the proposal in the haxe-evolution meeting today. There have been long-standing open questions that have not been answered, which we interpret as the feature potentially being "nice to have", but not important enough to the general interest. Importantly, we do not reject the feature of a this-type per-se, but rather the proposal itself on these grounds. A new proposal that aims to answer open questions could lead to further discussions, and possibly acceptance. |
Rendered version