Skip to content
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

Allow classes to extend abstracts #11118

Closed
EliteMasterEric opened this issue Apr 11, 2023 · 7 comments
Closed

Allow classes to extend abstracts #11118

EliteMasterEric opened this issue Apr 11, 2023 · 7 comments

Comments

@EliteMasterEric
Copy link
Contributor

Allowing classes to extend abstracts would be useful:

class Foo {
    public function new() {}

    public function value():Int { return 1; }
}

abstract Bar(Foo) {
    public function new() {
        this = new Foo();
    }

    // Calls to this function look like:
    // Bar_Impl_.doubleValue(foo_inst);
    public function doubleValue():Int {
        return 2 * this.value();
    }
}

// In the current version of Haxe, this would throw a compilation error.
// Instead, it should look like:
// class Baz extends Foo
class Baz extends Bar {
    public function new() {
        super();
    }

    // This function's body should look like:
    // return 2 * Bar_Impl_.doubleValue(this) + this.value();
    public function quintupleValue():Int {
        return 2 * this.doubleValue() + this.value();
    }

    // This should work as expected.
    public override function value():Int { return 3; }

    // This should throw a compilation error:
    // Cannot override a function declared in a parent abstract
    public override function doubleValue():Int;
}

If this is too big of a change to be considered a normal enhancement, let me know and I can draft a HaxeEvolution proposal.

@Simn
Copy link
Member

Simn commented Apr 11, 2023

Yeah this would definitely need a haxe-evolution! I'll tell you right now though that this has not a high chance of acceptance unless you somehow manage to present a killer use-case. I have no intuition for what "class extending abstract" means, which is never a good starting point for language additions.

@Simn Simn closed this as completed Apr 11, 2023
@EliteMasterEric
Copy link
Contributor Author

I have no intuition for what "class extending abstract" means

The basic intuition for "class extending abstract" is that the class extends the underlying type of the abstract while also allowing calls to the abstract's methods.

@Simn
Copy link
Member

Simn commented Apr 11, 2023

But then that just completely breaks the abstraction.

@EliteMasterEric
Copy link
Contributor Author

@nanjizal
Copy link
Contributor

nanjizal commented Jul 29, 2023

https://try.haxe.org/#c7e7A03E

class Foo {
    public function new() {}

    public function value():Int { return 1; }
}

abstract Bar(Foo) from Foo {
    public function new() {
        this = new Foo();
    }
    public function doubleValue():Int {
        return 2 * this.value();
    }
}

class Baz extends Foo {
    final bar: Bar;
    public function new() {
        super();
        bar = ( this: Bar );
    }
    public function quintupleValue():Int {
        return 2 * this.doubleValue() + this.value();
    }
    public override function value():Int { return 3; }
  	public function doubleValue():Int{
			return bar.doubleValue();
  	};
}

class Test {
  static function main() {
    var baz = new Baz();
    trace( baz.quintupleValue() );
  }
}

Having a property seems to mostly disappear in the analyser, so while a few modifications are needed and minor compromise the limitation can be worked around, or maybe this suggests an implementation approach.
Anyway was just curious so my haxe try take on it.

@nanjizal
Copy link
Contributor

nanjizal commented Aug 1, 2023

https://try.haxe.org/#23A39292
in fact you don't even need a real property or to set it in super.

  var bar( get, never ): Bar;
  private inline function get_bar():Bar{
       return ( this: Bar );
  }

the down side you can't override, you would need to setup the redirection for all the Bar abstract types methods in the inherited class, which is a little manual/awkwardly different from just override, but it is a fairly obvious and easy approach to follow.

public function doubleValue():Int{
     return bar.doubleValue();
 }

but the code seems fairly clean in js output atleast. But can imagine allowing the main to and from to use Bar could be messy internally if extending abstracts was implemented. ( with some more inlines the js out gets even shorter ).

@EliteMasterEric
Copy link
Contributor Author

https://try.haxe.org/#23A39292 in fact you don't even need a real property or to set it in super.

  var bar( get, never ): Bar;
  private inline function get_bar():Bar{
       return ( this: Bar );
  }

the down side you can't override, you would need to setup the redirection for all the Bar abstract types methods in the inherited class, which is a little manual/awkwardly different from just override, but it is a fairly obvious and easy approach to follow.

public function doubleValue():Int{
     return bar.doubleValue();
 }

but the code seems fairly clean in js output atleast. But can imagine allowing the main to and from to use Bar could be messy internally if extending abstracts was implemented. ( with some more inlines the js out gets even shorter ).

This does seem like a good solution actually. Have you tried seeing how the output looks when making the functions inline?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants