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

Use cases of static invoking the lexical methods/accessors in the classes #14

Open
hax opened this issue Jun 2, 2022 · 0 comments
Open

Comments

@hax
Copy link
Member

hax commented Jun 2, 2022

One use case of this proposal is providing good syntax for first-class protocol:

protocol MyProtocol {
  foo
  bar() {
    this::foo()  // instead of this[MyProtocol.foo]() which is wordy and unsafe
  }
}

Actually classes also have similar use cases:

class MyClass {
  foo() {
  }
  bar() {
    this.foo() // invoke dynamically, but for many reasons we want to ensure to invoke the original foo
    MyClass.prototype.foo.call(this) // invoke statically, wordy and unsafe
  }
}

If foo is getter/setter, the code will be even more hard: Object.getOwnPropertyDescriptor(MyClass.prototype, 'foo').get.call(this)

This proposal already make it easy:

class MyClass {
  foo() {
  }
  bar() {
    this::MyClass:foo() // invoke statically
  }
}

The syntax is ok, but still not safe enough because MyClass.prototype could be hacked. (another small issue is there are anonymous classes)

To ensure safety, we need to extract the methods/accessors in advance.

class MyClass {
  foo() {
  }
  bar() {
    this::foo() // invoke statically, safely
  }
}
const ::{foo, bar} from MyClass

There are two problems of such pattern, first it make the methods outside of the class scope, second the order is unfortunate because you only can extract methods after class definition.

The solution is simple, just allow classes could invoke all class members directly, like protocol.

class MyClass {
  foo() {
  }
  bar() {
    this::foo()
  }
}

expr::foo() // throw ReferenceError

Use cases/Reasons why we want static invoking in the classes

  • Avoid Fragile base class issue by default. (only use dynamic invoking in their real usage: invoking abstract/virtual methods which need/tend to be implemented/overridden in subclasses.)
  • Safety. Note, class.hasInstance proposal provide a simple way to ensure the instances have all implementation details (private elements), but in the discussion people seems to expect it could also ensure the public interface. Now static invoking could help to meet the requirements.
  • Use static dispatch to avoid the cost of dynamic invoking, especially useful to the code for embed devices, which only have interpreter, no JIT.
  • Transpile other languages code with static dispatch semantics to JS, and allow the transpile code still readable.

Currently the most "easy" way for such use cases is write every things as private elements, then wrap them as public. This is cumbersome, introduce extra semantic effect (brand checking) which may not wanted, and introduce perf cost due to wrapper. All such issues prevent the users adopt the pattern.

It's also very useful for shared structs or record, because they only allow data fields and no methods/accessors. We could have a companion class to provide methods/accessors for them, and the methods/accessors should always be invoked statically.


Finally, for consistency we should also support it in object literals, this allow us write extensions just using object literal (this matches the util function namespaces today), and convenient to invoke extension methods/accessors of the same extension (normally, we collect the related methods in one extension, so very possible to invoke one method in the other).

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

1 participant