Skip to content

Commit d219232

Browse files
author
soronpo
authored
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 😄 - 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](typelevel/scala#69) for the suggestion.
1 parent 6719504 commit d219232

File tree

1 file changed

+43
-53
lines changed

1 file changed

+43
-53
lines changed

sips/pending/_posts/2017-02-07-make-types-behave-like-expressions.md

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ title: SIP-NN - Make types behave like expressions
88

99
## History
1010

11-
| Date | Version |
12-
|---------------|------------------|
13-
| Feb 7th 2017 | Initial Draft |
11+
| Date | Version |
12+
|---------------|--------------------------|
13+
| Feb 7th 2017 | Initial Draft |
14+
| Feb 9th 2017 | Updates from feedback |
15+
16+
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.
1417

1518
---
1619
## Introduction
@@ -19,43 +22,42 @@ Unfortunately, there is a 'surprise' element since the two differ in behaviour:
1922

2023
* **Infix operator precedence and associativity**:
2124
Infix types are 'mostly' left-associative,
22-
while the expression operations are more intuitive with different precedence weights.
25+
while the expression operation precedence is determined by the operator's first character (e.g., `/` is precedent to `+`).
2326
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.
2427

2528
**Example**:
2629
```scala
2730
object InfixExpressionPrecedence {
28-
case class Nummy(expand : String) {
29-
def + (that : Nummy) : Nummy = Nummy(s"Plus[$this,$that]")
30-
def * (that : Nummy) : Nummy = Nummy(s"Prod[$this,$that]")
31-
override def toString : String = expand
32-
}
33-
object N1 extends Nummy("N1")
34-
object N2 extends Nummy("N2")
35-
object N3 extends Nummy("N3")
36-
object N4 extends Nummy("N4")
37-
val result_expected = N1 + N2 * N3 + N4
38-
//result_expected.expand is Plus[Plus[N1,Prod[N2,N3]],N4]
31+
case class Nummy(expand : String) {
32+
def + (that : Nummy) : Nummy = Nummy(s"Plus[$this,$that]")
33+
def / (that : Nummy) : Nummy = Nummy(s"Div[$this,$that]")
34+
}
35+
object N1 extends Nummy("N1")
36+
object N2 extends Nummy("N2")
37+
object N3 extends Nummy("N3")
38+
object N4 extends Nummy("N4")
39+
//Both expand to Plus[Plus[N1,Div[N2,N3]],N4]
40+
assert((N1 + N2 / N3 + N4).expand == (N1 + (N2 / N3) + N4).expand)
3941
}
4042
object InfixTypePrecedence {
41-
trait Plus[N1, N2]
42-
trait Prod[N1, N2]
43-
type +[N1, N2] = Plus[N1, N2]
44-
type *[N1, N2] = Prod[N1, N2]
45-
trait N1
46-
trait N2
47-
trait N3
48-
trait N4
49-
type Result_Surprise = N1 + N2 * N3 + N4
50-
//Result_Surprise expands to Plus[Prod[Plus[N1,N2],N3],N4]
51-
type Result_Expected = N1 + (N2 * N3) + N4
52-
//Result_Expected expands to Plus[Plus[N1,Prod[N2,N3]],N4]
43+
trait Plus[N1, N2]
44+
trait Div[N1, N2]
45+
type +[N1, N2] = Plus[N1, N2]
46+
type /[N1, N2] = Div[N1, N2]
47+
trait N1
48+
trait N2
49+
trait N3
50+
trait N4
51+
//Error!
52+
//Left expands to Plus[Plus[N1,Div[N2,N3]],N4] (Surprising)
53+
//Right expands to Plus[Div[Plus[N1,N2],N3],N4]
54+
implicitly[(N1 + N2 / N3 + N4) =:= (N1 + (N2 / N3) + N4)]
5355
}
5456
```
5557

5658
* **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.
5759
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.
58-
(Author's note: Not crucial as infix precedence, but good for completeness)
60+
5961

6062
**Example**:
6163
```scala
@@ -91,19 +93,22 @@ The proposal is split into two; type infix precedence, and prefix unary types. N
9193

9294
### Proposal, Part 1: Infix type precedence & associativity
9395
Make infix types conform to the same precedence and associativity traits as expression operations.
94-
(Author's note: I can copy-paste the specification and modify it, if it so required)
9596
### Proposal, Part 2: Prefix unary types
9697
Add prefix types, exactly as specified for prefix expression.
97-
(Author's note: I can copy-paste the specification and modify it, if it so required)
98+
9899

99100
---
101+
## Motivation
102+
The general motivation is developers expect terms and types to behave equally regarding operation precedence and availability of unary types.
100103

101-
## Motivating examples
104+
### Motivating examples
102105
#### Dotty infix type similarity
103-
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)]`).
104-
Dotty has no prefix types.
106+
Dotty infix type associativity and precedence seem to act the same as expressions.
107+
No documentation available to prove this, but the infix example above works perfectly in dotty.
108+
109+
Dotty has no prefix types, same as Scalac.
105110

106-
#### Singleton-ops library
111+
#### Singleton-ops library example
107112
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.
108113
For example:
109114
```scala
@@ -129,18 +134,16 @@ val works : 1 + (2 * 3) + 4 = 11
129134
val fails : 1 + 2 * 3 + 4 = 11 //left associative:(((1+2)*3)+4))) = 13
130135
```
131136

132-
#### Developer issues
133-
The following stackoverflow question demonstrate developers are 'surprised' by the difference in infix precedence.
137+
#### Developer issues example
138+
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.
134139
http://stackoverflow.com/questions/23333882/scala-infix-type-aliasing-for-2-type-parameters
135140

136141

137142

138-
---
139-
140143
## Interactions with other language features
141144

142145
#### Variance Annotation
143-
Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types might lead to some confusion.
146+
Variance annotation uses the `-` and `+` symbols to annotate contravariant and covariant subtyping, respectively. Introducing unary prefix types may lead to some developer confusion.
144147
E.g.
145148
```scala
146149
trait Negate[A]
@@ -150,7 +153,6 @@ type unary_+[A] = Positive[A]
150153
trait Contravariant[B, -A <: -B] //contravariant A subtype upper-bounded by Negate[B]
151154
trait Covariant[B, +A <: +B] //covariant A subtype upper-bounded by Positive[B]
152155
```
153-
(Author's note: it seem very unlikely that such feature interaction will occur)
154156

155157
#### Negative Literal Types
156158
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
172174
```
173175
This means that if unary prefix types are added, then `+42` will be a type expansion of `unary_+[42]`.
174176

175-
#### Scala meta
176-
Open question how this SIP affects `scala-meta`.
177-
178177
---
179178

180179
## Backward Compatibility
181180
Changing infix type associativity and precedence affects code that uses type operations and conforms to the current specification.
182-
(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.)
183181

184182
---
185183

186-
### Extended proposal alternative
187-
It is possible to extend this proposal and allow the developer to annotate the expected associativity and precedence per operation.
188-
(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.)
189-
See the following [Typelevel Scala issue](https://github.com/typelevel/scala/issues/69) for the suggestion.
190-
191-
### Other languages
192-
Would love some help to complete what happens in different programming languages.
193-
194-
### Discussions
184+
### Bibliography
195185
[Scala Contributors](https://contributors.scala-lang.org/t/sip-nn-make-infix-type-alias-precedence-like-expression-operator-precedence/471)
196186

197187
[scala-sips](https://groups.google.com/forum/#!topic/scala-sips/ARVf1RLDw9U)

0 commit comments

Comments
 (0)