HaxeFoundation / HaxeManual

The official Haxe manual
https://haxe.org/manual/
Creative Commons Attribution 4.0 International
218 stars 154 forks source link

Document constructor inlining limitations. #513

Closed player-03 closed 2 years ago

player-03 commented 2 years ago

Here's some code demonstrating the limitations.

class InlineConstructorTest {
  static function main() {
    //Can't be inlined because `object1` is reassigned later.
    var object1:SimpleObject = new SimpleObject("one");
    object1 = new SimpleObject("uno");

    //Can be inlined.
    var object2:SimpleObject = new SimpleObject("two");
    object2.name = "dos";

    //Can't be inlined because `object3` is passed to a function.
    var object3:SimpleObject = new SimpleObject("three");
    if(Reflect.fields(object3).length > 0) {
      object3.name = "tres";
    }

    trace(object1.name);
    trace(object2.name);
    trace(object3.name);
    printObject4();
  }

  static inline function printObject4():SimpleObject {
    //Can't be inlined because `object4` is returned.
    var object4:SimpleObject = new SimpleObject("cuatro");
    trace(object4.name);
    return object4;
  }
}

class SimpleObject {
  public var name:String;

  public inline function new(name:String) {
    this.name = name;
  }
}
Simn commented 2 years ago

This might be a bit too specific because it's really about any use of the local variable in a way that doesn't allow deconstruction. Not sure how to express that succinctly though.

RblSb commented 2 years ago

We can also add that extern inline function declaration disables deinlining, and compiler starts showing errors in cases, when inline is not possible.

player-03 commented 2 years ago

This might be a bit too specific because it's really about any use of the local variable in a way that doesn't allow deconstruction. Not sure how to express that succinctly though.

Off the top of my head, here are some options:

  • The local variable must allow deconstruction. (For instance, it must not be passed to a function or returned.)
  • The local variable may not be passed to a function, returned, or otherwise used in a way that prevents deconstruction.

Though I've also noticed that you don't actually need to assign to a local variable. Using hxmath's Vector2 class, you can write trace((new Vector2(2, 3) + 5 * new Vector2(-1, -1)).length) and it will inline both constructors. So the real requirement is that the class instance must be used in a way that allows deconstruction, whether it's assigned to a local variable or not. (And "remaining local" is just one of the criteria.)

player-03 commented 2 years ago

Tried another rewrite. Any better?

player-03 commented 2 years ago

We can also add that extern inline function declaration disables deinlining, and compiler starts showing errors in cases, when inline is not possible.

This is also true if you write inline new MyClass(), which is described on its own page. Probably should be mentioned here too, but I might make a different pull request for that.

Simn commented 2 years ago

I think that last line raises more questions than it answers... Introducing the term "deconstructible" doesn't help much.

Maybe instead of talking about all the things we can't do, it's easier to talk about what we can do with the local variable, which is accessing its fields.

player-03 commented 2 years ago

Better?

If a constructor is declared to be inline, the compiler may try to optimize it away in certain situations. For this to work, the compiler must be able to verify that the object can be replaced by a set of local variables.

  • The newly-constructed instance must only be accessible from the local function.
  • All called instance functions must be inlined.
  • All other references to the instance must only read or write its variables.
Simn commented 2 years ago

Seems good now. Thank you for your patience!

player-03 commented 2 years ago

Thank you for your patience!

This only took three days and three revisions. From my perspective that's really fast.