Add @static SIP #491

Merged
merged 4 commits into from Nov 25, 2016

Projects

None yet

10 participants

@DarkDimius
Member

Add @static SIP

@dwijnand dwijnand commented on an outdated diff Jan 18, 2016
sips/pending/_posts/2016-01-11-static-members.md
+```
+
+would look to JavaScript code as if it had been declared with the following JavaScript code:
+
+```javascript
+{% highlight javascript %}
+class Foo extends Object {
+ static bar(y) {
+ return x + y;
+ }
+}
+Foo.x = 5; // in ES6, there is no declarative syntax for static fields yet
+{% endhighlight %}
+```
+
+## Comparisson with mirror classes ##
@dwijnand
dwijnand Jan 18, 2016 Member

Comparison

@DarkDimius DarkDimius referenced this pull request in lampepfl/dotty Feb 13, 2016
Merged

Drop empty companion objects #1075

@DarkDimius DarkDimius added a commit to dotty-staging/dotty that referenced this pull request Mar 7, 2016
@DarkDimius DarkDimius Implement @static sip.
This pull request implements most of machinery needed for
scala/scala.github.com#491

Only 3-rd check is not implemented by this commit.
I propose to get this in faster to fix #1149
826e5ab
@DarkDimius DarkDimius added a commit to dotty-staging/dotty that referenced this pull request Mar 7, 2016
@DarkDimius DarkDimius Implement @static sip.
This pull request implements most of machinery needed for
scala/scala.github.com#491

Only 3-rd check is not implemented by this commit.
I propose to get this in faster to fix #1149
c73fbaa
@DarkDimius DarkDimius referenced this pull request in lampepfl/dotty Mar 7, 2016
Merged

Implement @static sip. #1155

@DarkDimius
Member

The implementation was merged into Dotty.

@janekdb janekdb commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+
+__Dmitry Petrashko, Sébastien Doeraene and Martin Odersky__
+
+__first submitted 11 January 2016__
+
+## Motivation ##
+
+We would like to allow methods and fields to be compiled as static. This is usable for interop with Java and other JVM languages, as well as with JavaScript, and is convenient for optimizations.
+
+## Use Cases
+
+Some JVM and JavaScript frameworks require classes to have specific static fields and/or methods.
+
+For example, classes extending `android.os.Parcelable` are required to have a static field named `CREATOR` of type `android.os.Parcelable$Creator`.
+
+Another example is using an [`AtomicReferenceFieldUpdater`](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.html).
@janekdb
janekdb Apr 20, 2016 edited Contributor

s/7/8/ ?

@janekdb janekdb commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+We would like to allow methods and fields to be compiled as static. This is usable for interop with Java and other JVM languages, as well as with JavaScript, and is convenient for optimizations.
+
+## Use Cases
+
+Some JVM and JavaScript frameworks require classes to have specific static fields and/or methods.
+
+For example, classes extending `android.os.Parcelable` are required to have a static field named `CREATOR` of type `android.os.Parcelable$Creator`.
+
+Another example is using an [`AtomicReferenceFieldUpdater`](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.html).
+
+On the JavaScript side, one example is [Relay Route Definitions](https://facebook.github.io/relay/docs/guides-routes.html), whose subclasses must define static fields such as `queries`.
+Static methods and fields for JavaScript classes are one of the very few things (if not the only thing) that Scala.js "cannot do" at the moment, at least not declaratively.
+
+## Overview ##
+
+In order for method or field to be considered static it needs to be defined in an `object` and annotated `@static`.
@janekdb
janekdb Apr 20, 2016 Contributor

for method or field -> for a method or field.

@janekdb janekdb commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+
+```scala
+{% highlight scala %}
+class Foo
+
+object Foo {
+ @static val x = 5
+ @static def bar(y: Int): Int = x + y
+}
+
+println(Foo.x)
+println(Foo.bar(12))
+{% endhighlight %}
+```
+
+Intuively, the presence of the `@static` annotation ensures that a field/method is declared as a static member of the companion class.
@janekdb
janekdb Apr 20, 2016 Contributor

Intuitively

@janekdb janekdb commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+object O {
+ val d = 1
+ object I {
+ val f = 1
+ }
+}
+{% endhighlight %}
+```
+
+Under the proposed scheme users will be able to opt-in to have the field `f` defined in the inner object `I` emited as a static field.
+In case `O.d` is annotated with `@static` the field will be crated as a static field in `class O`.
+If not annotated, it will be created in the companion module with a static forwarder in `class O`.
+
+## Restrictions ##
+
+The following rules ensure that method can be correctly compiled into static member on both JVM and JavaScript:
@janekdb
janekdb Apr 20, 2016 Contributor

