From ac3184b1454779f5194dcfe861bb423b343cefc5 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 19 Jan 2017 18:41:05 +0100 Subject: [PATCH 1/6] SIP25: answer feedback & add agreements with Scala.js Feedback was: - answer if @static could this be @tailrec-like annotation; - clarify if and how @static affects initialization order; - describe if @static affects binary compatibility. Addition to the SIP was an update of situation with Scala.js --- .../_posts/2016-01-11-static-members.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/sips/pending/_posts/2016-01-11-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md index cb5d066f97..2495d863b4 100644 --- a/sips/pending/_posts/2016-01-11-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -115,6 +115,8 @@ The following rules ensure that methods can be correctly compiled into static me 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. +Note that because of platform requirements for JavaScript interop, rules `3` and `4` would be lifted for objects that have a companion class that inherits `js.Any`. + ## Compilation scheme ## No modification 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 `object`s. @@ -132,12 +134,53 @@ Java allows classes to define static methods with the same name and signature as 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. +## ScalaJS and @JSstatic ## +As ScalaJS needs this feature fast, a decision has been made to ship it under a name of `@JSStatic` before waiting for this SIP to be accepted and implemented in `scalac`. When this SIP is accepted and implemented in `scalac` the `@JSStatic` would become a deprecated type alias to `scala.static`. + +## Scala.Native ## + ## Comparison with [@lrytz's proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ## 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 ## - @static lazy val + +## Initialization order discussion ## +In general, emission of static fields could affect the initialization order and change semantics. +This SIP solves this by enforcing (rule `2`) that `@static` fields and expressions preceed non-static fields. +This means that no code preceeds the `@static` field initialization which makes it hard to observe the difference between if the field is initialized statically or not, since fields are initialized in the order `as written`, similar to how normal fields are initialized. + +The `@static` proposal is similar to `@tailrec` in a sense that it fails compilation in the case where the user did not write code that follows the aforementioned rules. These rules exist to enforce the unlikelyhood of an observable difference in semantics if `@static` annotations are dropped; without resorting to code which either uses `Unsafe` or exhibits undefined behaviour under the JVM. + +## Could `@static` be a `@tailrec`-like annotation that doesn't affect code generation but only checks ## +Unlike `@tailrec` this annotation does affect the binary API and dropping such an annotation would be a binary incompatible change. This is why authors believe that developers should be in full control of what is static. + +## Alternative: Emitting fields of objects as static by default ## +An alternative to this proposal would be to emit all the fields defined in objects as static. +Unfotrunatelly this gets us under dark waters when we try to figure out in the following example: + +``` +{% highlight scala %} +class Super { + val c = {println(1); 1} +} +object Object extends Super { + override val c = {println(2); 2} + val d = {println(3); 2} +} +{% endhighlight %} +``` +Let's consider possible options: + - if the field `c` is emitted as `static` on the bytecode level, it will be initialized before the `c` in superclass is initialized, reordering side-effects in initializers; + - if the field `c` is emitted as `static` on the bytecode level it will use a different storage that the memory layout defined by `Super`, leading to potential bugs and wasted memory; + - if the field `c` is _not_ emitted as `static` but the field `d` is, then the order of initialization would also be affected, reordering side-effects. + +Based on the previous study done in preparation for this SIP, the authors believe that the only reasonable way to maintain current sematics would be to say that such alternative would require these rules: + - only the fields which were not declared by parents of the object can be emitted as static; + - only fields that are lexically defined before any non-static field or statement in the body can be emitted as static. + +Authors believe that the alternative would require the same effort to implement, but will be less intuitive to users and harder to control. ## See Also ## * [SI-4581](https://issues.scala-lang.org/browse/SI-4581) is a request for a `@static` annotation From b1349b12cdd9011074fb6540153e579d71041f27 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 19 Jan 2017 19:17:30 +0100 Subject: [PATCH 2/6] Update 2016-01-11-static-members.md --- sips/pending/_posts/2016-01-11-static-members.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/pending/_posts/2016-01-11-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md index 2495d863b4..aef30a8212 100644 --- a/sips/pending/_posts/2016-01-11-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -180,7 +180,7 @@ Based on the previous study done in preparation for this SIP, the authors believ - only the fields which were not declared by parents of the object can be emitted as static; - only fields that are lexically defined before any non-static field or statement in the body can be emitted as static. -Authors believe that the alternative would require the same effort to implement, but will be less intuitive to users and harder to control. +Authors believe that the alternative would require the same effort to implement, but will be less intuitive to users and harder to control as, for example, reodering fields in object might not be binary compatible. ## See Also ## * [SI-4581](https://issues.scala-lang.org/browse/SI-4581) is a request for a `@static` annotation From c75169aa2625089e6b1bbc9d7b66aa769651a9b4 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 10 Feb 2017 14:50:15 +0100 Subject: [PATCH 3/6] @static: typos, fixes, clarifications --- .../_posts/2016-01-11-static-members.md | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/sips/pending/_posts/2016-01-11-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md index aef30a8212..1e5ae2166d 100644 --- a/sips/pending/_posts/2016-01-11-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -105,7 +105,7 @@ The following rules ensure that methods can be correctly compiled into static me 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. +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 of this class. 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. @@ -134,10 +134,8 @@ Java allows classes to define static methods with the same name and signature as 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. -## ScalaJS and @JSstatic ## -As ScalaJS needs this feature fast, a decision has been made to ship it under a name of `@JSStatic` before waiting for this SIP to be accepted and implemented in `scalac`. When this SIP is accepted and implemented in `scalac` the `@JSStatic` would become a deprecated type alias to `scala.static`. - -## Scala.Native ## +## Scala.js and @JSStatic ## +As Scala.js needs this feature fast, a decision has been made to ship it under a name of `@JSStatic` before waiting for this SIP to be accepted and implemented in `scalac`. When this SIP is accepted and implemented in `scalac` the `@JSStatic` would become a deprecated type alias to `scala.static`. ## Comparison with [@lrytz's proposal](https://gist.github.com/lrytz/80f3141de8240f9629da) ## 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. @@ -149,16 +147,47 @@ It also does not address the question of `@static` members in inner objects and ## Initialization order discussion ## In general, emission of static fields could affect the initialization order and change semantics. This SIP solves this by enforcing (rule `2`) that `@static` fields and expressions preceed non-static fields. -This means that no code preceeds the `@static` field initialization which makes it hard to observe the difference between if the field is initialized statically or not, since fields are initialized in the order `as written`, similar to how normal fields are initialized. +This means that no code precedes the `@static` field initialization which makes it hard to observe the difference between if the field is initialized statically or not, +since fields are initialized in the order `as written`, similar to how normal fields are initialized. + +The `@static` proposal is similar to `@tailrec` in a sense that it fails compilation in the case where the user did not write code that follows the aforementioned rules. +These rules exist to enforce the unlikelyhood of an observable difference in semantics if `@static` annotations are dropped; +The restrictions in this SIP make it hard to observe changes in initialization within the same object. +It is still possible to observe those changes using multiple classes and side effects within initializers: + +```scala +{% highlight scala %} +class C { + val x = {println("x"); 1 } +} + + +object O extends C { + val y = { println("y"); 2 } + // prints: + // x + // y +} + +object Os extends C { + @static val y = { println("y"); 2 } + // prints: + // y + // x +} +{% endhighlight %} +``` -The `@static` proposal is similar to `@tailrec` in a sense that it fails compilation in the case where the user did not write code that follows the aforementioned rules. These rules exist to enforce the unlikelyhood of an observable difference in semantics if `@static` annotations are dropped; without resorting to code which either uses `Unsafe` or exhibits undefined behaviour under the JVM. +Static fields can be initialized earlier than they used to be initialized while being non-static, but never later. +By requiring `@static` first to be defined first inside the object, +we guarantee that you can't observe the changes in initialization withing the same object without resorting to code which either uses `Unsafe` or exhibits undefined behaviour under the JVM. ## Could `@static` be a `@tailrec`-like annotation that doesn't affect code generation but only checks ## Unlike `@tailrec` this annotation does affect the binary API and dropping such an annotation would be a binary incompatible change. This is why authors believe that developers should be in full control of what is static. ## Alternative: Emitting fields of objects as static by default ## An alternative to this proposal would be to emit all the fields defined in objects as static. -Unfotrunatelly this gets us under dark waters when we try to figure out in the following example: +Unfortunately this gets us under dark waters when we try to figure out in the following example: ``` {% highlight scala %} From 96f036c00d3bc0eeb62129cdef6876faa7bb1715 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 10 Feb 2017 15:01:56 +0100 Subject: [PATCH 4/6] @static: make jekyll happy by giving him more spaces. --- sips/pending/_posts/2016-01-11-static-members.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sips/pending/_posts/2016-01-11-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md index 1e5ae2166d..6c023bde84 100644 --- a/sips/pending/_posts/2016-01-11-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -201,11 +201,13 @@ object Object extends Super { {% endhighlight %} ``` Let's consider possible options: + - if the field `c` is emitted as `static` on the bytecode level, it will be initialized before the `c` in superclass is initialized, reordering side-effects in initializers; - if the field `c` is emitted as `static` on the bytecode level it will use a different storage that the memory layout defined by `Super`, leading to potential bugs and wasted memory; - if the field `c` is _not_ emitted as `static` but the field `d` is, then the order of initialization would also be affected, reordering side-effects. Based on the previous study done in preparation for this SIP, the authors believe that the only reasonable way to maintain current sematics would be to say that such alternative would require these rules: + - only the fields which were not declared by parents of the object can be emitted as static; - only fields that are lexically defined before any non-static field or statement in the body can be emitted as static. From 9f44c9f9696200cc38c48070af2ae9481fc8e952 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 10 Feb 2017 15:02:55 +0100 Subject: [PATCH 5/6] @static: change status as requested by @jvican --- sips/pending/_posts/2016-01-11-static-members.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/pending/_posts/2016-01-11-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md index 6c023bde84..67d09f4fc0 100644 --- a/sips/pending/_posts/2016-01-11-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -3,7 +3,7 @@ layout: sip title: SIP 25 - @static fields and methods in Scala objects(SI-4581) disqus: true -vote-status: under revision +vote-status: under review vote-text: Authors need to update the proposal before the next review. --- From 86792d58d73ae1288d7d7f938b3371b5017cc46e Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Fri, 10 Feb 2017 15:40:49 +0100 Subject: [PATCH 6/6] @static: remove an irrelevant statement. It's true in both @static and non-@static case. --- sips/pending/_posts/2016-01-11-static-members.md | 1 - 1 file changed, 1 deletion(-) diff --git a/sips/pending/_posts/2016-01-11-static-members.md b/sips/pending/_posts/2016-01-11-static-members.md index 67d09f4fc0..50d32cb2c9 100644 --- a/sips/pending/_posts/2016-01-11-static-members.md +++ b/sips/pending/_posts/2016-01-11-static-members.md @@ -203,7 +203,6 @@ object Object extends Super { Let's consider possible options: - if the field `c` is emitted as `static` on the bytecode level, it will be initialized before the `c` in superclass is initialized, reordering side-effects in initializers; - - if the field `c` is emitted as `static` on the bytecode level it will use a different storage that the memory layout defined by `Super`, leading to potential bugs and wasted memory; - if the field `c` is _not_ emitted as `static` but the field `d` is, then the order of initialization would also be affected, reordering side-effects. Based on the previous study done in preparation for this SIP, the authors believe that the only reasonable way to maintain current sematics would be to say that such alternative would require these rules: