From 574e61aa5cf4de067e5c2dd12ffc352b3cffabe3 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 6 Jan 2016 14:38:53 +0100 Subject: [PATCH 1/4] Initial draft of `@static` proposal. --- .../_posts/2016-01-01-static-members.md | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 sips/pending/_posts/2016-01-01-static-members.md diff --git a/sips/pending/_posts/2016-01-01-static-members.md b/sips/pending/_posts/2016-01-01-static-members.md new file mode 100644 index 0000000000..b49ff7f215 --- /dev/null +++ b/sips/pending/_posts/2016-01-01-static-members.md @@ -0,0 +1,73 @@ +--- +layout: sip +title: SIP 25 - @static fields and methods in Scala objects(SI-4581) +disqus: true +--- + +__Dmitry Petrashko__ + +__first submitted TODO 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 and is convenient for optimizations. + +## Use Cases + +Some JVM and JavaScript frameworks require classes to have specific static fields. + +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). + +@sjrd could you please illustrate JS exaples? + +## Syntax ## +In order for method or field to be considered static it needs to be defined in an `object` and annotated `@static`. +There is no special syntax proposed to access these members, they are accessed as if they were a member of defining objects with all appropriate access requirements for accessing them. + +## Restrictions ## + +The following rules ensure that method can be correctly compiled into static member on both JVM and JavaScript: + +1. Only objects can have members annotated as `@static` + +2. The fields annotated with `@static` should preceed any non-`@static` fields. This ensures that we do not introduce surprises for users in initialization order. + +3. The right hand side of method or field annotated as `@static` can only refer to members of globally accessible objects and `@static` members. In particular, for non-static objects `this` is not accesable. `super` is never accessable. + +4. If member `foo` of `object C` is annotated `@static`, companion class `C` is not allowed to define term members with name `foo`. + +5. If member `foo` of `object C` is annotated `@static`, companion class `C` is not allowed to inherit classes that define a term member with name `foo`.. + +6. If companion `object P` defines an `@static` method or field `foo`, classes inheriting from companion `class P` and their companions are not allowed to define term members with name `foo`. + +## Compilation scheme ## +No modificaiton of typer is planned. The current proposed scheme piggybacks on already existing scoping restrictions in typer, thus requiring `@static` methods to be defined in `objects`. +If implemented in dotty code base, such 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 member annotated `@static` should not trigger capturing object that contains this member; + - extend LambdaLift to trigger error if `@static` annotated method cannot be lifted to top level scope; + - extend GenBCode to emmit static fields and methods in companion classes and forwarders to them in companion modules. + +## Overriding of @static members is not allowed## +Java allows classes to define static methods with same name and signature as a static method of superclass. In order to define semantics of what does it mean, +Java Specification introduces a notion of [hiding](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2). + +This proposal does not want to introduce overcomplication and does not allow this. If in future overriding\hiding of `@static` methods will be considered worth the complexity +it could be introduced in a separate SIP. + +## Comparison with @lrytz [proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ## +Lucas Rytz has proposed a similar SIP, but his SIP requires changes to typer to ensure that `@static` fields do not capture `this`. +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 + - @static methods in companions of traits. Java8 supports this. + - @static vals in companions of traits. Java8 supports this, but not vars. + +## See Also ## + * [SI-4581](https://issues.scala-lang.org/browse/SI-4581) is a request for a `@static` annotation + * [Another proposal by @lrytz](https://gist.github.com/lrytz/80f3141de8240f9629da) + * [Old discussion on scala-internals mailing list](https://groups.google.com/forum/#!searchin/scala-internals/static/scala-internals/vOps4k8CADY/Dq1I3Ysvao0J) + * [Another discussion of scala-internals mailing list](https://groups.google.com/forum/#!searchin/scala-internals/static/scala-internals/Y3OlFWPvnyM/tGE5BQw4Pe0J) From e6a414bd66c6ac1a19ad9fcf5199d0dab4d15b82 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 6 Jan 2016 20:50:09 +0100 Subject: [PATCH 2/4] Incorporatin Martin's comments. --- sips/pending/_posts/2016-01-01-static-members.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sips/pending/_posts/2016-01-01-static-members.md b/sips/pending/_posts/2016-01-01-static-members.md index b49ff7f215..bee0dfdfdd 100644 --- a/sips/pending/_posts/2016-01-01-static-members.md +++ b/sips/pending/_posts/2016-01-01-static-members.md @@ -40,7 +40,7 @@ The following rules ensure that method can be correctly compiled into static mem 5. If member `foo` of `object C` is annotated `@static`, companion class `C` is not allowed to inherit classes that define a term member with name `foo`.. -6. If companion `object P` defines an `@static` method or field `foo`, classes inheriting from companion `class P` and their companions are not allowed to define term members with name `foo`. +6. Only @static methods and vals are suppoerted in companions of traits. Java8 supports those, but not vars. ## Compilation scheme ## No modificaiton of typer is planned. The current proposed scheme piggybacks on already existing scoping restrictions in typer, thus requiring `@static` methods to be defined in `objects`. @@ -50,21 +50,19 @@ If implemented in dotty code base, such modifications would be needed: - extend LambdaLift to trigger error if `@static` annotated method cannot be lifted to top level scope; - extend GenBCode to emmit static fields and methods in companion classes and forwarders to them in companion modules. -## Overriding of @static members is not allowed## +## Overriding&Hiding ## Java allows classes to define static methods with same name and signature as a static method of superclass. In order to define semantics of what does it mean, Java Specification introduces a notion of [hiding](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2). -This proposal does not want to introduce overcomplication and does not allow this. If in future overriding\hiding of `@static` methods will be considered worth the complexity -it could be introduced in a separate SIP. +This is required because in Java calling `@static` method on class instance is supported. +This proposal does not need to introduce this notion as we do not support such calls. ## Comparison with @lrytz [proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ## -Lucas Rytz has proposed a similar SIP, but his SIP requires changes to typer to ensure that `@static` fields do not capture `this`. +Lucas Rytz has proposed a similar SIP, but his SIP requires changes to typer to ensure that `@static` fields do not capture `this`, as in his proposal `@static` fields are defined in class body. 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 - - @static methods in companions of traits. Java8 supports this. - - @static vals in companions of traits. Java8 supports this, but not vars. ## See Also ## * [SI-4581](https://issues.scala-lang.org/browse/SI-4581) is a request for a `@static` annotation From b13183d17c4153063bc48c7aea46b4acf8aa6818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 7 Jan 2016 16:56:45 +0100 Subject: [PATCH 3/4] Various expansions to the static SIP, including JS-related stuff. --- .../_posts/2016-01-01-static-members.md | 97 ++++++++++++++----- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/sips/pending/_posts/2016-01-01-static-members.md b/sips/pending/_posts/2016-01-01-static-members.md index bee0dfdfdd..45ecd53b56 100644 --- a/sips/pending/_posts/2016-01-01-static-members.md +++ b/sips/pending/_posts/2016-01-01-static-members.md @@ -4,68 +4,121 @@ title: SIP 25 - @static fields and methods in Scala objects(SI-4581) disqus: true --- -__Dmitry Petrashko__ +__Dmitry Petrashko and Sébastien Doeraene__ __first submitted TODO 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 and is convenient for optimizations. +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. +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). -@sjrd could you please illustrate JS exaples? +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 ## -## Syntax ## In order for method or field to be considered static it needs to be defined in an `object` and annotated `@static`. There is no special syntax proposed to access these members, they are accessed as if they were a member of defining objects with all appropriate access requirements for accessing them. +For example: + +{% 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. +For the JVM, the above would therefore look to other Java code as if it had been declared with the following Java code: + +{% highlight java %} +class Foo { + public static int x = 5; + public static int bar(int y) { + return x + y; + } +} +{% endhighlight %} + +In Scala.js, the `@static` annotation has no semantic effect in Scala objects, as they are not visible from JavaScript anyway (it could be used for optimizations). +It has a semantic effect on Scala.js-defined JS classes, for example: + +{% highlight scala %} +@ScalaJSDefined +class Foo extends js.Object + +@ScalaJSDefined +object Foo extends js.Object { + @static val x = 5 + @static def bar(y: Int): Int = x + y +} +{% endhighlight %} + +would look to JavaScript code as if it had been declared with the following JavaScript code: + +{% 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 %} + ## Restrictions ## The following rules ensure that method can be correctly compiled into static member on both JVM and JavaScript: -1. Only objects can have members annotated as `@static` +1. Only objects can have members annotated with `@static` 2. The fields annotated with `@static` should preceed any non-`@static` fields. This ensures that we do not introduce surprises for users in initialization order. -3. The right hand side of method or field annotated as `@static` can only refer to members of globally accessible objects and `@static` members. In particular, for non-static objects `this` is not accesable. `super` is never accessable. +3. The right hand side of a method or field annotated with `@static` can only refer to members of globally accessible objects and `@static` members. In particular, for non-static objects `this` is not accesible. `super` is never accessible. -4. If member `foo` of `object C` is annotated `@static`, companion class `C` is not allowed to define term members with name `foo`. +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 member `foo` of `object C` is annotated `@static`, companion class `C` is not allowed to inherit classes that define a term member 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 suppoerted in companions of traits. Java8 supports those, but not vars. +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 typer is planned. The current proposed scheme piggybacks on already existing scoping restrictions in typer, thus requiring `@static` methods to be defined in `objects`. -If implemented in dotty code base, such 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 member annotated `@static` should not trigger capturing object that contains this member; - - extend LambdaLift to trigger error if `@static` annotated method cannot be lifted to top level scope; - - extend GenBCode to emmit static fields and methods in companion classes and forwarders to them in companion modules. +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 same name and signature as a static method of superclass. In order to define semantics of what does it mean, -Java Specification introduces a notion of [hiding](http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2). +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 `@static` method on class instance is supported. +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 [proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ## -Lucas Rytz has proposed a similar SIP, but his SIP requires changes to typer to ensure that `@static` fields do not capture `this`, as in his proposal `@static` fields are defined in class body. -It also does not address the question of `@static` members in inner objects and inheritance\hiding of those methods in subclasses. +## 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) * [Old discussion on scala-internals mailing list](https://groups.google.com/forum/#!searchin/scala-internals/static/scala-internals/vOps4k8CADY/Dq1I3Ysvao0J) * [Another discussion of scala-internals mailing list](https://groups.google.com/forum/#!searchin/scala-internals/static/scala-internals/Y3OlFWPvnyM/tGE5BQw4Pe0J) From 53fd83d23d0f7ac32261123da61cd104891df07d Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 8 Jan 2016 11:30:15 +0100 Subject: [PATCH 4/4] Incorporate feedback from @lrytz, @janekdb and @dwijnand. --- ...embers.md => 2016-01-11-static-members.md} | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) rename sips/pending/_posts/{2016-01-01-static-members.md => 2016-01-11-static-members.md} (77%) diff --git a/sips/pending/_posts/2016-01-01-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md similarity index 77% rename from sips/pending/_posts/2016-01-01-static-members.md rename to sips/pending/_posts/2016-01-11-static-members.md index 45ecd53b56..ac7a32a5c6 100644 --- a/sips/pending/_posts/2016-01-01-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -4,9 +4,9 @@ title: SIP 25 - @static fields and methods in Scala objects(SI-4581) disqus: true --- -__Dmitry Petrashko and Sébastien Doeraene__ +__Dmitry Petrashko, Sébastien Doeraene and Martin Odersky__ -__first submitted TODO 2016__ +__first submitted 11 January 2016__ ## Motivation ## @@ -18,18 +18,19 @@ Some JVM and JavaScript frameworks require classes to have specific static field 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). +Another example is using an [`AtomicReferenceFieldUpdater`](http://docs.oracle.com/javase/8/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`. +In order for a method or field to be considered static it needs to be defined in an `object` and annotated `@static`. There is no special syntax proposed to access these members, they are accessed as if they were a member of defining objects with all appropriate access requirements for accessing them. For example: +```scala {% highlight scala %} class Foo @@ -41,10 +42,12 @@ object Foo { 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. +Intuitively, the presence of the `@static` annotation ensures that a field/method is declared as a static member of the companion class. For the JVM, the above would therefore look to other Java code as if it had been declared with the following Java code: +```java {% highlight java %} class Foo { public static int x = 5; @@ -53,10 +56,12 @@ class Foo { } } {% endhighlight %} +``` In Scala.js, the `@static` annotation has no semantic effect in Scala objects, as they are not visible from JavaScript anyway (it could be used for optimizations). It has a semantic effect on Scala.js-defined JS classes, for example: +```scala {% highlight scala %} @ScalaJSDefined class Foo extends js.Object @@ -67,9 +72,11 @@ object Foo extends js.Object { @static def bar(y: Int): Int = x + y } {% endhighlight %} +``` 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) { @@ -78,22 +85,42 @@ class Foo extends Object { } Foo.x = 5; // in ES6, there is no declarative syntax for static fields yet {% endhighlight %} +``` + +## Comparison 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. +In case `O.d` is annotated with `@static` the field will be crated as a static field `d` in `class O`. +If not annotated, it will be created in the companion module with a static forwarder `d` in `class O`. ## Restrictions ## -The following rules ensure that method can be correctly compiled into static member on both JVM and JavaScript: +The following rules ensure that methods can be correctly compiled into static members on both JVM and JavaScript: 1. Only objects can have members annotated with `@static` 2. The fields annotated with `@static` should preceed any non-`@static` fields. This ensures that we do not introduce surprises for users in initialization order. -3. The right hand side of a method or field annotated with `@static` can only refer to members of globally accessible objects and `@static` members. In particular, for non-static objects `this` is not accesible. `super` is never accessible. +3. The right hand side of a method or field annotated with `@static` can only refer to top-level classes, members of globally accessible objects and `@static` members. In particular, for non-static objects `this` is not accesible. `super` is never accessible. 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. +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`. @@ -103,14 +130,14 @@ If implemented in the dotty code base, the following modifications would be need - 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 ## +## 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. +Lukas 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 ##