... that method can be ... into static member ... -> ... that methods can be ... into static members ...

@janekdb janekdb commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+
+4. If a member `foo` of an `object C` is annotated with `@static`, the companion class `C` is not allowed to define term members with name `foo`.
+
+5. If a member `foo` of an `object C` is annotated with `@static`, the companion class `C` is not allowed to inherit classes that define a term member with name `foo`.
+
+6. Only `@static` methods and vals are supported in companions of traits. Java8 supports those, but not vars, and JavaScript does not have interfaces at all.
+
+## Compilation scheme ##
+No modificaiton of the typer is planned. The current proposed scheme piggybacks on already existing scoping restrictions in the typer, thus requiring `@static` methods to be defined in `objects`.
+If implemented in the dotty code base, the following modifications would be needed:
+ - extend `RefChecks` to check restrictions 1, 2, 4, 5 and 6. This can be done in a separate mini-phase;
+ - extend `LamdaLift.CollectDependencies` to be aware that accessing a member annotated `@static` should not trigger capturing the object that contains this member;
+ - extend `LambdaLift` to trigger an error if a method annotated with `@static` method cannot be lifted to the top level scope;
+ - extend `GenBCode` to emit static fields and methods in companion classes and forwarders to them in companion modules.
+
+## Overriding&Hiding ##
@janekdb
janekdb Apr 20, 2016 Contributor

Overriding&Hiding -> Overriding & Hiding ?

@janekdb janekdb commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+## Compilation scheme ##
+No modificaiton of the typer is planned. The current proposed scheme piggybacks on already existing scoping restrictions in the typer, thus requiring `@static` methods to be defined in `objects`.
+If implemented in the dotty code base, the following modifications would be needed:
+ - extend `RefChecks` to check restrictions 1, 2, 4, 5 and 6. This can be done in a separate mini-phase;
+ - extend `LamdaLift.CollectDependencies` to be aware that accessing a member annotated `@static` should not trigger capturing the object that contains this member;
+ - extend `LambdaLift` to trigger an error if a method annotated with `@static` method cannot be lifted to the top level scope;
+ - extend `GenBCode` to emit static fields and methods in companion classes and forwarders to them in companion modules.
+
+## Overriding&Hiding ##
+Java allows classes to define static methods with the same name and signature as a static method of a superclass. In order to define the semantics of such cases, the Java Specification introduces the notion of [hiding](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2).
+
+This is required because in Java calling a `static` method on a class instance is supported.
+This proposal does not need to introduce this notion as we do not support such calls.
+
+## Comparison with [@lrytz's proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ##
+Lucas Rytz has proposed a similar SIP, but his SIP requires changes to the typer to ensure that `@static` fields do not capture `this`, as in his proposal `@static` fields are defined in the class, rather than its companion object.
@janekdb
janekdb Apr 20, 2016 Contributor

Lukas

