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

Explicit self #3569

Merged
merged 32 commits into from
Jul 27, 2022
Merged

Explicit self #3569

merged 32 commits into from
Jul 27, 2022

Conversation

hubertp
Copy link
Contributor

@hubertp hubertp commented Jul 7, 2022

Pull Request Description

This change modifies the current language by requiring explicit self parameter declaration
for methods. Methods without self parameter in the first position should be treated as statics
although that is not yet part of this PR. We add an implicit self to all methods
This obviously required updating the whole stdlib and its components, tests etc but the change
is pretty straightforward in the diff.

Notice that this change does not change method dispatch, which was removed in the last changes.
This was done on purpose to simplify the implementation for now. We will likely still remove all
those implicit selfs to bring true statics.
Minor caveat - since main doesn't actually need self, already removed that which simplified
a lot of code.

Checklist

Please include the following checklist in your PR:

  • The documentation has been updated if necessary.
  • All code conforms to the
    Scala,
    Java,
    and
    Rust
    style guides.
  • All code has been tested:
    • Unit tests have been written where possible.
    • If GUI codebase was changed: Enso GUI was tested when built using BOTH
      ./run ide dist and ./run ide watch.

@hubertp hubertp force-pushed the wip/hubert/explicit-self-182582560 branch 3 times, most recently from b8bf352 to 460a334 Compare July 18, 2022 10:34
@hubertp hubertp changed the title WIP: Explicit self Explicit self Jul 18, 2022
@hubertp hubertp marked this pull request as ready for review July 18, 2022 10:34
@hubertp hubertp requested a review from kustosz July 18, 2022 10:34
) =>
val global = fn.getMetadata(GlobalNames)
global.map(_.target) match {
case Some(BindingsMap.ResolvedMethod(module, method)) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is a bit controversial in a sense that by making GlobalNames code simple and conform to the overall approach (no self arguments) we have to compensate for that in IrToTruffle translation. It seemed like a good idea at the time but it complicated the logic slightly here.
On the upside, we don't do symbol resolution for local functions in runtime.

I can bring back the old approach by reverting the change in GlobalNames and removing this special handling here. It would be a tiny change and I checked that it works. So happy to get feedback on this piece!

@hubertp hubertp marked this pull request as draft July 18, 2022 22:23
Copy link
Contributor

@kustosz kustosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explained on priv, I have some doubts about why this change reaches so deep into function execution

CHANGELOG.md Outdated Show resolved Hide resolved
@hubertp hubertp force-pushed the wip/hubert/explicit-self-182582560 branch 3 times, most recently from 24cf852 to 47e909b Compare July 22, 2022 08:35
@hubertp hubertp marked this pull request as ready for review July 22, 2022 08:36
@hubertp hubertp requested a review from kustosz July 22, 2022 08:36
@hubertp
Copy link
Contributor Author

hubertp commented Jul 22, 2022

@kustosz removed the controversial method dispatch changes.
Couldn't bring myself to reverting all those Object self in builtins, so I modified processor to add those instead :p

@hubertp hubertp force-pushed the wip/hubert/explicit-self-182582560 branch from 47e909b to 429b86c Compare July 22, 2022 09:52
Copy link
Member

@jdunkerley jdunkerley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have only reviewed the enso files - a few minor fixed but otherwise LGTM

test/Tests/src/Semantic/Names_Spec.enso Outdated Show resolved Hide resolved
Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went thru all the non-.enso files and tried to make a sense of the changes. My comments are more questions. If the system holds together the change is probably good. Great work!

@@ -58,24 +58,24 @@ public abstract List<String> generate(
protected String methodSigDef(String owner, List<MethodParameter> params, boolean isAbstract) {
int paramsLen = params.size();
String paramsDef;
boolean includeSelfParam = !(isStatic || isConstructor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These DSL changes are interesting, but: @hubertp, didn't you have to update Ir or parser? I am asking because I am supposed to implement default keyword. I thought my task will be similar to your one. It seems to me that with explicit self we are also introducing new keyword self...

Copy link
Contributor Author

@hubertp hubertp Jul 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No? This particular change affects generating builtin nodes.
For example (roughly) for

@Builtin.Method
public static void foo(Object x) {
  // ...
}

it will generate Builtin node with execute without Object self i.e.


@BuiltinMethod(...)
public class FooNode {
    public void execute(Object x) {
        /// ...
    }
}

rather than

@BuiltinMethod(...)
public class FooNode {
    public void execute(Object self, Object x) {
        /// ...
    }
}

This is then accepted by the next processor which knows that it needs to add self as ArgumentDefinition at 0.
While strictly speaking not necessary, because in this version everything still has self ( insert sad face ) but at least most of it is now hidden.

@@ -210,7 +210,7 @@ case object IgnoredBindings extends IRPass {
): IR.DefinitionArgument = {
arg match {
case spec @ IR.DefinitionArgument.Specified(
IR.Name.Self(_, _, _),
IR.Name.Self(_, _, _, _),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is IR.Name.Self! In the same manner I will have to make sure there is IR.Name.Default once I try to implement default arguments, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is only because I added a parameter to Self class definition and compiler would reject this pattern

* @param ir the annotated application
* @param paramPosition the reason why the annotation cannot be obeyed
*/
case class WrongSelfParameterPos(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why not make it an error instead of warning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The discussion in discord mentions that it should be a warning. Truth be told, it will almost always be an error....

case AstView.Binding(AST.App.Section.Right(opr, arg), body) =>
val translatedArgs = arg match {
case AstView.FunctionParamList(items) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change related to self? Or is it just adding a missing processing of FunctionParamList triggered by some new failing tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is related to self.
Previously methods involving operands wouldn't have self.
For example, without this change we will crash on something as simple as

    == self that = ....

@hubertp hubertp force-pushed the wip/hubert/explicit-self-182582560 branch from 4799b21 to 1cb2229 Compare July 25, 2022 12:35
@hubertp hubertp requested a review from jdunkerley July 25, 2022 12:36
@hubertp hubertp force-pushed the wip/hubert/explicit-self-182582560 branch 2 times, most recently from ffba928 to 809c6e5 Compare July 26, 2022 13:41
On a scale of 1 to 10, the hack is probably 5. All the alternatives I
considered, involved tweaking IR in a horrible way. And JS is a bit of a
special case TBH.

The solution adds an implicit self parameter with a default value
resolving to the definining module. That way users don't have to provide
an extra  parameter and all arguments are magically applied
Added missing `self` in interop specs that were pending.
Minor nit: turns out methods are registered for modules under their
lowercase name, rather than the original one. This is a bit surprising
and might need to be removed, if it turns out to be unnecessary.
In the current approach the order of calling local functions matters
which came up accidentally in a method with default arguments in
Delimited_Reader. This is because methods are added to the scope in the
order they are processed.
Suprised this hasn't come up before. Will need to address this before
releasing.

Added a (pending) test-case to demonstrate the problem.
Handle local functions that are being used before being defined.
Might want to revise that in GlobalNames
Discovered by accident.
This was requested to resolve the exceptional status of `this` in JS.
It also introduces an inconsistency to the language as everything else
uses `self`.
Added some logic to detect situations when someone uses `self` in JS and
issue warnings in such situation.

The implementation implicitly replaces `this` with `self` in the
parameter list so that we don't have to change the whole compiler to
support this exception.
This approach might still go away, since we will explore adding implicit
self always.
In order to limit the complexity of the change and its effect on method
dispatch, this change brings back (implicit) self arguments for all
methods.

Couldn't force myself to bring all self parameters to builtins so
instead adapted processor to add them.
@hubertp hubertp force-pushed the wip/hubert/explicit-self-182582560 branch from 98d4f7b to 387904b Compare July 27, 2022 14:46
@hubertp hubertp added the CI: Ready to merge This PR is eligible for automatic merge label Jul 27, 2022
@mergify mergify bot merged commit f63e40d into develop Jul 27, 2022
@mergify mergify bot deleted the wip/hubert/explicit-self-182582560 branch July 27, 2022 17:45
hubertp added a commit that referenced this pull request Jul 28, 2022
`main` method is now special because it is trully static i.e. no
implicit `self` is being generated for it.
But since REPL's `main` isn't called `main` its invocation was missing
an argument.

Follow up on #3569

Will work on adding a CI test for REPL to avoid problems with REPL in a
follow up PR.
@hubertp hubertp mentioned this pull request Jul 28, 2022
4 tasks
jdunkerley pushed a commit that referenced this pull request Aug 4, 2022
`main` method is now special because it is trully static i.e. no
implicit `self` is being generated for it.
But since REPL's `main` isn't called `main` its invocation was missing
an argument.

Follow up on #3569

Will work on adding a CI test for REPL to avoid problems with REPL in a
follow up PR.
hubertp added a commit that referenced this pull request Aug 5, 2022
`main` method is now special because it is trully static i.e. no
implicit `self` is being generated for it.
But since REPL's `main` isn't called `main` its invocation was missing
an argument.

Follow up on #3569

Will work on adding a CI test for REPL to avoid problems with REPL in a
follow up PR.
mergify bot pushed a commit that referenced this pull request Aug 8, 2022
`main` method is now special because it is trully static i.e. no
implicit `self` is being generated for it.
But since REPL's `main` isn't called `main` its invocation was missing
an argument.

Follow up on #3569

# Important Notes
Will work on adding a CI test for REPL to avoid problems with REPL in a
follow up PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Ready to merge This PR is eligible for automatic merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants