From c75ad0851f7bbd3dbb7fe8d8847b399b7db1f569 Mon Sep 17 00:00:00 2001 From: Oron Port Date: Tue, 7 Feb 2017 19:38:53 +0200 Subject: [PATCH 01/11] Added SIP --- ...2-07-make-types-behave-like-expressions.md | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md new file mode 100644 index 0000000000..1b7a37a47b --- /dev/null +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -0,0 +1,128 @@ +--- +layout: sip +disqus: true +title: SIP-NN - Make types behave like expressions +--- + +**By: Oron Port** + +## History + +| Date | Version | +|---------------|------------------| +| Feb 7th 2017 | Initial Draft | + +--- +## Introduction +Currently scala allows symbol operators (`-`, `*`, `~~>`, etc.) for both type names and definition names. +Unfortunately, there is a 'surprise' element since the two differ in behaviour: +1. Infix operator precedence and associativity: +The differences are detailed in the Scala spec. Infix types are 'mostly' left-associative, +while the expression operations are more intuitive with different precedence weights. +Please see [Infix Types](http://scala-lang.org/files/archive/spec/2.12/03-types.html#infix-types) and [Infix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations) sections of the Scala specifications for more details. + +**Example**: +```scala +object InfixExpressionPrecedence { + case class Nummy(expand : String) { + def + (that : Nummy) : Nummy = Nummy(s"Plus[$this,$that]") + def * (that : Nummy) : Nummy = Nummy(s"Prod[$this,$that]") + override def toString : String = expand + } + object N1 extends Nummy("N1") + object N2 extends Nummy("N2") + object N3 extends Nummy("N3") + object N4 extends Nummy("N4") + val result_expected = N1 + N2 * N3 + N4 + //result_expected.expand is Plus[Plus[N1,Prod[N2,N3]],N4] +} +object InfixTypePrecedence { + trait Plus[N1, N2] + trait Prod[N1, N2] + type +[N1, N2] = Plus[N1, N2] + type *[N1, N2] = Prod[N1, N2] + trait N1 + trait N2 + trait N3 + trait N4 + type Result_Surprise = N1 + N2 * N3 + N4 + //Result_Surprise expands to Plus[Prod[Plus[N1,N2],N3],N4] + type Result_Expected = N1 + (N2 * N3) + N4 + //Result_Expected expands to Plus[Plus[N1,Prod[N2,N3]],N4] +} +``` +2. Prefix operators bracketless unary use: + +--- +## Proposal +The proposal is split into two; type infix precedence, and prefix unary types. Note to the SIP committee: It might be better to vote on the two parts separately. + +### Proposal, Part 1: Infix type precedence & associativity +Make infix types conform to the same precedence and associativity traits as expression operations. +(Author's note: I can copy-paste the specification and modify it, if it so required) +### Proposal, Part 2: Prefix unary types + +--- + +## Motivating examples + +#### Singleton-ops library +The [singleton-ops library](https://github.com/fthomas/singleton-ops) with [Typelevel Scala](https://github.com/typelevel/scala) (which implemented [SIP-23](http://docs.scala-lang.org/sips/pending/42.type.html)) enables developers to express literal type operations more intuitively. +For example: +```scala +import singleton.ops._ + +val four1 : 4 = implicitly[2 + 2] +val four2 : 2 + 2 = 4 +val four3 : 1 + 3 = implicitly[2 + 2] + +class MyVec[L] { + def doubleSize = new MyVec[2 * L] + def nSize[N] = new MyVec[N * L] +} +object MyVec { + implicit def apply[L](implicit check : Require[L > 0]) : MyVec[L] = new MyVec[L]() +} +val myVec : MyVec[10] = MyVec[4 + 1].doubleSize +val myBadVec = MyVec[-1] //fails compilation, as required +``` +We currently loose some of the intuitive appeal due to the precedence issue: +```scala +val works : 1 + (2 * 3) + 4 = 11 +val fails : 1 + 2 * 3 + 4 = 11 //left associative:(((1+2)*3)+4))) = 13 +``` + +#### Developer issues +The following stackoverflow question demonstrate developers are 'surprised' by the difference in infix precedence. +http://stackoverflow.com/questions/23333882/scala-infix-type-aliasing-for-2-type-parameters + + + +--- + +## Interactions with other language features + +#### Variance Annotation + +#### Negative Literal Types + +--- + +## Backward Compatibility +Changing infix type associativity and precedence affects code that uses type operations and conforms to the current specification. +(Author's note: I don't know if providing a flag to select the precedence is good or not. IMHO, it is better to create a tool that adds brackets to convert code to the old associativity.) + +--- + +### Extended proposal alternative +It is possible to extend this proposal and allow the developer to annotate the expected associativity and precedence per operation. +(Author's note: I personally don't like this, but if such a solution is better for the community, then I will gladly modify this SIP to reflect that.) +See the following [Typelevel Scala issue](https://github.com/typelevel/scala/issues/69) for the suggestion. + +### Other languages +Would love some help to complete what happens in different programming languages. + +### Discussions +[Scala Contributors](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471) + +[scala-sips](https://groups.google.com/forum/#!topic/scala-sips/ARVf1RLDw9U) From 5eb415c2bbaa63759785eaf4873951ddd3c3c278 Mon Sep 17 00:00:00 2001 From: Oron Port Date: Tue, 7 Feb 2017 19:42:34 +0200 Subject: [PATCH 02/11] Update SIP --- .../_posts/2017-02-07-make-types-behave-like-expressions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index 1b7a37a47b..a32f3830f3 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -16,6 +16,7 @@ title: SIP-NN - Make types behave like expressions ## Introduction Currently scala allows symbol operators (`-`, `*`, `~~>`, etc.) for both type names and definition names. Unfortunately, there is a 'surprise' element since the two differ in behaviour: + 1. Infix operator precedence and associativity: The differences are detailed in the Scala spec. Infix types are 'mostly' left-associative, while the expression operations are more intuitive with different precedence weights. From 1d6b25c82cd03719ee0f398381694624db85d556 Mon Sep 17 00:00:00 2001 From: Oron Port Date: Tue, 7 Feb 2017 20:39:51 +0200 Subject: [PATCH 03/11] Update SIP --- ...2-07-make-types-behave-like-expressions.md | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index a32f3830f3..f4a34e8703 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -17,7 +17,7 @@ title: SIP-NN - Make types behave like expressions Currently scala allows symbol operators (`-`, `*`, `~~>`, etc.) for both type names and definition names. Unfortunately, there is a 'surprise' element since the two differ in behaviour: -1. Infix operator precedence and associativity: +1. **Infix operator precedence and associativity**: The differences are detailed in the Scala spec. Infix types are 'mostly' left-associative, while the expression operations are more intuitive with different precedence weights. Please see [Infix Types](http://scala-lang.org/files/archive/spec/2.12/03-types.html#infix-types) and [Infix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations) sections of the Scala specifications for more details. @@ -52,7 +52,37 @@ object InfixTypePrecedence { //Result_Expected expands to Plus[Plus[N1,Prod[N2,N3]],N4] } ``` -2. Prefix operators bracketless unary use: +2. **Prefix operators bracketless unary use**: While expressions have prefix unary operators, there are none for types. See the [Prefix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section of the Scala specification. +This is a lacking feature of the type language Scala offers. See also interactions of this feature with other Scala features, further down this text. +(Author's note: Not crucial as infix precedence, but good for completeness) + +**Example**: +```scala +object PrefixExpression { + case class Nummy(expand : String) { + def unary_- : Nummy = Nummy(s"-$this") + def unary_~ : Nummy = Nummy(s"~$this") + def unary_! : Nummy = Nummy(s"!$this") + def unary_+ : Nummy = Nummy(s"+$this") + } + object N extends Nummy("N") + val n1 = -N + val n2 = ~N + val n3 = !N + val n4 = +N +} +object NonExistingPrefixTypes { + trait unary_-[A] + trait unary_~[A] + trait unary_![A] + trait unary_+[A] + trait N + type N1 = -N //Not working + type N2 = ~N //Not working + type N3 = !N //Not working + type N4 = +N //Not working +} +``` --- ## Proposal @@ -62,6 +92,8 @@ The proposal is split into two; type infix precedence, and prefix unary types. N Make infix types conform to the same precedence and associativity traits as expression operations. (Author's note: I can copy-paste the specification and modify it, if it so required) ### Proposal, Part 2: Prefix unary types +Add prefix types, exactly as specified for prefix expression. +(Author's note: I can copy-paste the specification and modify it, if it so required) --- @@ -104,8 +136,37 @@ http://stackoverflow.com/questions/23333882/scala-infix-type-aliasing-for-2-type ## Interactions with other language features #### Variance Annotation +Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types might lead to some confusion, more precisely with the `-` symbol. +E.g. +```scala +trait Negate[A] +type unary_-[A] = Negate[A] +trait MyTrait[B, -A <: -B] //contravariant A subtype upper-bounded by Negate[B] +``` +(Author's note: it seem very unlikely that such feature interaction will occur) #### Negative Literal Types +Negative literal types are annotated using the `-` symbol. This can lead to the following confusion: +```scala +trait Negate[A] +type unary_-[A] = Negate[A] +trait MyTrait[B] + +type MinusFortyTwo = MyTrait[-42] +type NegateFortyTwo = MyTrait[Negate[42]] +``` +The above example demonstrates a case of two types `MinusFortyTwo` and `NegateFortyTwo` which are different. They may be equivalent in view (implicit conversion between the two type instances), but they are not equal. + +Note: It is not possible to annotate a positive literal type in Scala (checked both in TLS and Dotty): +```scala +val a : 42 = +42 //works +val b : -42 = -42 //works +val c : +42 = 42 //error: ';' expected but integer literal found +``` +This means that if unary prefix types are added, then `+42` will be a type expansion of `unary_+[42]`. + +#### Scala meta +Open question how this SIP affects `scala-meta`. --- From 4a7f32d234da8351d963f1bd184f56569ccef663 Mon Sep 17 00:00:00 2001 From: soronpo Date: Tue, 7 Feb 2017 20:42:08 +0200 Subject: [PATCH 04/11] Update 2017-02-07-make-types-behave-like-expressions.md --- .../_posts/2017-02-07-make-types-behave-like-expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index f4a34e8703..7e51c368a4 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -18,7 +18,7 @@ Currently scala allows symbol operators (`-`, `*`, `~~>`, etc.) for both type na Unfortunately, there is a 'surprise' element since the two differ in behaviour: 1. **Infix operator precedence and associativity**: -The differences are detailed in the Scala spec. Infix types are 'mostly' left-associative, +Infix types are 'mostly' left-associative, while the expression operations are more intuitive with different precedence weights. Please see [Infix Types](http://scala-lang.org/files/archive/spec/2.12/03-types.html#infix-types) and [Infix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations) sections of the Scala specifications for more details. From 4638248c0f90dfc1003ba745a2e1dc00e0ee8ebf Mon Sep 17 00:00:00 2001 From: soronpo Date: Tue, 7 Feb 2017 20:44:51 +0200 Subject: [PATCH 05/11] Update 2017-02-07-make-types-behave-like-expressions.md --- .../_posts/2017-02-07-make-types-behave-like-expressions.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index 7e51c368a4..a8c2a345dc 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -17,7 +17,7 @@ title: SIP-NN - Make types behave like expressions Currently scala allows symbol operators (`-`, `*`, `~~>`, etc.) for both type names and definition names. Unfortunately, there is a 'surprise' element since the two differ in behaviour: -1. **Infix operator precedence and associativity**: +* **Infix operator precedence and associativity**: Infix types are 'mostly' left-associative, while the expression operations are more intuitive with different precedence weights. Please see [Infix Types](http://scala-lang.org/files/archive/spec/2.12/03-types.html#infix-types) and [Infix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations) sections of the Scala specifications for more details. @@ -52,7 +52,8 @@ object InfixTypePrecedence { //Result_Expected expands to Plus[Plus[N1,Prod[N2,N3]],N4] } ``` -2. **Prefix operators bracketless unary use**: While expressions have prefix unary operators, there are none for types. See the [Prefix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section of the Scala specification. + +* **Prefix operators bracketless unary use**: While expressions have prefix unary operators, there are none for types. See the [Prefix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section of the Scala specification. This is a lacking feature of the type language Scala offers. See also interactions of this feature with other Scala features, further down this text. (Author's note: Not crucial as infix precedence, but good for completeness) From 265919327da4085f7197c57114f1937023aa0fef Mon Sep 17 00:00:00 2001 From: soronpo Date: Tue, 7 Feb 2017 20:49:12 +0200 Subject: [PATCH 06/11] Update 2017-02-07-make-types-behave-like-expressions.md --- .../2017-02-07-make-types-behave-like-expressions.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index a8c2a345dc..3c66e87b2d 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -137,12 +137,15 @@ http://stackoverflow.com/questions/23333882/scala-infix-type-aliasing-for-2-type ## Interactions with other language features #### Variance Annotation -Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types might lead to some confusion, more precisely with the `-` symbol. +Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types might lead to some confusion. E.g. ```scala trait Negate[A] +trait Positive[A] type unary_-[A] = Negate[A] -trait MyTrait[B, -A <: -B] //contravariant A subtype upper-bounded by Negate[B] +type unary_+[A] = Positive[A] +trait Contravariant[B, -A <: -B] //contravariant A subtype upper-bounded by Negate[B] +trait Covariant[B, +A <: +B] //covariant A subtype upper-bounded by Positive[B] ``` (Author's note: it seem very unlikely that such feature interaction will occur) From 671950407fac67b896e5a0df395c7ee33f1e4f60 Mon Sep 17 00:00:00 2001 From: soronpo Date: Thu, 9 Feb 2017 16:23:54 +0200 Subject: [PATCH 07/11] Update 2017-02-07-make-types-behave-like-expressions.md Added comment about dotty --- .../_posts/2017-02-07-make-types-behave-like-expressions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index 3c66e87b2d..3ee41f6d64 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -99,6 +99,9 @@ Add prefix types, exactly as specified for prefix expression. --- ## Motivating examples +#### Dotty infix type similarity +Dotty infix type associativity and precedence seem to be the same as expressions (Author's note: I have seen no documentation of this, but checked the implementation for a simple example `implicitly[(N1 + (N2 / N3) + N4) =:= (N1 + N2 / N3 + N4)]`). +Dotty has no prefix types. #### Singleton-ops library The [singleton-ops library](https://github.com/fthomas/singleton-ops) with [Typelevel Scala](https://github.com/typelevel/scala) (which implemented [SIP-23](http://docs.scala-lang.org/sips/pending/42.type.html)) enables developers to express literal type operations more intuitively. From d219232e33d5eb2f1bc07dd28833d8df1c1a4ba4 Mon Sep 17 00:00:00 2001 From: soronpo Date: Thu, 9 Feb 2017 21:26:44 +0200 Subject: [PATCH 08/11] Updates due to @jvican 's hellpful comments - Removed author's notes, and Adding them here: 1. Unary types are not crucial as infix type precedence, but good for completeness. 2. For the proposal section, I can copy-paste the specifications from expression and modify them to types, if it so required. 3. Would love some help to complete what happens in different programming languages. 4. I think it is very unlikely that variance annotation will interact with literal types, so the confusion is not that critical. 5. Backward compatibility: I don't know if providing a flag to select the precedence is good or not. IMHO, it is better to create a tool that adds brackets to convert code to the old associativity. @jvican's suggestion to use a tool to analyze libraries and check if they are compatible or not is interesting. Don't know if I have time to make it. It is more useful for me to explore the scala compiler code, and make a PR for this SIP :smile: - Modified the example to `/` instead of `*` because currently dotty has bug and does not allow `*` infix type. - Removed scala meta section. - Removed extended proposal alternative: It is possible to extend this proposal and allow the developer to annotate the expected associativity and precedence per operation. I personally don't like this, but if such a solution is better for the community, then I will gladly modify this SIP to reflect that. See the following [Typelevel Scala issue](https://github.com/typelevel/scala/issues/69) for the suggestion. --- ...2-07-make-types-behave-like-expressions.md | 96 +++++++++---------- 1 file changed, 43 insertions(+), 53 deletions(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index 3ee41f6d64..6fce395399 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -8,9 +8,12 @@ title: SIP-NN - Make types behave like expressions ## History -| Date | Version | -|---------------|------------------| -| Feb 7th 2017 | Initial Draft | +| Date | Version | +|---------------|--------------------------| +| Feb 7th 2017 | Initial Draft | +| Feb 9th 2017 | Updates from feedback | + +Your feedback is welcome! If you're interested in discussing this proposal, head over to [this](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471) Scala Contributors thread and let me know what you think. --- ## Introduction @@ -19,43 +22,42 @@ Unfortunately, there is a 'surprise' element since the two differ in behaviour: * **Infix operator precedence and associativity**: Infix types are 'mostly' left-associative, -while the expression operations are more intuitive with different precedence weights. +while the expression operation precedence is determined by the operator's first character (e.g., `/` is precedent to `+`). Please see [Infix Types](http://scala-lang.org/files/archive/spec/2.12/03-types.html#infix-types) and [Infix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations) sections of the Scala specifications for more details. **Example**: ```scala object InfixExpressionPrecedence { - case class Nummy(expand : String) { - def + (that : Nummy) : Nummy = Nummy(s"Plus[$this,$that]") - def * (that : Nummy) : Nummy = Nummy(s"Prod[$this,$that]") - override def toString : String = expand - } - object N1 extends Nummy("N1") - object N2 extends Nummy("N2") - object N3 extends Nummy("N3") - object N4 extends Nummy("N4") - val result_expected = N1 + N2 * N3 + N4 - //result_expected.expand is Plus[Plus[N1,Prod[N2,N3]],N4] + case class Nummy(expand : String) { + def + (that : Nummy) : Nummy = Nummy(s"Plus[$this,$that]") + def / (that : Nummy) : Nummy = Nummy(s"Div[$this,$that]") + } + object N1 extends Nummy("N1") + object N2 extends Nummy("N2") + object N3 extends Nummy("N3") + object N4 extends Nummy("N4") + //Both expand to Plus[Plus[N1,Div[N2,N3]],N4] + assert((N1 + N2 / N3 + N4).expand == (N1 + (N2 / N3) + N4).expand) } object InfixTypePrecedence { - trait Plus[N1, N2] - trait Prod[N1, N2] - type +[N1, N2] = Plus[N1, N2] - type *[N1, N2] = Prod[N1, N2] - trait N1 - trait N2 - trait N3 - trait N4 - type Result_Surprise = N1 + N2 * N3 + N4 - //Result_Surprise expands to Plus[Prod[Plus[N1,N2],N3],N4] - type Result_Expected = N1 + (N2 * N3) + N4 - //Result_Expected expands to Plus[Plus[N1,Prod[N2,N3]],N4] + trait Plus[N1, N2] + trait Div[N1, N2] + type +[N1, N2] = Plus[N1, N2] + type /[N1, N2] = Div[N1, N2] + trait N1 + trait N2 + trait N3 + trait N4 + //Error! + //Left expands to Plus[Plus[N1,Div[N2,N3]],N4] (Surprising) + //Right expands to Plus[Div[Plus[N1,N2],N3],N4] + implicitly[(N1 + N2 / N3 + N4) =:= (N1 + (N2 / N3) + N4)] } ``` * **Prefix operators bracketless unary use**: While expressions have prefix unary operators, there are none for types. See the [Prefix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section of the Scala specification. This is a lacking feature of the type language Scala offers. See also interactions of this feature with other Scala features, further down this text. -(Author's note: Not crucial as infix precedence, but good for completeness) + **Example**: ```scala @@ -91,19 +93,22 @@ The proposal is split into two; type infix precedence, and prefix unary types. N ### Proposal, Part 1: Infix type precedence & associativity Make infix types conform to the same precedence and associativity traits as expression operations. -(Author's note: I can copy-paste the specification and modify it, if it so required) ### Proposal, Part 2: Prefix unary types Add prefix types, exactly as specified for prefix expression. -(Author's note: I can copy-paste the specification and modify it, if it so required) + --- +## Motivation +The general motivation is developers expect terms and types to behave equally regarding operation precedence and availability of unary types. -## Motivating examples +### Motivating examples #### Dotty infix type similarity -Dotty infix type associativity and precedence seem to be the same as expressions (Author's note: I have seen no documentation of this, but checked the implementation for a simple example `implicitly[(N1 + (N2 / N3) + N4) =:= (N1 + N2 / N3 + N4)]`). -Dotty has no prefix types. +Dotty infix type associativity and precedence seem to act the same as expressions. +No documentation available to prove this, but the infix example above works perfectly in dotty. + +Dotty has no prefix types, same as Scalac. -#### Singleton-ops library +#### Singleton-ops library example The [singleton-ops library](https://github.com/fthomas/singleton-ops) with [Typelevel Scala](https://github.com/typelevel/scala) (which implemented [SIP-23](http://docs.scala-lang.org/sips/pending/42.type.html)) enables developers to express literal type operations more intuitively. For example: ```scala @@ -129,18 +134,16 @@ val works : 1 + (2 * 3) + 4 = 11 val fails : 1 + 2 * 3 + 4 = 11 //left associative:(((1+2)*3)+4))) = 13 ``` -#### Developer issues -The following stackoverflow question demonstrate developers are 'surprised' by the difference in infix precedence. +#### Developer issues example +The following stackoverflow question demonstrate developers are 'surprised' by the difference in infix precedence, expecting infix type precedence to act the same as expression operations. http://stackoverflow.com/questions/23333882/scala-infix-type-aliasing-for-2-type-parameters ---- - ## Interactions with other language features #### Variance Annotation -Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types might lead to some confusion. +Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types may lead to some developer confusion. E.g. ```scala trait Negate[A] @@ -150,7 +153,6 @@ type unary_+[A] = Positive[A] trait Contravariant[B, -A <: -B] //contravariant A subtype upper-bounded by Negate[B] trait Covariant[B, +A <: +B] //covariant A subtype upper-bounded by Positive[B] ``` -(Author's note: it seem very unlikely that such feature interaction will occur) #### Negative Literal Types Negative literal types are annotated using the `-` symbol. This can lead to the following confusion: @@ -172,26 +174,14 @@ val c : +42 = 42 //error: ';' expected but integer literal found ``` This means that if unary prefix types are added, then `+42` will be a type expansion of `unary_+[42]`. -#### Scala meta -Open question how this SIP affects `scala-meta`. - --- ## Backward Compatibility Changing infix type associativity and precedence affects code that uses type operations and conforms to the current specification. -(Author's note: I don't know if providing a flag to select the precedence is good or not. IMHO, it is better to create a tool that adds brackets to convert code to the old associativity.) --- -### Extended proposal alternative -It is possible to extend this proposal and allow the developer to annotate the expected associativity and precedence per operation. -(Author's note: I personally don't like this, but if such a solution is better for the community, then I will gladly modify this SIP to reflect that.) -See the following [Typelevel Scala issue](https://github.com/typelevel/scala/issues/69) for the suggestion. - -### Other languages -Would love some help to complete what happens in different programming languages. - -### Discussions +### Bibliography [Scala Contributors](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471) [scala-sips](https://groups.google.com/forum/#!topic/scala-sips/ARVf1RLDw9U) From 84d5cc5564708395215df3f7b8f07bd7f0e328df Mon Sep 17 00:00:00 2001 From: soronpo Date: Fri, 10 Feb 2017 16:31:03 +0200 Subject: [PATCH 09/11] More updates from feedback - Changed title to reflect more what's inside the SIP. - Visual modifications --- .../2017-02-07-make-types-behave-like-expressions.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index 6fce395399..b32a370990 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -1,7 +1,7 @@ --- layout: sip disqus: true -title: SIP-NN - Make types behave like expressions +title: SIP-NN - Match infix & prefix types to meet expression rules --- **By: Oron Port** @@ -12,6 +12,7 @@ title: SIP-NN - Make types behave like expressions |---------------|--------------------------| | Feb 7th 2017 | Initial Draft | | Feb 9th 2017 | Updates from feedback | +| Feb 10th 2017 | Updates from feedback | Your feedback is welcome! If you're interested in discussing this proposal, head over to [this](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471) Scala Contributors thread and let me know what you think. @@ -20,7 +21,7 @@ Your feedback is welcome! If you're interested in discussing this proposal, head Currently scala allows symbol operators (`-`, `*`, `~~>`, etc.) for both type names and definition names. Unfortunately, there is a 'surprise' element since the two differ in behaviour: -* **Infix operator precedence and associativity**: +###Infix operator precedence and associativity Infix types are 'mostly' left-associative, while the expression operation precedence is determined by the operator's first character (e.g., `/` is precedent to `+`). Please see [Infix Types](http://scala-lang.org/files/archive/spec/2.12/03-types.html#infix-types) and [Infix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations) sections of the Scala specifications for more details. @@ -55,7 +56,8 @@ object InfixTypePrecedence { } ``` -* **Prefix operators bracketless unary use**: While expressions have prefix unary operators, there are none for types. See the [Prefix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section of the Scala specification. +###Prefix operators bracketless unary use +While expressions have prefix unary operators, there are none for types. See the [Prefix Operations](http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#prefix-operations) section of the Scala specification. This is a lacking feature of the type language Scala offers. See also interactions of this feature with other Scala features, further down this text. From 7750b937fd066bb770c589370c9c900dc8011c8f Mon Sep 17 00:00:00 2001 From: soronpo Date: Mon, 13 Feb 2017 00:49:59 +0200 Subject: [PATCH 10/11] Rebase --- .../_posts/2017-02-07-make-types-behave-like-expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index b32a370990..47ee62b93d 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -5,7 +5,7 @@ title: SIP-NN - Match infix & prefix types to meet expression rules --- **By: Oron Port** - + ## History | Date | Version | From 57f8d0a4afd0eec7a4ceb5a61158765ad9e11c8c Mon Sep 17 00:00:00 2001 From: soronpo Date: Mon, 13 Feb 2017 17:13:47 +0200 Subject: [PATCH 11/11] pushing again. crossing fingers. --- .../_posts/2017-02-07-make-types-behave-like-expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md index 47ee62b93d..b32a370990 100644 --- a/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md +++ b/sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md @@ -5,7 +5,7 @@ title: SIP-NN - Match infix & prefix types to meet expression rules --- **By: Oron Port** - + ## History | Date | Version |