@janekdb janekdb commented on the diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+Java allows classes to define static methods with the same name and signature as a static method of a superclass. In order to define the semantics of such cases, the Java Specification introduces the notion of [hiding](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2).
+
+This is required because in Java calling a `static` method on a class instance is supported.
+This proposal does not need to introduce this notion as we do not support such calls.
+
+## Comparison with [@lrytz's proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ##
+Lucas Rytz has proposed a similar SIP, but his SIP requires changes to the typer to ensure that `@static` fields do not capture `this`, as in his proposal `@static` fields are defined in the class, rather than its companion object.
+It also does not address the question of `@static` members in inner objects and inheritance/hiding of those methods in subclasses.
+
+## Open questions ##
+ - @static lazy val
+
+## See Also ##
+ * [SI-4581](https://issues.scala-lang.org/browse/SI-4581) is a request for a `@static` annotation
+ * [Scala.js issue #1902](https://github.com/scala-js/scala-js/issues/1902) is a request for defining static fields in Scala.js-defined JS classes
+ * [Another proposal by @lrytz](https://gist.github.com/lrytz/80f3141de8240f9629da)
@janekdb
janekdb Apr 20, 2016 Contributor

Intentionally repeated?

@lrytz lrytz commented on the diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+## Comparisson with mirror classes ##
+
+Scalac currently generates static forwarders for fields and methods in top-level objects:
+
+```scala
+{% highlight scala %}
+object O {
+ val d = 1
+ object I {
+ val f = 1
+ }
+}
+{% endhighlight %}
+```
+
+Under the proposed scheme users will be able to opt-in to have the field `f` defined in the inner object `I` emited as a static field.
@lrytz
lrytz Apr 20, 2016 Member

maybe mention that you need a companion inner class I.

@DarkDimius
DarkDimius Apr 20, 2016 Member

The current implementation, if companion is missing, is going to generate static field in the O.I$.
This is used internally to implement lazy vals since lampepfl/dotty#1226.
I'm not sure if I want to spec this, as this is subject to change.

@lrytz lrytz commented on an outdated diff Apr 20, 2016
sips/pending/_posts/2016-01-11-static-members.md
+
+Scalac currently generates static forwarders for fields and methods in top-level objects:
+
+```scala
+{% highlight scala %}
+object O {
+ val d = 1
+ object I {
+ val f = 1
+ }
+}
+{% endhighlight %}
+```
+
+Under the proposed scheme users will be able to opt-in to have the field `f` defined in the inner object `I` emited as a static field.
+In case `O.d` is annotated with `@static` the field will be crated as a static field in `class O`.
@lrytz
lrytz Apr 20, 2016 Member

this is a bit confusing given the phrase above, it sounds like "the field" refers to I.f

@kjsingh
kjsingh commented Nov 24, 2016

why can't we have static as a keyword?

@sjrd
Member
sjrd commented Nov 24, 2016

Because adding new keywords breaks existing code that used them as identifiers. Adding keywords must be done very sparingly, only when there is no other option.

@kjsingh
kjsingh commented Nov 24, 2016

I guess libs doing interop with Java code will be avoiding that.

@jvican
Member
jvican commented Nov 24, 2016

@DarkDimius is there any change you want to do here before the SIP review?

@DarkDimius
Member

I guess libs doing interop with Java code will be avoiding that.

Why would they? You may want some data to be seen as Java static field, and you can use @static for this.

@DarkDimius
Member

@DarkDimius is there any change you want to do here before the SIP review?

@jvican, I've applied those changes now and cleared git history. Feel free to merge if it looks good.

@jvican
Member
jvican commented Nov 25, 2016

Great changes, let's merge it for next week's discussion.

@jvican jvican merged commit 53f10e5 into scala:master Nov 25, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
@xuwei-k
Contributor
xuwei-k commented Nov 28, 2016
@adriaanm
Member
  • I don't think it's a good idea to let code gen depend in non-obvious ways on an annotation. Can we break this down further? How about....
    • Always emit object members as class statics, as suggested by Martin (solves initialization mismatch that killed scala/scala#894, and keeps static members out of class, which would be problematic in our type system)
    • Deal with name clashes using an @exportedName annotation?
    • Allow emitting a public static field without accessor using @suppressAccessors?

The proposal should go into more detail on:

  • What about binary compat (adding/removing @static annotation)
  • Interaction with initialization semantics?

Some relevant bugs:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment