diff --git a/docs/docs/reference/changed-features/compiler-plugins.md b/docs/docs/reference/changed-features/compiler-plugins.md index debf369cc0c1..e77e557eef50 100644 --- a/docs/docs/reference/changed-features/compiler-plugins.md +++ b/docs/docs/reference/changed-features/compiler-plugins.md @@ -63,28 +63,28 @@ import dotty.tools.dotc.plugins.{PluginPhase, StandardPlugin} import dotty.tools.dotc.transform.{Pickler, Staging} class DivideZero extends StandardPlugin: - val name: String = "divideZero" - override val description: String = "divide zero check" + val name: String = "divideZero" + override val description: String = "divide zero check" - def init(options: List[String]): List[PluginPhase] = - (new DivideZeroPhase) :: Nil + def init(options: List[String]): List[PluginPhase] = + (new DivideZeroPhase) :: Nil class DivideZeroPhase extends PluginPhase: - import tpd.* + import tpd.* - val phaseName = "divideZero" + val phaseName = "divideZero" - override val runsAfter = Set(Pickler.name) - override val runsBefore = Set(Staging.name) + override val runsAfter = Set(Pickler.name) + override val runsBefore = Set(Staging.name) - override def transformApply(tree: Apply)(implicit ctx: Context): Tree = - tree match - case Apply(Select(rcvr, nme.DIV), List(Literal(Constant(0)))) - if rcvr.tpe <:< defn.IntType => - report.error("dividing by zero", tree.pos) - case _ => - () - tree + override def transformApply(tree: Apply)(implicit ctx: Context): Tree = + tree match + case Apply(Select(rcvr, nme.DIV), List(Literal(Constant(0)))) + if rcvr.tpe <:< defn.IntType => + report.error("dividing by zero", tree.pos) + case _ => + () + tree end DivideZeroPhase ``` @@ -109,11 +109,11 @@ import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.plugins.ResearchPlugin class DummyResearchPlugin extends ResearchPlugin: - val name: String = "dummy" - override val description: String = "dummy research plugin" + val name: String = "dummy" + override val description: String = "dummy research plugin" - def init(options: List[String], phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = - phases + def init(options: List[String], phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] = + phases end DummyResearchPlugin ``` diff --git a/docs/docs/reference/changed-features/implicit-conversions-spec.md b/docs/docs/reference/changed-features/implicit-conversions-spec.md index 33557ecef72c..930a8a4ebf77 100644 --- a/docs/docs/reference/changed-features/implicit-conversions-spec.md +++ b/docs/docs/reference/changed-features/implicit-conversions-spec.md @@ -17,7 +17,7 @@ The standard library defines an abstract class `Conversion`: package scala @java.lang.FunctionalInterface abstract class Conversion[-T, +U] extends Function1[T, U]: - def apply(x: T): U + def apply(x: T): U ``` Function literals are automatically converted to `Conversion` values. diff --git a/docs/docs/reference/changed-features/implicit-conversions.md b/docs/docs/reference/changed-features/implicit-conversions.md index df713ed09072..d5dd75169cea 100644 --- a/docs/docs/reference/changed-features/implicit-conversions.md +++ b/docs/docs/reference/changed-features/implicit-conversions.md @@ -34,7 +34,7 @@ method that expects a `java.lang.Integer` ```scala import scala.language.implicitConversions implicit def int2Integer(x: Int): java.lang.Integer = - x.asInstanceOf[java.lang.Integer] + x.asInstanceOf[java.lang.Integer] ``` The second example shows how to use `Conversion` to define an @@ -44,11 +44,11 @@ types: ```scala import scala.language.implicitConversions implicit def ordT[T, S]( - implicit conv: Conversion[T, S], - ordS: Ordering[S] + implicit conv: Conversion[T, S], + ordS: Ordering[S] ): Ordering[T] = - // `ordS` compares values of type `S`, but we can convert from `T` to `S` - (x: T, y: T) => ordS.compare(x, y) + // `ordS` compares values of type `S`, but we can convert from `T` to `S` + (x: T, y: T) => ordS.compare(x, y) class A(val x: Int) // The type for which we want an `Ordering` diff --git a/docs/docs/reference/changed-features/implicit-resolution.md b/docs/docs/reference/changed-features/implicit-resolution.md index 90b6c80cf3bf..7f7ebf160c2f 100644 --- a/docs/docs/reference/changed-features/implicit-resolution.md +++ b/docs/docs/reference/changed-features/implicit-resolution.md @@ -13,23 +13,23 @@ where the type may still be inferred: ```scala class C { - val ctx: Context = ... // ok + val ctx: Context = ... // ok - /*!*/ implicit val x = ... // error: type must be given explicitly + /*!*/ implicit val x = ... // error: type must be given explicitly - /*!*/ implicit def y = ... // error: type must be given explicitly + /*!*/ implicit def y = ... // error: type must be given explicitly } val y = { - implicit val ctx = this.ctx // ok - ... + implicit val ctx = this.ctx // ok + ... } ``` **2.** Nesting is now taken into account for selecting an implicit. Consider for instance the following scenario: ```scala def f(implicit i: C) = { - def g(implicit j: C) = { - implicitly[C] - } + def g(implicit j: C) = { + implicitly[C] + } } ``` This will now resolve the `implicitly` call to `j`, because `j` is nested @@ -45,8 +45,8 @@ no longer applies. given a: A = A() object o: - given b: B = B() - type C + given b: B = B() + type C ``` Both `a` and `b` are visible as implicits at the point of the definition of `type C`. However, a reference to `p.o.C` outside of package `p` will diff --git a/docs/docs/reference/changed-features/imports.md b/docs/docs/reference/changed-features/imports.md index cdd24ae6382d..dfdd3fc8edf3 100644 --- a/docs/docs/reference/changed-features/imports.md +++ b/docs/docs/reference/changed-features/imports.md @@ -16,8 +16,8 @@ If you want to import a member named `*` specifically, you can use backticks aro ```scala object A: - def * = ... - def min = ... + def * = ... + def min = ... object B: import A.`*` // imports just `*` diff --git a/docs/docs/reference/changed-features/main-functions.md b/docs/docs/reference/changed-features/main-functions.md index 165bd2efba12..1f45124c820d 100644 --- a/docs/docs/reference/changed-features/main-functions.md +++ b/docs/docs/reference/changed-features/main-functions.md @@ -9,18 +9,18 @@ Example: ```scala @main def happyBirthday(age: Int, name: String, others: String*) = - val suffix = - age % 100 match - case 11 | 12 | 13 => "th" - case _ => - age % 10 match - case 1 => "st" - case 2 => "nd" - case 3 => "rd" - case _ => "th" - val bldr = new StringBuilder(s"Happy $age$suffix birthday, $name") - for other <- others do bldr.append(" and ").append(other) - bldr.toString + val suffix = + age % 100 match + case 11 | 12 | 13 => "th" + case _ => + age % 10 match + case 1 => "st" + case 2 => "nd" + case 3 => "rd" + case _ => "th" + val bldr = new StringBuilder(s"Happy $age$suffix birthday, $name") + for other <- others do bldr.append(" and ").append(other) + bldr.toString ``` This would generate a main program `happyBirthday` that could be called like this @@ -62,15 +62,15 @@ For instance, the `happyBirthDay` method above would generate additional code eq ```scala final class happyBirthday: - import scala.util.CommandLineParser as CLP - def main(args: Array[String]): Unit = - try - happyBirthday( - CLP.parseArgument[Int](args, 0), - CLP.parseArgument[String](args, 1), - CLP.parseRemainingArguments[String](args, 2)) - catch - case error: CLP.ParseError => CLP.showError(error) + import scala.util.CommandLineParser as CLP + def main(args: Array[String]): Unit = + try + happyBirthday( + CLP.parseArgument[Int](args, 0), + CLP.parseArgument[String](args, 1), + CLP.parseRemainingArguments[String](args, 2)) + catch + case error: CLP.ParseError => CLP.showError(error) ``` **Note**: The `` modifier above expresses that the `main` method is generated @@ -80,8 +80,8 @@ as a static method of class `happyBirthDay`. It is not available for user progra ```scala object happyBirthday extends App: - // needs by-hand parsing of arguments vector - ... + // needs by-hand parsing of arguments vector + ... ``` The previous functionality of `App`, which relied on the "magic" [`DelayedInit`](../dropped-features/delayed-init.md) trait, is no longer available. [`App`](https://dotty.epfl.ch/api/scala/App.html) still exists in limited form for now, but it does not support command line arguments and will be deprecated in the future. If programs need to cross-build diff --git a/docs/docs/reference/changed-features/match-syntax.md b/docs/docs/reference/changed-features/match-syntax.md index 67c2f675a704..ee8ebbc305e8 100644 --- a/docs/docs/reference/changed-features/match-syntax.md +++ b/docs/docs/reference/changed-features/match-syntax.md @@ -10,11 +10,11 @@ The syntactical precedence of match expressions has been changed. ```scala xs match { - case Nil => "empty" - case _ => "nonempty" + case Nil => "empty" + case _ => "nonempty" } match { - case "empty" => 0 - case "nonempty" => 1 + case "empty" => 0 + case "nonempty" => 1 } ``` @@ -22,19 +22,19 @@ The syntactical precedence of match expressions has been changed. ```scala xs match - case Nil => "empty" - case _ => "nonempty" + case Nil => "empty" + case _ => "nonempty" match - case "empty" => 0 - case "nonempty" => 1 + case "empty" => 0 + case "nonempty" => 1 ``` 2. `match` may follow a period: ```scala if xs.match - case Nil => false - case _ => true + case Nil => false + case _ => true then "nonempty" else "empty" ``` diff --git a/docs/docs/reference/changed-features/numeric-literals.md b/docs/docs/reference/changed-features/numeric-literals.md index 3ac84541592f..30c6890c525c 100644 --- a/docs/docs/reference/changed-features/numeric-literals.md +++ b/docs/docs/reference/changed-features/numeric-literals.md @@ -17,7 +17,7 @@ val y: BigInt = 0x123_abc_789_def_345_678_901 val z: BigDecimal = 110_222_799_799.99 (y: BigInt) match - case 123_456_789_012_345_678_901 => + case 123_456_789_012_345_678_901 => ``` The syntax of numeric literals is the same as before, except there are no pre-set limits @@ -72,7 +72,7 @@ as follows: ```scala trait FromDigits[T]: - def fromDigits(digits: String): T + def fromDigits(digits: String): T ``` Implementations of the `fromDigits` convert strings of digits to the values of the @@ -88,23 +88,23 @@ numbers that can have both a decimal point and an exponent: ```scala object FromDigits: - /** A subclass of `FromDigits` that also allows to convert whole - * number literals with a radix other than 10 - */ - trait WithRadix[T] extends FromDigits[T]: - def fromDigits(digits: String): T = fromDigits(digits, 10) - def fromDigits(digits: String, radix: Int): T - - /** A subclass of `FromDigits` that also allows to convert number - * literals containing a decimal point ".". - */ - trait Decimal[T] extends FromDigits[T] - - /** A subclass of `FromDigits`that allows also to convert number - * literals containing a decimal point "." or an - * exponent `('e' | 'E')['+' | '-']digit digit*`. - */ - trait Floating[T] extends Decimal[T] + /** A subclass of `FromDigits` that also allows to convert whole + * number literals with a radix other than 10 + */ + trait WithRadix[T] extends FromDigits[T]: + def fromDigits(digits: String): T = fromDigits(digits, 10) + def fromDigits(digits: String, radix: Int): T + + /** A subclass of `FromDigits` that also allows to convert number + * literals containing a decimal point ".". + */ + trait Decimal[T] extends FromDigits[T] + + /** A subclass of `FromDigits`that allows also to convert number + * literals containing a decimal point "." or an + * exponent `('e' | 'E')['+' | '-']digit digit*`. + */ + trait Floating[T] extends Decimal[T] ``` A user-defined number type can implement one of those, which signals to the compiler @@ -131,7 +131,7 @@ As a fully worked out example, here is an implementation of a new numeric class, ```scala case class BigFloat(mantissa: BigInt, exponent: Int): - override def toString = s"${mantissa}e${exponent}" + override def toString = s"${mantissa}e${exponent}" ``` `BigFloat` literals can have a decimal point as well as an exponent. E.g. the following expression @@ -146,34 +146,34 @@ from a `digits` string. Here is a possible implementation: ```scala object BigFloat: - import scala.util.FromDigits - - def apply(digits: String): BigFloat = - val (mantissaDigits, givenExponent) = - digits.toUpperCase.split('E') match - case Array(mantissaDigits, edigits) => - val expo = - try FromDigits.intFromDigits(edigits) - catch case ex: FromDigits.NumberTooLarge => - throw FromDigits.NumberTooLarge(s"exponent too large: $edigits") - (mantissaDigits, expo) - case Array(mantissaDigits) => - (mantissaDigits, 0) - val (intPart, exponent) = - mantissaDigits.split('.') match - case Array(intPart, decimalPart) => - (intPart ++ decimalPart, givenExponent - decimalPart.length) - case Array(intPart) => - (intPart, givenExponent) - BigFloat(BigInt(intPart), exponent) + import scala.util.FromDigits + + def apply(digits: String): BigFloat = + val (mantissaDigits, givenExponent) = + digits.toUpperCase.split('E') match + case Array(mantissaDigits, edigits) => + val expo = + try FromDigits.intFromDigits(edigits) + catch case ex: FromDigits.NumberTooLarge => + throw FromDigits.NumberTooLarge(s"exponent too large: $edigits") + (mantissaDigits, expo) + case Array(mantissaDigits) => + (mantissaDigits, 0) + val (intPart, exponent) = + mantissaDigits.split('.') match + case Array(intPart, decimalPart) => + (intPart ++ decimalPart, givenExponent - decimalPart.length) + case Array(intPart) => + (intPart, givenExponent) + BigFloat(BigInt(intPart), exponent) ``` To accept `BigFloat` literals, all that's needed in addition is a `given` instance of type `FromDigits.Floating[BigFloat]`: ```scala - given FromDigits: FromDigits.Floating[BigFloat] with - def fromDigits(digits: String) = apply(digits) + given FromDigits: FromDigits.Floating[BigFloat] with + def fromDigits(digits: String) = apply(digits) end BigFloat ``` @@ -204,15 +204,15 @@ To do this, replace the `FromDigits` instance in the `BigFloat` object by the fo ```scala object BigFloat: - ... + ... - class FromDigits extends FromDigits.Floating[BigFloat]: - def fromDigits(digits: String) = apply(digits) + class FromDigits extends FromDigits.Floating[BigFloat]: + def fromDigits(digits: String) = apply(digits) - given FromDigits with - override inline def fromDigits(digits: String) = ${ - fromDigitsImpl('digits) - } + given FromDigits with + override inline def fromDigits(digits: String) = ${ + fromDigitsImpl('digits) + } ``` Note that an inline method cannot directly fill in for an abstract method, since it produces @@ -222,17 +222,17 @@ method in the `FromDigits` given instance. That method is defined in terms of a implementation method `fromDigitsImpl`. Here is its definition: ```scala - private def fromDigitsImpl(digits: Expr[String])(using ctx: Quotes): Expr[BigFloat] = - digits.value match - case Some(ds) => - try - val BigFloat(m, e) = apply(ds) - '{BigFloat(${Expr(m)}, ${Expr(e)})} - catch case ex: FromDigits.FromDigitsException => - ctx.error(ex.getMessage) - '{BigFloat(0, 0)} - case None => - '{apply($digits)} + private def fromDigitsImpl(digits: Expr[String])(using ctx: Quotes): Expr[BigFloat] = + digits.value match + case Some(ds) => + try + val BigFloat(m, e) = apply(ds) + '{BigFloat(${Expr(m)}, ${Expr(e)})} + catch case ex: FromDigits.FromDigitsException => + ctx.error(ex.getMessage) + '{BigFloat(0, 0)} + case None => + '{apply($digits)} end BigFloat ``` diff --git a/docs/docs/reference/changed-features/operators.md b/docs/docs/reference/changed-features/operators.md index a9511ab7cc5e..7d0b67be95b2 100644 --- a/docs/docs/reference/changed-features/operators.md +++ b/docs/docs/reference/changed-features/operators.md @@ -18,12 +18,12 @@ import scala.annotation.targetName trait MultiSet[T]: - infix def union(other: MultiSet[T]): MultiSet[T] + infix def union(other: MultiSet[T]): MultiSet[T] - def difference(other: MultiSet[T]): MultiSet[T] + def difference(other: MultiSet[T]): MultiSet[T] - @targetName("intersection") - def *(other: MultiSet[T]): MultiSet[T] + @targetName("intersection") + def *(other: MultiSet[T]): MultiSet[T] end MultiSet @@ -79,8 +79,8 @@ The purpose of the `infix` modifier is to achieve consistency across a code base infix def op3[T](x: T, y: S): R // error: two parameters extension (x: A) - infix def op4(y: B): R // ok - infix def op5(y1: B, y2: B): R // error: two parameters + infix def op4(y: B): R // ok + infix def op5(y1: B, y2: B): R // error: two parameters ``` 4. `infix` modifiers can also be given to type, trait or class definitions that have exactly two type parameters. An infix type like @@ -113,14 +113,14 @@ Infix operators can now appear at the start of lines in a multi-line expression. ```scala val str = "hello" - ++ " world" - ++ "!" + ++ " world" + ++ "!" def condition = - x > 0 - || - xs.exists(_ > 0) - || xs.isEmpty + x > 0 + || + xs.exists(_ > 0) + || xs.isEmpty ``` Previously, those expressions would have been rejected, since the compiler's semicolon inference diff --git a/docs/docs/reference/changed-features/pattern-matching.md b/docs/docs/reference/changed-features/pattern-matching.md index b61ce8fa886e..d2d5dd46e404 100644 --- a/docs/docs/reference/changed-features/pattern-matching.md +++ b/docs/docs/reference/changed-features/pattern-matching.md @@ -101,11 +101,11 @@ For example: ```scala object Even: - def unapply(s: String): Boolean = s.size % 2 == 0 + def unapply(s: String): Boolean = s.size % 2 == 0 "even" match - case s @ Even() => println(s"$s has an even number of characters") - case s => println(s"$s has an odd number of characters") + case s @ Even() => println(s"$s has an even number of characters") + case s => println(s"$s has an odd number of characters") // even has an even number of characters ``` @@ -122,20 +122,20 @@ For example: ```scala class FirstChars(s: String) extends Product: - def _1 = s.charAt(0) - def _2 = s.charAt(1) + def _1 = s.charAt(0) + def _2 = s.charAt(1) // Not used by pattern matching: Product is only used as a marker trait. - def canEqual(that: Any): Boolean = ??? - def productArity: Int = ??? - def productElement(n: Int): Any = ??? + def canEqual(that: Any): Boolean = ??? + def productArity: Int = ??? + def productElement(n: Int): Any = ??? object FirstChars: - def unapply(s: String): FirstChars = new FirstChars(s) + def unapply(s: String): FirstChars = new FirstChars(s) "Hi!" match - case FirstChars(char1, char2) => - println(s"First: $char1; Second: $char2") + case FirstChars(char1, char2) => + println(s"First: $char1; Second: $char2") // First: H; Second: i ``` @@ -148,15 +148,15 @@ object FirstChars: ```scala class Nat(val x: Int): - def get: Int = x - def isEmpty = x < 0 + def get: Int = x + def isEmpty = x < 0 object Nat: - def unapply(x: Int): Nat = new Nat(x) + def unapply(x: Int): Nat = new Nat(x) 5 match - case Nat(n) => println(s"$n is a natural number") - case _ => () + case Nat(n) => println(s"$n is a natural number") + case _ => () // 5 is a natural number ``` @@ -168,15 +168,15 @@ object Nat: ```Scala object ProdEmpty: - def _1: Int = ??? - def _2: String = ??? - def isEmpty = true - def unapply(s: String): this.type = this - def get = this + def _1: Int = ??? + def _2: String = ??? + def isEmpty = true + def unapply(s: String): this.type = this + def get = this "" match - case ProdEmpty(_, _) => ??? - case _ => () + case ProdEmpty(_, _) => ??? + case _ => () ``` @@ -186,10 +186,10 @@ object ProdEmpty: ```Scala type X = { - def lengthCompare(len: Int): Int // or, `def length: Int` - def apply(i: Int): T1 - def drop(n: Int): scala.Seq[T2] - def toSeq: scala.Seq[T3] + def lengthCompare(len: Int): Int // or, `def length: Int` + def apply(i: Int): T1 + def drop(n: Int): scala.Seq[T2] + def toSeq: scala.Seq[T3] } ``` @@ -200,13 +200,13 @@ type X = { ```scala object CharList: - def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList) + def unapplySeq(s: String): Option[Seq[Char]] = Some(s.toList) "example" match - case CharList(c1, c2, c3, c4, _, _, _) => - println(s"$c1,$c2,$c3,$c4") - case _ => - println("Expected *exactly* 7 characters!") + case CharList(c1, c2, c3, c4, _, _, _) => + println(s"$c1,$c2,$c3,$c4") + case _ => + println("Expected *exactly* 7 characters!") // e,x,a,m ``` @@ -222,12 +222,12 @@ object CharList: ```Scala class Foo(val name: String, val children: Int *) object Foo: - def unapplySeq(f: Foo): Option[(String, Seq[Int])] = - Some((f.name, f.children)) + def unapplySeq(f: Foo): Option[(String, Seq[Int])] = + Some((f.name, f.children)) def foo(f: Foo) = f match - case Foo(name, ns : _*) => - case Foo(name, x, y, ns : _*) => + case Foo(name, ns : _*) => + case Foo(name, x, y, ns : _*) => ``` There are plans for further simplification, in particular to factor out *product diff --git a/docs/docs/reference/changed-features/structural-types.md b/docs/docs/reference/changed-features/structural-types.md index 9a056fb2beee..780c5bed6612 100644 --- a/docs/docs/reference/changed-features/structural-types.md +++ b/docs/docs/reference/changed-features/structural-types.md @@ -35,12 +35,12 @@ Here's an example of a structural type `Person`: ```scala class Record(elems: (String, Any)*) extends Selectable: - private val fields = elems.toMap - def selectDynamic(name: String): Any = fields(name) + private val fields = elems.toMap + def selectDynamic(name: String): Any = fields(name) type Person = Record { val name: String; val age: Int } ``` - + The type `Person` adds a _refinement_ to its parent type `Record` that defines the two fields `name` and `age`. We say the refinement is _structural_ since `name` and `age` are not defined in the parent type. But they exist nevertheless as members of class `Person`. For instance, the following program would print "Emma is 42 years old.": @@ -135,11 +135,11 @@ than other classes. Here is an example: ```scala trait Vehicle extends reflect.Selectable: - val wheels: Int + val wheels: Int val i3 = new Vehicle: // i3: Vehicle { val range: Int } - val wheels = 4 - val range = 240 + val wheels = 4 + val range = 240 i3.range ``` @@ -153,11 +153,11 @@ defines the necessary `selectDynamic` member. ```scala trait Vehicle: - val wheels: Int + val wheels: Int val i3 = new Vehicle: // i3: Vehicle - val wheels = 4 - val range = 240 + val wheels = 4 + val range = 240 i3.range // error: range is not a member of `Vehicle` ``` diff --git a/docs/docs/reference/changed-features/vararg-splices.md b/docs/docs/reference/changed-features/vararg-splices.md index a787edd04225..d85ada4a880a 100644 --- a/docs/docs/reference/changed-features/vararg-splices.md +++ b/docs/docs/reference/changed-features/vararg-splices.md @@ -7,10 +7,10 @@ The syntax of vararg splices in patterns and function arguments has changed. The ```scala val arr = Array(0, 1, 2, 3) -val lst = List(arr*) // vararg splice argument +val lst = List(arr*) // vararg splice argument lst match - case List(0, 1, xs*) => println(xs) // binds xs to Seq(2, 3) - case List(1, _*) => // wildcard pattern + case List(0, 1, xs*) => println(xs) // binds xs to Seq(2, 3) + case List(1, _*) => // wildcard pattern ``` The old syntax for splice arguments will be phased out. @@ -18,7 +18,7 @@ The old syntax for splice arguments will be phased out. ```scala /*!*/ val lst = List(arr: _*) // syntax error lst match - case List(0, 1, xs @ _*) // ok, equivalent to `xs*` + case List(0, 1, xs @ _*) // ok, equivalent to `xs*` ``` ## Syntax diff --git a/docs/docs/reference/contextual/by-name-context-parameters.md b/docs/docs/reference/contextual/by-name-context-parameters.md index 549cdb4e08b7..d9e46025f810 100644 --- a/docs/docs/reference/contextual/by-name-context-parameters.md +++ b/docs/docs/reference/contextual/by-name-context-parameters.md @@ -7,14 +7,14 @@ Context parameters can be declared by-name to avoid a divergent inferred expansi ```scala trait Codec[T]: - def write(x: T): Unit + def write(x: T): Unit given intCodec: Codec[Int] = ??? given optionCodec[T](using ev: => Codec[T]): Codec[Option[T]] with - def write(xo: Option[T]) = xo match - case Some(x) => ev.write(x) - case None => + def write(xo: Option[T]) = xo match + case Some(x) => ev.write(x) + case None => val s = summon[Codec[Option[Int]]] @@ -52,7 +52,7 @@ In the example above, the definition of `s` would be expanded as follows. ```scala val s = summon[Test.Codec[Option[Int]]]( - optionCodec[Int](using intCodec) + optionCodec[Int](using intCodec) ) ``` diff --git a/docs/docs/reference/contextual/context-functions-spec.md b/docs/docs/reference/contextual/context-functions-spec.md index 981bc208bf79..01983f2fb899 100644 --- a/docs/docs/reference/contextual/context-functions-spec.md +++ b/docs/docs/reference/contextual/context-functions-spec.md @@ -26,7 +26,7 @@ methods with context parameters. Specifically, the `N`-ary function type ```scala package scala trait ContextFunctionN[-T1, ..., -TN, +R]: - def apply(using x1: T1, ..., xN: TN): R + def apply(using x1: T1, ..., xN: TN): R ``` Context function types erase to normal function types, so these classes are @@ -49,7 +49,7 @@ The context function literal is evaluated as the instance creation expression ```scala new scala.ContextFunctionN[T1, ..., Tn, T]: - def apply(using x1: T1, ..., xn: Tn): T = e + def apply(using x1: T1, ..., xn: Tn): T = e ``` A context parameter may also be a wildcard represented by an underscore `_`. In that case, a fresh name for the parameter is chosen arbitrarily. diff --git a/docs/docs/reference/contextual/context-functions.md b/docs/docs/reference/contextual/context-functions.md index 46b7ffa539ae..a4c615ab3f4b 100644 --- a/docs/docs/reference/contextual/context-functions.md +++ b/docs/docs/reference/contextual/context-functions.md @@ -54,28 +54,28 @@ instance, here is how they can support the "builder pattern", where the aim is to construct tables like this: ```scala table { - row { - cell("top left") - cell("top right") - } - row { - cell("bottom left") - cell("bottom right") - } + row { + cell("top left") + cell("top right") + } + row { + cell("bottom left") + cell("bottom right") + } } ``` The idea is to define classes for `Table` and `Row` that allow the addition of elements via `add`: ```scala class Table: - val rows = new ArrayBuffer[Row] - def add(r: Row): Unit = rows += r - override def toString = rows.mkString("Table(", ", ", ")") + val rows = new ArrayBuffer[Row] + def add(r: Row): Unit = rows += r + override def toString = rows.mkString("Table(", ", ", ")") class Row: - val cells = new ArrayBuffer[Cell] - def add(c: Cell): Unit = cells += c - override def toString = cells.mkString("Row(", ", ", ")") + val cells = new ArrayBuffer[Cell] + def add(c: Cell): Unit = cells += c + override def toString = cells.mkString("Row(", ", ", ")") case class Cell(elem: String) ``` @@ -84,9 +84,9 @@ with context function types as parameters to avoid the plumbing boilerplate that would otherwise be necessary. ```scala def table(init: Table ?=> Unit) = - given t: Table = Table() - init - t + given t: Table = Table() + init + t def row(init: Row ?=> Unit)(using t: Table) = given r: Row = Row() @@ -117,14 +117,14 @@ As a larger example, here is a way to define constructs for checking arbitrary p ```scala object PostConditions: - opaque type WrappedResult[T] = T + opaque type WrappedResult[T] = T - def result[T](using r: WrappedResult[T]): T = r + def result[T](using r: WrappedResult[T]): T = r - extension [T](x: T) - def ensuring(condition: WrappedResult[T] ?=> Boolean): T = - assert(condition(using x)) - x + extension [T](x: T) + def ensuring(condition: WrappedResult[T] ?=> Boolean): T = + assert(condition(using x)) + x end PostConditions import PostConditions.{ensuring, result} @@ -137,14 +137,13 @@ scope to pass along to the `result` method. `WrappedResult` is a fresh type, to that we do not get unwanted givens in scope (this is good practice in all cases where context parameters are involved). Since `WrappedResult` is an opaque type alias, its values need not be boxed, and since `ensuring` is added as an extension method, its argument -does not need boxing either. Hence, the implementation of `ensuring` is as about as efficient -as the best possible code one could write by hand: +does not need boxing either. Hence, the implementation of `ensuring` is close in efficiency to the best possible code one could write by hand: ```scala val s = - val result = List(1, 2, 3).sum - assert(result == 6) - result + val result = List(1, 2, 3).sum + assert(result == 6) + result ``` ### Reference diff --git a/docs/docs/reference/contextual/conversions.md b/docs/docs/reference/contextual/conversions.md index f2f4249efb8d..312dcacd8d8d 100644 --- a/docs/docs/reference/contextual/conversions.md +++ b/docs/docs/reference/contextual/conversions.md @@ -7,12 +7,12 @@ Implicit conversions are defined by given instances of the `scala.Conversion` cl This class is defined in package `scala` as follows: ```scala abstract class Conversion[-T, +U] extends (T => U): - def apply (x: T): U + def apply (x: T): U ``` For example, here is an implicit conversion from `String` to `Token`: ```scala given Conversion[String, Token] with - def apply(str: String): Token = new KeyWord(str) + def apply(str: String): Token = new KeyWord(str) ``` Using an alias this can be expressed more concisely as: ```scala @@ -38,20 +38,20 @@ primitive number types to subclasses of `java.lang.Number`. For instance, the conversion from `Int` to `java.lang.Integer` can be defined as follows: ```scala given int2Integer: Conversion[Int, java.lang.Integer] = - java.lang.Integer.valueOf(_) + java.lang.Integer.valueOf(_) ``` 2. The "magnet" pattern is sometimes used to express many variants of a method. Instead of defining overloaded versions of the method, one can also let the method take one or more arguments of specially defined "magnet" types, into which various argument types can be converted. Example: ```scala object Completions: - // The argument "magnet" type - enum CompletionArg: - case Error(s: String) - case Response(f: Future[HttpResponse]) - case Status(code: Future[StatusCode]) + // The argument "magnet" type + enum CompletionArg: + case Error(s: String) + case Response(f: Future[HttpResponse]) + case Status(code: Future[StatusCode]) - object CompletionArg: + object CompletionArg: // conversions defining the possible arguments to pass to `complete` // these always come with CompletionArg @@ -59,16 +59,16 @@ conversion from `Int` to `java.lang.Integer` can be defined as follows: // // CompletionArg.fromStatusCode(statusCode) - given fromString : Conversion[String, CompletionArg] = Error(_) - given fromFuture : Conversion[Future[HttpResponse], CompletionArg] = Response(_) - given fromStatusCode: Conversion[Future[StatusCode], CompletionArg] = Status(_) - end CompletionArg - import CompletionArg.* + given fromString : Conversion[String, CompletionArg] = Error(_) + given fromFuture : Conversion[Future[HttpResponse], CompletionArg] = Response(_) + given fromStatusCode: Conversion[Future[StatusCode], CompletionArg] = Status(_) + end CompletionArg + import CompletionArg.* - def complete[T](arg: CompletionArg) = arg match - case Error(s) => ... - case Response(f) => ... - case Status(code) => ... + def complete[T](arg: CompletionArg) = arg match + case Error(s) => ... + case Response(f) => ... + case Status(code) => ... end Completions ``` diff --git a/docs/docs/reference/contextual/derivation-macro.md b/docs/docs/reference/contextual/derivation-macro.md index 22b4d0663c7e..913561a5eed5 100644 --- a/docs/docs/reference/contextual/derivation-macro.md +++ b/docs/docs/reference/contextual/derivation-macro.md @@ -17,7 +17,7 @@ As in the original code, the type class definition is the same: ```scala trait Eq[T]: - def eqv(x: T, y: T): Boolean + def eqv(x: T, y: T): Boolean ``` we need to implement a method `Eq.derived` on the companion object of `Eq` that @@ -41,25 +41,25 @@ from the signature. The body of the `derived` method is shown below: ```scala given derived[T: Type](using Quotes): Expr[Eq[T]] = - import quotes.reflect.* + import quotes.reflect.* - val ev: Expr[Mirror.Of[T]] = Expr.summon[Mirror.Of[T]].get + val ev: Expr[Mirror.Of[T]] = Expr.summon[Mirror.Of[T]].get - ev match - case '{ $m: Mirror.ProductOf[T] { type MirroredElemTypes = elementTypes }} => - val elemInstances = summonAll[elementTypes] - val eqProductBody: (Expr[T], Expr[T]) => Expr[Boolean] = (x, y) => - elemInstances.zipWithIndex.foldLeft(Expr(true: Boolean)) { - case (acc, (elem, index)) => - val e1 = '{$x.asInstanceOf[Product].productElement(${Expr(index)})} - val e2 = '{$y.asInstanceOf[Product].productElement(${Expr(index)})} - '{ $acc && $elem.asInstanceOf[Eq[Any]].eqv($e1, $e2) } - } + ev match + case '{ $m: Mirror.ProductOf[T] { type MirroredElemTypes = elementTypes }} => + val elemInstances = summonAll[elementTypes] + val eqProductBody: (Expr[T], Expr[T]) => Expr[Boolean] = (x, y) => + elemInstances.zipWithIndex.foldLeft(Expr(true: Boolean)) { + case (acc, (elem, index)) => + val e1 = '{$x.asInstanceOf[Product].productElement(${Expr(index)})} + val e2 = '{$y.asInstanceOf[Product].productElement(${Expr(index)})} + '{ $acc && $elem.asInstanceOf[Eq[Any]].eqv($e1, $e2) } + } - '{ eqProduct((x: T, y: T) => ${eqProductBody('x, 'y)}) } + '{ eqProduct((x: T, y: T) => ${eqProductBody('x, 'y)}) } - // case for Mirror.ProductOf[T] - // ... + // case for Mirror.ProductOf[T] + // ... ``` Note, that in the `inline` case we can merely write diff --git a/docs/docs/reference/contextual/derivation.md b/docs/docs/reference/contextual/derivation.md index 9a89fad25324..670060236e66 100644 --- a/docs/docs/reference/contextual/derivation.md +++ b/docs/docs/reference/contextual/derivation.md @@ -10,8 +10,8 @@ on. Common examples are `Eq`, `Ordering`, or `Show`. For example, given the foll ```scala enum Tree[T] derives Eq, Ordering, Show: - case Branch(left: Tree[T], right: Tree[T]) - case Leaf(elem: T) + case Branch(left: Tree[T], right: Tree[T]) + case Leaf(elem: T) ``` The `derives` clause generates the following given instances for the `Eq`, `Ordering` and `Show` type classes in the @@ -42,37 +42,37 @@ derivation support. ```scala sealed trait Mirror: - /** the type being mirrored */ - type MirroredType + /** the type being mirrored */ + type MirroredType - /** the type of the elements of the mirrored type */ - type MirroredElemTypes + /** the type of the elements of the mirrored type */ + type MirroredElemTypes - /** The mirrored *-type */ - type MirroredMonoType + /** The mirrored *-type */ + type MirroredMonoType - /** The name of the type */ - type MirroredLabel <: String + /** The name of the type */ + type MirroredLabel <: String - /** The names of the elements of the type */ - type MirroredElemLabels <: Tuple + /** The names of the elements of the type */ + type MirroredElemLabels <: Tuple object Mirror: - /** The Mirror for a product type */ - trait Product extends Mirror: + /** The Mirror for a product type */ + trait Product extends Mirror: - /** Create a new instance of type `T` with elements - * taken from product `p`. - */ - def fromProduct(p: scala.Product): MirroredMonoType + /** Create a new instance of type `T` with elements + * taken from product `p`. + */ + def fromProduct(p: scala.Product): MirroredMonoType - trait Sum extends Mirror: + trait Sum extends Mirror: - /** The ordinal number of the case class of `x`. - * For enums, `ordinal(x) == x.ordinal` - */ - def ordinal(x: MirroredMonoType): Int + /** The ordinal number of the case class of `x`. + * For enums, `ordinal(x) == x.ordinal` + */ + def ordinal(x: MirroredMonoType): Int end Mirror ``` @@ -85,37 +85,37 @@ For the `Tree` ADT from above the following `Mirror` instances will be automatic ```scala // Mirror for Tree new Mirror.Sum: - type MirroredType = Tree - type MirroredElemTypes[T] = (Branch[T], Leaf[T]) - type MirroredMonoType = Tree[_] - type MirroredLabels = "Tree" - type MirroredElemLabels = ("Branch", "Leaf") + type MirroredType = Tree + type MirroredElemTypes[T] = (Branch[T], Leaf[T]) + type MirroredMonoType = Tree[_] + type MirroredLabels = "Tree" + type MirroredElemLabels = ("Branch", "Leaf") - def ordinal(x: MirroredMonoType): Int = x match - case _: Branch[_] => 0 - case _: Leaf[_] => 1 + def ordinal(x: MirroredMonoType): Int = x match + case _: Branch[_] => 0 + case _: Leaf[_] => 1 // Mirror for Branch new Mirror.Product: - type MirroredType = Branch - type MirroredElemTypes[T] = (Tree[T], Tree[T]) - type MirroredMonoType = Branch[_] - type MirroredLabels = "Branch" - type MirroredElemLabels = ("left", "right") + type MirroredType = Branch + type MirroredElemTypes[T] = (Tree[T], Tree[T]) + type MirroredMonoType = Branch[_] + type MirroredLabels = "Branch" + type MirroredElemLabels = ("left", "right") - def fromProduct(p: Product): MirroredMonoType = - new Branch(...) + def fromProduct(p: Product): MirroredMonoType = + new Branch(...) // Mirror for Leaf new Mirror.Product: - type MirroredType = Leaf - type MirroredElemTypes[T] = Tuple1[T] - type MirroredMonoType = Leaf[_] - type MirroredLabels = "Leaf" - type MirroredElemLabels = Tuple1["elem"] - - def fromProduct(p: Product): MirroredMonoType = - new Leaf(...) + type MirroredType = Leaf + type MirroredElemTypes[T] = Tuple1[T] + type MirroredMonoType = Leaf[_] + type MirroredLabels = "Leaf" + type MirroredElemLabels = Tuple1["elem"] + + def fromProduct(p: Product): MirroredMonoType = + new Leaf(...) ``` Note the following properties of `Mirror` types, @@ -169,7 +169,7 @@ type-level constructs in Scala 3: inline methods, inline matches, and implicit s ```scala trait Eq[T]: - def eqv(x: T, y: T): Boolean + def eqv(x: T, y: T): Boolean ``` we need to implement a method `Eq.derived` on the companion object of `Eq` that produces a given instance for `Eq[T]` given @@ -177,10 +177,10 @@ a `Mirror[T]`. Here is a possible implementation, ```scala inline given derived[T](using m: Mirror.Of[T]): Eq[T] = - val elemInstances = summonAll[m.MirroredElemTypes] // (1) - inline m match // (2) - case s: Mirror.SumOf[T] => eqSum(s, elemInstances) - case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances) + val elemInstances = summonAll[m.MirroredElemTypes] // (1) + inline m match // (2) + case s: Mirror.SumOf[T] => eqSum(s, elemInstances) + case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances) ``` Note that `derived` is defined as an `inline` given. This means that the method will be expanded at @@ -194,9 +194,9 @@ implementation of `summonAll` is `inline` and uses Scala 3's `summonInline` cons ```scala inline def summonAll[T <: Tuple]: List[Eq[_]] = - inline erasedValue[T] match - case _: EmptyTuple => Nil - case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] + inline erasedValue[T] match + case _: EmptyTuple => Nil + case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] ``` with the instances for children in hand the `derived` method uses an `inline match` to dispatch to methods which can @@ -210,10 +210,10 @@ instance for the appropriate ADT subtype using the auxiliary method `check` (4). ```scala def eqSum[T](s: Mirror.SumOf[T], elems: List[Eq[_]]): Eq[T] = - new Eq[T]: - def eqv(x: T, y: T): Boolean = - val ordx = s.ordinal(x) // (3) - (s.ordinal(y) == ordx) && check(elems(ordx))(x, y) // (4) + new Eq[T]: + def eqv(x: T, y: T): Boolean = + val ordx = s.ordinal(x) // (3) + (s.ordinal(y) == ordx) && check(elems(ordx))(x, y) // (4) ``` In the product case, `eqProduct` we test the runtime values of the arguments to `eqv` for equality as products based @@ -221,11 +221,11 @@ on the `Eq` instances for the fields of the data type (5), ```scala def eqProduct[T](p: Mirror.ProductOf[T], elems: List[Eq[_]]): Eq[T] = - new Eq[T]: - def eqv(x: T, y: T): Boolean = - iterator(x).zip(iterator(y)).zip(elems.iterator).forall { // (5) - case ((x, y), elem) => check(elem)(x, y) - } + new Eq[T]: + def eqv(x: T, y: T): Boolean = + iterator(x).zip(iterator(y)).zip(elems.iterator).forall { // (5) + case ((x, y), elem) => check(elem)(x, y) + } ``` Pulling this all together we have the following complete implementation, @@ -235,40 +235,40 @@ import scala.deriving.* import scala.compiletime.{erasedValue, summonInline} inline def summonAll[T <: Tuple]: List[Eq[_]] = - inline erasedValue[T] match - case _: EmptyTuple => Nil - case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] + inline erasedValue[T] match + case _: EmptyTuple => Nil + case _: (t *: ts) => summonInline[Eq[t]] :: summonAll[ts] trait Eq[T]: - def eqv(x: T, y: T): Boolean + def eqv(x: T, y: T): Boolean object Eq: - given Eq[Int] with - def eqv(x: Int, y: Int) = x == y - - def check(elem: Eq[_])(x: Any, y: Any): Boolean = - elem.asInstanceOf[Eq[Any]].eqv(x, y) - - def iterator[T](p: T) = p.asInstanceOf[Product].productIterator - - def eqSum[T](s: Mirror.SumOf[T], elems: => List[Eq[_]]): Eq[T] = - new Eq[T]: - def eqv(x: T, y: T): Boolean = - val ordx = s.ordinal(x) - (s.ordinal(y) == ordx) && check(elems(ordx))(x, y) - - def eqProduct[T](p: Mirror.ProductOf[T], elems: => List[Eq[_]]): Eq[T] = - new Eq[T]: - def eqv(x: T, y: T): Boolean = - iterator(x).zip(iterator(y)).zip(elems.iterator).forall { - case ((x, y), elem) => check(elem)(x, y) - } - - inline given derived[T](using m: Mirror.Of[T]): Eq[T] = - lazy val elemInstances = summonAll[m.MirroredElemTypes] - inline m match - case s: Mirror.SumOf[T] => eqSum(s, elemInstances) - case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances) + given Eq[Int] with + def eqv(x: Int, y: Int) = x == y + + def check(elem: Eq[_])(x: Any, y: Any): Boolean = + elem.asInstanceOf[Eq[Any]].eqv(x, y) + + def iterator[T](p: T) = p.asInstanceOf[Product].productIterator + + def eqSum[T](s: Mirror.SumOf[T], elems: => List[Eq[_]]): Eq[T] = + new Eq[T]: + def eqv(x: T, y: T): Boolean = + val ordx = s.ordinal(x) + (s.ordinal(y) == ordx) && check(elems(ordx))(x, y) + + def eqProduct[T](p: Mirror.ProductOf[T], elems: => List[Eq[_]]): Eq[T] = + new Eq[T]: + def eqv(x: T, y: T): Boolean = + iterator(x).zip(iterator(y)).zip(elems.iterator).forall { + case ((x, y), elem) => check(elem)(x, y) + } + + inline given derived[T](using m: Mirror.Of[T]): Eq[T] = + lazy val elemInstances = summonAll[m.MirroredElemTypes] + inline m match + case s: Mirror.SumOf[T] => eqSum(s, elemInstances) + case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances) end Eq ``` @@ -276,15 +276,15 @@ we can test this relative to a simple ADT like so, ```scala enum Opt[+T] derives Eq: - case Sm(t: T) - case Nn + case Sm(t: T) + case Nn @main def test(): Unit = - import Opt.* - val eqoi = summon[Eq[Opt[Int]]] - assert(eqoi.eqv(Sm(23), Sm(23))) - assert(!eqoi.eqv(Sm(23), Sm(13))) - assert(!eqoi.eqv(Sm(23), Nn)) + import Opt.* + val eqoi = summon[Eq[Opt[Int]]] + assert(eqoi.eqv(Sm(23), Sm(23))) + assert(!eqoi.eqv(Sm(23), Sm(13))) + assert(!eqoi.eqv(Sm(23), Nn)) ``` In this case the code that is generated by the inline expansion for the derived `Eq` instance for `Opt` looks like the @@ -292,13 +292,13 @@ following, after a little polishing, ```scala given derived$Eq[T](using eqT: Eq[T]): Eq[Opt[T]] = - eqSum( - summon[Mirror[Opt[T]]], - List( - eqProduct(summon[Mirror[Sm[T]]], List(summon[Eq[T]])), - eqProduct(summon[Mirror[Nn.type]], Nil) - ) - ) + eqSum( + summon[Mirror[Opt[T]]], + List( + eqProduct(summon[Mirror[Sm[T]]], List(summon[Eq[T]])), + eqProduct(summon[Mirror[Nn.type]], Nil) + ) + ) ``` Alternative approaches can be taken to the way that `derived` methods can be defined. For example, more aggressively @@ -310,18 +310,18 @@ As a third example, using a higher level library such as Shapeless the type clas ```scala given eqSum[A](using inst: => K0.CoproductInstances[Eq, A]): Eq[A] with - def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)( - [t] => (eqt: Eq[t], t0: t, t1: t) => eqt.eqv(t0, t1) - ) + def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)( + [t] => (eqt: Eq[t], t0: t, t1: t) => eqt.eqv(t0, t1) + ) given eqProduct[A](using inst: K0.ProductInstances[Eq, A]): Eq[A] with - def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)( - [t] => (acc: Boolean, eqt: Eq[t], t0: t, t1: t) => - Complete(!eqt.eqv(t0, t1))(false)(true) - ) + def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)( + [t] => (acc: Boolean, eqt: Eq[t], t0: t, t1: t) => + Complete(!eqt.eqv(t0, t1))(false)(true) + ) inline def derived[A](using gen: K0.Generic[A]) as Eq[A] = - gen.derive(eqSum, eqProduct) + gen.derive(eqSum, eqProduct) ``` The framework described here enables all three of these approaches without mandating any of them. diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index fea5af12283d..105d7b906c63 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -9,7 +9,7 @@ Extension methods allow one to add methods to a type after the type is defined. case class Circle(x: Double, y: Double, radius: Double) extension (c: Circle) - def circumference: Double = c.radius * math.Pi * 2 + def circumference: Double = c.radius * math.Pi * 2 ``` Like regular methods, extension methods can be invoked with infix `.`: @@ -36,11 +36,11 @@ The extension method syntax can also be used to define operators. Examples: ```scala extension (x: String) - def < (y: String): Boolean = ... + def < (y: String): Boolean = ... extension (x: Elem) - def +: (xs: Seq[Elem]): Seq[Elem] = ... + def +: (xs: Seq[Elem]): Seq[Elem] = ... extension (x: Number) - infix def min (y: Number): Number = ... + infix def min (y: Number): Number = ... "ab" < "c" 1 +: List(2, 3) @@ -68,10 +68,10 @@ It is also possible to extend generic types by adding type parameters to an exte ```scala extension [T](xs: List[T]) - def second = xs.tail.head + def second = xs.tail.head extension [T: Numeric](x: T) - def + (y: T): T = summon[Numeric[T]].plus(x, y) + def + (y: T): T = summon[Numeric[T]].plus(x, y) ``` Type parameters on extensions can also be combined with type parameters on the methods @@ -79,7 +79,7 @@ themselves: ```scala extension [T](xs: List[T]) - def sumBy[U: Numeric](f: T => U): U = ... + def sumBy[U: Numeric](f: T => U): U = ... ``` Type arguments matching method type parameters are passed as usual: @@ -105,7 +105,7 @@ Extensions can also take using clauses. For instance, the `+` extension above co ```scala extension [T](x: T)(using n: Numeric[T]) - def + (y: T): T = n.plus(x, y) + def + (y: T): T = n.plus(x, y) ``` ### Collective Extensions @@ -118,11 +118,11 @@ Example: ```scala extension (ss: Seq[String]) - def longestStrings: Seq[String] = - val maxLength = ss.map(_.length).max - ss.filter(_.length == maxLength) + def longestStrings: Seq[String] = + val maxLength = ss.map(_.length).max + ss.filter(_.length == maxLength) - def longestString: String = longestStrings.head + def longestString: String = longestStrings.head ``` The same can be written with braces as follows (note that indented regions can still be used inside braces): @@ -130,10 +130,10 @@ The same can be written with braces as follows (note that indented regions can s ```scala extension (ss: Seq[String]) { - def longestStrings: Seq[String] = { - val maxLength = ss.map(_.length).max - ss.filter(_.length == maxLength) - } + def longestStrings: Seq[String] = { + val maxLength = ss.map(_.length).max + ss.filter(_.length == maxLength) + } def longestString: String = longestStrings.head } @@ -147,22 +147,22 @@ where each method is defined separately. For instance, the first extension above ```scala extension (ss: Seq[String]) - def longestStrings: Seq[String] = - val maxLength = ss.map(_.length).max - ss.filter(_.length == maxLength) + def longestStrings: Seq[String] = + val maxLength = ss.map(_.length).max + ss.filter(_.length == maxLength) extension (ss: Seq[String]) - def longestString: String = ss.longestStrings.head + def longestString: String = ss.longestStrings.head ``` Collective extensions also can take type parameters and have using clauses. Example: ```scala extension [T](xs: List[T])(using Ordering[T]) - def smallest(n: Int): List[T] = xs.sorted.take(n) - def smallestIndices(n: Int): List[Int] = - val limit = smallest(n).max - xs.zipWithIndex.collect { case (x, i) if x <= limit => i } + def smallest(n: Int): List[T] = xs.sorted.take(n) + def smallestIndices(n: Int): List[Int] = + val limit = smallest(n).max + xs.zipWithIndex.collect { case (x, i) if x <= limit => i } ``` ### Translation of Calls to Extension Methods @@ -183,27 +183,27 @@ Here is an example for the first rule: ```scala trait IntOps: - extension (i: Int) def isZero: Boolean = i == 0 + extension (i: Int) def isZero: Boolean = i == 0 - extension (i: Int) def safeMod(x: Int): Option[Int] = - // extension method defined in same scope IntOps - if x.isZero then None - else Some(i % x) + extension (i: Int) def safeMod(x: Int): Option[Int] = + // extension method defined in same scope IntOps + if x.isZero then None + else Some(i % x) object IntOpsEx extends IntOps: - extension (i: Int) def safeDiv(x: Int): Option[Int] = - // extension method brought into scope via inheritance from IntOps - if x.isZero then None - else Some(i / x) + extension (i: Int) def safeDiv(x: Int): Option[Int] = + // extension method brought into scope via inheritance from IntOps + if x.isZero then None + else Some(i / x) trait SafeDiv: - import IntOpsEx.* // brings safeDiv and safeMod into scope + import IntOpsEx.* // brings safeDiv and safeMod into scope - extension (i: Int) def divide(d: Int): Option[(Int, Int)] = - // extension methods imported and thus in scope - (i.safeDiv(d), i.safeMod(d)) match - case (Some(d), Some(r)) => Some((d, r)) - case _ => None + extension (i: Int) def divide(d: Int): Option[(Int, Int)] = + // extension methods imported and thus in scope + (i.safeDiv(d), i.safeMod(d)) match + case (Some(d), Some(r)) => Some((d, r)) + case _ => None ``` By the second rule, an extension method can be made available by defining a given instance containing it, like this: @@ -218,15 +218,15 @@ By the third and fourth rule, an extension method is available if it is in the i ```scala class List[T]: - ... + ... object List: - ... - extension [T](xs: List[List[T]]) - def flatten: List[T] = xs.foldLeft(List.empty[T])(_ ++ _) + ... + extension [T](xs: List[List[T]]) + def flatten: List[T] = xs.foldLeft(List.empty[T])(_ ++ _) - given [T: Ordering]: Ordering[List[T]] with - extension (xs: List[T]) - def < (ys: List[T]): Boolean = ... + given [T: Ordering]: Ordering[List[T]] with + extension (xs: List[T]) + def < (ys: List[T]): Boolean = ... end List // extension method available since it is in the implicit scope @@ -258,25 +258,25 @@ An extension method can also be referenced using a simple identifier without a p ```scala extension (x: T) - def f ... = ... g ... - def g ... + def f ... = ... g ... + def g ... ``` the identifier is rewritten to `x.g`. This is also the case if `f` and `g` are the same method. Example: ```scala extension (s: String) - def position(ch: Char, n: Int): Int = - if n < s.length && s(n) != ch then position(ch, n + 1) - else n + def position(ch: Char, n: Int): Int = + if n < s.length && s(n) != ch then position(ch, n + 1) + else n ``` The recursive call `position(ch, n + 1)` expands to `s.position(ch, n + 1)` in this case. The whole extension method rewrites to ```scala def position(s: String)(ch: Char, n: Int): Int = - if n < s.length && s(n) != ch then position(s)(ch, n + 1) - else n + if n < s.length && s(n) != ch then position(s)(ch, n + 1) + else n ``` ### Syntax diff --git a/docs/docs/reference/contextual/given-imports.md b/docs/docs/reference/contextual/given-imports.md index c67ae8050245..a763fa938071 100644 --- a/docs/docs/reference/contextual/given-imports.md +++ b/docs/docs/reference/contextual/given-imports.md @@ -7,14 +7,14 @@ A special form of import wildcard selector is used to import given instances. Ex ```scala object A: - class TC - given tc: TC = ??? - def f(using TC) = ??? + class TC + given tc: TC = ??? + def f(using TC) = ??? object B: - import A.* - import A.given - ... + import A.* + import A.given + ... ``` In the code above, the `import A.*` clause in object `B` imports all members @@ -23,7 +23,7 @@ The two import clauses can also be merged into one: ```scala object B: - import A.{given, *} + import A.{given, *} ... ``` @@ -59,10 +59,10 @@ For instance, assuming the object ```scala object Instances: - given intOrd: Ordering[Int] = ... - given listOrd[T: Ordering]: Ordering[List[T]] = ... - given ec: ExecutionContext = ... - given im: Monoid[Int] = ... + given intOrd: Ordering[Int] = ... + given listOrd[T: Ordering]: Ordering[List[T]] = ... + given ec: ExecutionContext = ... + given im: Monoid[Int] = ... ``` the import clause diff --git a/docs/docs/reference/contextual/givens.md b/docs/docs/reference/contextual/givens.md index a65548cd06a2..24526826b28f 100644 --- a/docs/docs/reference/contextual/givens.md +++ b/docs/docs/reference/contextual/givens.md @@ -8,23 +8,23 @@ that serve for synthesizing arguments to [context parameters](./using-clauses.md ```scala trait Ord[T]: - def compare(x: T, y: T): Int - extension (x: T) def < (y: T) = compare(x, y) < 0 - extension (x: T) def > (y: T) = compare(x, y) > 0 + def compare(x: T, y: T): Int + extension (x: T) def < (y: T) = compare(x, y) < 0 + extension (x: T) def > (y: T) = compare(x, y) > 0 given intOrd: Ord[Int] with - def compare(x: Int, y: Int) = - if x < y then -1 else if x > y then +1 else 0 + def compare(x: Int, y: Int) = + if x < y then -1 else if x > y then +1 else 0 given listOrd[T](using ord: Ord[T]): Ord[List[T]] with - def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match - case (Nil, Nil) => 0 - case (Nil, _) => -1 - case (_, Nil) => +1 - case (x :: xs1, y :: ys1) => - val fst = ord.compare(x, y) - if fst != 0 then fst else compare(xs1, ys1) + def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match + case (Nil, Nil) => 0 + case (Nil, _) => -1 + case (_, Nil) => +1 + case (x :: xs1, y :: ys1) => + val fst = ord.compare(x, y) + if fst != 0 then fst else compare(xs1, ys1) ``` @@ -42,9 +42,9 @@ of the last section can also be expressed like this: ```scala given Ord[Int] with - ... + ... given [T](using Ord[T]): Ord[List[T]] with - ... + ... ``` If the name of a given is missing, the compiler will synthesize a name from @@ -107,7 +107,7 @@ Given instances can also appear in patterns. Example: for given Context <- applicationContexts do pair match - case (ctx @ given Context, y) => ... + case (ctx @ given Context, y) => ... ``` In the first fragment above, anonymous given instances for class `Context` are established by enumerating over `applicationContexts`. In the second fragment, a given `Context` @@ -131,13 +131,13 @@ trait Tagged[A] case class Foo[A](value: Boolean) object Foo: - given fooTagged[A](using Tagged[A]): Foo[A] = Foo(true) - given fooNotTagged[A](using NotGiven[Tagged[A]]): Foo[A] = Foo(false) + given fooTagged[A](using Tagged[A]): Foo[A] = Foo(true) + given fooNotTagged[A](using NotGiven[Tagged[A]]): Foo[A] = Foo(false) @main def test(): Unit = - given Tagged[Int]() - assert(summon[Foo[Int]].value) // fooTagged is found - assert(!summon[Foo[String]].value) // fooNotTagged is found + given Tagged[Int]() + assert(summon[Foo[Int]].value) // fooTagged is found + assert(!summon[Foo[String]].value) // fooNotTagged is found ``` ## Given Instance Initialization diff --git a/docs/docs/reference/contextual/multiversal-equality.md b/docs/docs/reference/contextual/multiversal-equality.md index 35a232903576..6ea107084a6a 100644 --- a/docs/docs/reference/contextual/multiversal-equality.md +++ b/docs/docs/reference/contextual/multiversal-equality.md @@ -55,7 +55,7 @@ import annotation.implicitNotFound sealed trait CanEqual[-L, -R] object CanEqual: - object derived extends CanEqual[Any, Any] + object derived extends CanEqual[Any, Any] ``` One can have several `CanEqual` given instances for a type. For example, the four @@ -108,7 +108,7 @@ this generates the following `CanEqual` instance in the companion object of `Box ```scala given [T, U](using CanEqual[T, U]): CanEqual[Box[T], Box[U]] = - CanEqual.derived + CanEqual.derived ``` That is, two boxes are comparable with `==` or `!=` if their elements are. Examples: @@ -173,22 +173,22 @@ we are dealing with a refinement of pre-existing, universal equality. It is best Say you want to come up with a safe version of the `contains` method on `List[T]`. The original definition of `contains` in the standard library was: ```scala class List[+T]: - ... - def contains(x: Any): Boolean + ... + def contains(x: Any): Boolean ``` That uses universal equality in an unsafe way since it permits arguments of any type to be compared with the list's elements. The "obvious" alternative definition ```scala - def contains(x: T): Boolean + def contains(x: T): Boolean ``` does not work, since it refers to the covariant parameter `T` in a nonvariant context. The only variance-correct way to use the type parameter `T` in `contains` is as a lower bound: ```scala - def contains[U >: T](x: U): Boolean + def contains[U >: T](x: U): Boolean ``` This generic version of `contains` is the one used in the current (Scala 2.13) version of `List`. It looks different but it admits exactly the same applications as the `contains(x: Any)` definition we started with. However, we can make it more useful (i.e. restrictive) by adding a `CanEqual` parameter: ```scala - def contains[U >: T](x: U)(using CanEqual[T, U]): Boolean // (1) + def contains[U >: T](x: U)(using CanEqual[T, U]): Boolean // (1) ``` This version of `contains` is equality-safe! More precisely, given `x: T`, `xs: List[T]` and `y: U`, then `xs.contains(y)` is type-correct if and only if @@ -196,7 +196,7 @@ This version of `contains` is equality-safe! More precisely, given Unfortunately, the crucial ability to "lift" equality type checking from simple equality and pattern matching to arbitrary user-defined operations gets lost if we restrict ourselves to an equality class with a single type parameter. Consider the following signature of `contains` with a hypothetical `CanEqual1[T]` type class: ```scala - def contains[U >: T](x: U)(using CanEqual1[U]): Boolean // (2) + def contains[U >: T](x: U)(using CanEqual1[U]): Boolean // (2) ``` This version could be applied just as widely as the original `contains(x: Any)` method, since the `CanEqual1[Any]` fallback is always available! So we have gained nothing. What got lost in the transition to a single parameter type class was the original rule that `CanEqual[A, B]` is available only if neither `A` nor `B` have a reflexive `CanEqual` instance. That rule simply cannot be expressed if there is a single type parameter for `CanEqual`. diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index 784f01dcbf48..988ebc38a0a5 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -34,7 +34,7 @@ Given instances can be mapped to combinations of implicit objects, classes and i ```scala class listOrd[T](implicit ord: Ord[T]) extends Ord[List[T]] { ... } final implicit def listOrd[T](implicit ord: Ord[T]): listOrd[T] = - new listOrd[T] + new listOrd[T] ``` 3. Alias givens map to implicit methods or implicit lazy vals. If an alias has neither type nor context parameters, @@ -114,14 +114,14 @@ Extension methods have no direct counterpart in Scala 2, but they can be simulat ```scala extension (c: Circle) - def circumference: Double = c.radius * math.Pi * 2 + def circumference: Double = c.radius * math.Pi * 2 ``` could be simulated to some degree by ```scala implicit class CircleDecorator(c: Circle) extends AnyVal { - def circumference: Double = c.radius * math.Pi * 2 + def circumference: Double = c.radius * math.Pi * 2 } ``` @@ -153,7 +153,7 @@ one can write ```scala given stringToToken: Conversion[String, Token] with - def apply(str: String): Token = KeyWord(str) + def apply(str: String): Token = KeyWord(str) ``` or diff --git a/docs/docs/reference/contextual/type-classes.md b/docs/docs/reference/contextual/type-classes.md index 5911eff48eed..326df48c377a 100644 --- a/docs/docs/reference/contextual/type-classes.md +++ b/docs/docs/reference/contextual/type-classes.md @@ -17,47 +17,47 @@ Here's the `Monoid` type class definition: ```scala trait SemiGroup[T]: - extension (x: T) def combine (y: T): T + extension (x: T) def combine (y: T): T trait Monoid[T] extends SemiGroup[T]: - def unit: T + def unit: T ``` An implementation of this `Monoid` type class for the type `String` can be the following: ```scala given Monoid[String] with - extension (x: String) def combine (y: String): String = x.concat(y) - def unit: String = "" + extension (x: String) def combine (y: String): String = x.concat(y) + def unit: String = "" ``` Whereas for the type `Int` one could write the following: ```scala given Monoid[Int] with - extension (x: Int) def combine (y: Int): Int = x + y - def unit: Int = 0 + extension (x: Int) def combine (y: Int): Int = x + y + def unit: Int = 0 ``` This monoid can now be used as _context bound_ in the following `combineAll` method: ```scala def combineAll[T: Monoid](xs: List[T]): T = - xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) + xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) ``` To get rid of the `summon[...]` we can define a `Monoid` object as follows: ```scala object Monoid: - def apply[T](using m: Monoid[T]) = m + def apply[T](using m: Monoid[T]) = m ``` Which would allow to re-write the `combineAll` method this way: ```scala def combineAll[T: Monoid](xs: List[T]): T = - xs.foldLeft(Monoid[T].unit)(_.combine(_)) + xs.foldLeft(Monoid[T].unit)(_.combine(_)) ``` ### Functors @@ -69,7 +69,7 @@ The definition of a generic `Functor` would thus be written as: ```scala trait Functor[F[_]]: - def map[A, B](x: F[A], f: A => B): F[B] + def map[A, B](x: F[A], f: A => B): F[B] ``` Which could read as follows: "A `Functor` for the type constructor `F[_]` represents the ability to transform `F[A]` to `F[B]` through the application of function `f` with type `A => B`". We call the `Functor` definition here a _type class_. @@ -77,8 +77,8 @@ This way, we could define an instance of `Functor` for the `List` type: ```scala given Functor[List] with - def map[A, B](x: List[A], f: A => B): List[B] = - x.map(f) // List already has a `map` method + def map[A, B](x: List[A], f: A => B): List[B] = + x.map(f) // List already has a `map` method ``` With this `given` instance in scope, everywhere a `Functor` is expected, the compiler will accept a `List` to be used. @@ -87,7 +87,7 @@ For instance, we may write such a testing method: ```scala def assertTransformation[F[_]: Functor, A, B](expected: F[B], original: F[A], mapping: A => B): Unit = - assert(expected == summon[Functor[F]].map(original, mapping)) + assert(expected == summon[Functor[F]].map(original, mapping)) ``` And use it this way, for example: @@ -101,17 +101,17 @@ As in the previous example of Monoids, [`extension` methods](extension-methods.m ```scala trait Functor[F[_]]: - extension [A](x: F[A]) - def map[B](f: A => B): F[B] + extension [A](x: F[A]) + def map[B](f: A => B): F[B] ``` The instance of `Functor` for `List` now becomes: ```scala given Functor[List] with - extension [A](xs: List[A]) - def map[B](f: A => B): List[B] = - xs.map(f) // List already has a `map` method + extension [A](xs: List[A]) + def map[B](f: A => B): List[B] = + xs.map(f) // List already has a `map` method ``` @@ -119,7 +119,7 @@ It simplifies the `assertTransformation` method: ```scala def assertTransformation[F[_]: Functor, A, B](expected: F[B], original: F[A], mapping: A => B): Unit = - assert(expected == original.map(mapping)) + assert(expected == original.map(mapping)) ``` The `map` method is now directly used on `original`. It is available as an extension method @@ -140,15 +140,15 @@ Here is the translation of this definition in Scala 3: ```scala trait Monad[F[_]] extends Functor[F]: - /** The unit value for a monad */ - def pure[A](x: A): F[A] + /** The unit value for a monad */ + def pure[A](x: A): F[A] - extension [A](x: F[A]) - /** The fundamental composition operation */ - def flatMap[B](f: A => F[B]): F[B] + extension [A](x: F[A]) + /** The fundamental composition operation */ + def flatMap[B](f: A => F[B]): F[B] - /** The `map` operation can now be defined in terms of `flatMap` */ - def map[B](f: A => B) = x.flatMap(f.andThen(pure)) + /** The `map` operation can now be defined in terms of `flatMap` */ + def map[B](f: A => B) = x.flatMap(f.andThen(pure)) end Monad ``` @@ -159,11 +159,11 @@ A `List` can be turned into a monad via this `given` instance: ```scala given listMonad: Monad[List] with - def pure[A](x: A): List[A] = - List(x) - extension [A](xs: List[A]) - def flatMap[B](f: A => List[B]): List[B] = - xs.flatMap(f) // rely on the existing `flatMap` method of `List` + def pure[A](x: A): List[A] = + List(x) + extension [A](xs: List[A]) + def flatMap[B](f: A => List[B]): List[B] = + xs.flatMap(f) // rely on the existing `flatMap` method of `List` ``` Since `Monad` is a subtype of `Functor`, `List` is also a functor. The Functor's `map` @@ -176,12 +176,12 @@ it explicitly. ```scala given optionMonad: Monad[Option] with - def pure[A](x: A): Option[A] = - Option(x) - extension [A](xo: Option[A]) - def flatMap[B](f: A => Option[B]): Option[B] = xo match - case Some(x) => f(x) - case None => None + def pure[A](x: A): Option[A] = + Option(x) + extension [A](xo: Option[A]) + def flatMap[B](f: A => Option[B]): Option[B] = xo match + case Some(x) => f(x) + case None => None ``` #### Reader @@ -224,12 +224,12 @@ The monad instance will look like this: ```scala given configDependentMonad: Monad[ConfigDependent] with - def pure[A](x: A): ConfigDependent[A] = - config => x + def pure[A](x: A): ConfigDependent[A] = + config => x - extension [A](x: ConfigDependent[A]) - def flatMap[B](f: A => ConfigDependent[B]): ConfigDependent[B] = - config => f(x(config))(config) + extension [A](x: ConfigDependent[A]) + def flatMap[B](f: A => ConfigDependent[B]): ConfigDependent[B] = + config => f(x(config))(config) end configDependentMonad ``` @@ -245,12 +245,12 @@ Using this syntax would turn the previous `configDependentMonad` into: ```scala given configDependentMonad: Monad[[Result] =>> Config => Result] with - def pure[A](x: A): Config => A = - config => x + def pure[A](x: A): Config => A = + config => x - extension [A](x: Config => A) - def flatMap[B](f: A => Config => B): Config => B = - config => f(x(config))(config) + extension [A](x: Config => A) + def flatMap[B](f: A => Config => B): Config => B = + config => f(x(config))(config) end configDependentMonad ``` @@ -260,12 +260,12 @@ It is likely that we would like to use this pattern with other kinds of environm ```scala given readerMonad[Ctx]: Monad[[X] =>> Ctx => X] with - def pure[A](x: A): Ctx => A = - ctx => x + def pure[A](x: A): Ctx => A = + ctx => x - extension [A](x: Ctx => A) - def flatMap[B](f: A => Ctx => B): Ctx => B = - ctx => f(x(ctx))(ctx) + extension [A](x: Ctx => A) + def flatMap[B](f: A => Ctx => B): Ctx => B = + ctx => f(x(ctx))(ctx) end readerMonad ``` diff --git a/docs/docs/reference/contextual/using-clauses.md b/docs/docs/reference/contextual/using-clauses.md index 42178a75a64c..9b5b8d6436f7 100644 --- a/docs/docs/reference/contextual/using-clauses.md +++ b/docs/docs/reference/contextual/using-clauses.md @@ -13,7 +13,7 @@ a `max` function that works for any arguments for which an ordering exists can b ```scala def max[T](x: T, y: T)(using ord: Ord[T]): T = - if ord.compare(x, y) < 0 then y else x + if ord.compare(x, y) < 0 then y else x ``` Here, `ord` is a _context parameter_ introduced with a `using` clause. @@ -39,7 +39,7 @@ and just provide its type. Example: ```scala def maximum[T](xs: List[T])(using Ord[T]): T = - xs.reduceLeft(max) + xs.reduceLeft(max) ``` `maximum` takes a context parameter of type `Ord` only to pass it on as an @@ -53,10 +53,10 @@ Here are two other methods that have a context parameter of type `Ord[T]`: ```scala def descending[T](using asc: Ord[T]): Ord[T] = new Ord[T]: - def compare(x: T, y: T) = asc.compare(y, x) + def compare(x: T, y: T) = asc.compare(y, x) def minimum[T](xs: List[T])(using Ord[T]) = - maximum(xs)(using descending) + maximum(xs)(using descending) ``` The `minimum` method's right-hand side passes `descending` as an explicit argument to `maximum(xs)`. diff --git a/docs/docs/reference/dropped-features/auto-apply.md b/docs/docs/reference/dropped-features/auto-apply.md index 9ff9aa648502..7e66f7a97143 100644 --- a/docs/docs/reference/dropped-features/auto-apply.md +++ b/docs/docs/reference/dropped-features/auto-apply.md @@ -74,10 +74,10 @@ exactly in their parameter lists. ```scala class A: - def next(): Int + def next(): Int class B extends A: - def next: Int // overriding error: incompatible type + def next: Int // overriding error: incompatible type ``` Methods overriding Java or Scala 2 methods are again exempted from this diff --git a/docs/docs/reference/dropped-features/delayed-init.md b/docs/docs/reference/dropped-features/delayed-init.md index ca640185252d..f2df991ac743 100644 --- a/docs/docs/reference/dropped-features/delayed-init.md +++ b/docs/docs/reference/dropped-features/delayed-init.md @@ -10,7 +10,7 @@ now partially broken. You can still use `App` as a simple way to set up a main p ```scala object HelloWorld extends App { - println("Hello, world!") + println("Hello, world!") } ``` @@ -21,8 +21,8 @@ you need to use an explicit `main` method for that. ```scala object Hello: - def main(args: Array[String]) = - println(s"Hello, ${args(0)}") + def main(args: Array[String]) = + println(s"Hello, ${args(0)}") ``` On the other hand, Scala 3 offers a convenient alternative to such "program" objects diff --git a/docs/docs/reference/dropped-features/do-while.md b/docs/docs/reference/dropped-features/do-while.md index b2ef652f4898..072f276ce021 100644 --- a/docs/docs/reference/dropped-features/do-while.md +++ b/docs/docs/reference/dropped-features/do-while.md @@ -15,22 +15,22 @@ while ({ ; }) () For instance, instead of ```scala do - i += 1 + i += 1 while (f(i) == 0) ``` one writes ```scala while - i += 1 - f(i) == 0 + i += 1 + f(i) == 0 do () ``` The idea to use a block as the condition of a while also gives a solution to the "loop-and-a-half" problem. Here is another example: ```scala while - val x: Int = iterator.next - x >= 0 + val x: Int = iterator.next + x >= 0 do print(".") ``` diff --git a/docs/docs/reference/dropped-features/nonlocal-returns.md b/docs/docs/reference/dropped-features/nonlocal-returns.md index dd1374c40342..8eca68b8da33 100644 --- a/docs/docs/reference/dropped-features/nonlocal-returns.md +++ b/docs/docs/reference/dropped-features/nonlocal-returns.md @@ -13,13 +13,13 @@ A drop-in library replacement is provided in [`scala.util.control.NonLocalReturn import scala.util.control.NonLocalReturns.* extension [T](xs: List[T]) - def has(elem: T): Boolean = returning { - for x <- xs do - if x == elem then throwReturn(true) - false - } + def has(elem: T): Boolean = returning { + for x <- xs do + if x == elem then throwReturn(true) + false + } @main def test(): Unit = - val xs = List(1, 2, 3, 4, 5) - assert(xs.has(2) == xs.contains(2)) + val xs = List(1, 2, 3, 4, 5) + assert(xs.has(2) == xs.contains(2)) ``` diff --git a/docs/docs/reference/enums/adts.md b/docs/docs/reference/enums/adts.md index 00f33c887998..cf7555c7b49b 100644 --- a/docs/docs/reference/enums/adts.md +++ b/docs/docs/reference/enums/adts.md @@ -9,8 +9,8 @@ how an `Option` type can be represented as an ADT: ```scala enum Option[+T]: - case Some(x: T) - case None + case Some(x: T) + case None ``` This example introduces an `Option` enum with a covariant type @@ -24,8 +24,8 @@ be given explicitly: ```scala enum Option[+T]: - case Some(x: T) extends Option[T] - case None extends Option[Nothing] + case Some(x: T) extends Option[T] + case None extends Option[Nothing] ``` Note that the parent type of the `None` value is inferred as @@ -60,17 +60,17 @@ As all other enums, ADTs can define methods. For instance, here is `Option` agai ```scala enum Option[+T]: - case Some(x: T) - case None + case Some(x: T) + case None - def isDefined: Boolean = this match - case None => false - case _ => true + def isDefined: Boolean = this match + case None => false + case _ => true object Option: - def apply[T >: Null](x: T): Option[T] = - if x == null then None else Some(x) + def apply[T >: Null](x: T): Option[T] = + if x == null then None else Some(x) end Option ``` @@ -84,10 +84,10 @@ parameterized case that takes an RGB value. ```scala enum Color(val rgb: Int): - case Red extends Color(0xFF0000) - case Green extends Color(0x00FF00) - case Blue extends Color(0x0000FF) - case Mix(mix: Int) extends Color(mix) + case Red extends Color(0xFF0000) + case Green extends Color(0x00FF00) + case Blue extends Color(0x0000FF) + case Mix(mix: Int) extends Color(mix) ``` ### Parameter Variance of Enums @@ -101,7 +101,7 @@ mapping a type `T` to itself: ```scala enum View[-T]: - case Refl(f: T => T) + case Refl(f: T => T) ``` The definition of `Refl` is incorrect, as it uses contravariant type `T` in the covariant result position of a @@ -119,7 +119,7 @@ Because `Refl` does not declare explicit parameters, it looks to the compiler li ```scala enum View[-T]: - case Refl[/*synthetic*/-T1](f: T1 => T1) extends View[T1] + case Refl[/*synthetic*/-T1](f: T1 => T1) extends View[T1] ``` The compiler has inferred for `Refl` the contravariant type parameter `T1`, following `T` in `View`. @@ -128,8 +128,8 @@ and can remedy the error by the following change to `Refl`: ```diff enum View[-T]: -- case Refl(f: T => T) -+ case Refl[R](f: R => R) extends View[R] +- case Refl(f: T => T) ++ case Refl[R](f: R => R) extends View[R] ``` Above, type `R` is chosen as the parameter for `Refl` to highlight that it has a different meaning to @@ -140,10 +140,10 @@ as the function type `T => U`: ```scala enum View[-T, +U] extends (T => U): - case Refl[R](f: R => R) extends View[R, R] + case Refl[R](f: R => R) extends View[R, R] - final def apply(t: T): U = this match - case refl: Refl[r] => refl.f(t) + final def apply(t: T): U = this match + case refl: Refl[r] => refl.f(t) ``` ### Syntax of Enums diff --git a/docs/docs/reference/enums/desugarEnums.md b/docs/docs/reference/enums/desugarEnums.md index 6430724e8572..46a2cb2cf1aa 100644 --- a/docs/docs/reference/enums/desugarEnums.md +++ b/docs/docs/reference/enums/desugarEnums.md @@ -41,7 +41,7 @@ map into `case class`es or `val`s. ```scala sealed abstract class E ... extends with scala.reflect.Enum { import E.{ } - + } object E { } ``` @@ -176,10 +176,10 @@ If `E` contains at least one simple case, its companion object will define in ad ```scala private def $new(_$ordinal: Int, $name: String) = - new E with runtime.EnumValue: - def ordinal = _$ordinal - override def productPrefix = $name // if not overridden in `E` - override def toString = $name // if not overridden in `E` + new E with runtime.EnumValue: + def ordinal = _$ordinal + override def productPrefix = $name // if not overridden in `E` + override def toString = $name // if not overridden in `E` ``` The anonymous class also implements the abstract `Product` methods that it inherits from `Enum`. diff --git a/docs/docs/reference/enums/enums.md b/docs/docs/reference/enums/enums.md index b65d2f1e89a4..fa4e0f4d341e 100644 --- a/docs/docs/reference/enums/enums.md +++ b/docs/docs/reference/enums/enums.md @@ -7,7 +7,7 @@ An enumeration is used to define a type consisting of a set of named values. ```scala enum Color: - case Red, Green, Blue + case Red, Green, Blue ``` This defines a new `sealed` class, `Color`, with three values, `Color.Red`, @@ -20,9 +20,9 @@ Enums can be parameterized. ```scala enum Color(val rgb: Int): - case Red extends Color(0xFF0000) - case Green extends Color(0x00FF00) - case Blue extends Color(0x0000FF) + case Red extends Color(0xFF0000) + case Green extends Color(0x00FF00) + case Blue extends Color(0x0000FF) ``` As the example shows, you can define the parameter value by using an @@ -61,18 +61,18 @@ It is possible to add your own definitions to an enum. Example: ```scala enum Planet(mass: Double, radius: Double): - private final val G = 6.67300E-11 - def surfaceGravity = G * mass / (radius * radius) - def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity - - case Mercury extends Planet(3.303e+23, 2.4397e6) - case Venus extends Planet(4.869e+24, 6.0518e6) - case Earth extends Planet(5.976e+24, 6.37814e6) - case Mars extends Planet(6.421e+23, 3.3972e6) - case Jupiter extends Planet(1.9e+27, 7.1492e7) - case Saturn extends Planet(5.688e+26, 6.0268e7) - case Uranus extends Planet(8.686e+25, 2.5559e7) - case Neptune extends Planet(1.024e+26, 2.4746e7) + private final val G = 6.67300E-11 + def surfaceGravity = G * mass / (radius * radius) + def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity + + case Mercury extends Planet(3.303e+23, 2.4397e6) + case Venus extends Planet(4.869e+24, 6.0518e6) + case Earth extends Planet(5.976e+24, 6.37814e6) + case Mars extends Planet(6.421e+23, 3.3972e6) + case Jupiter extends Planet(1.9e+27, 7.1492e7) + case Saturn extends Planet(5.688e+26, 6.0268e7) + case Uranus extends Planet(8.686e+25, 2.5559e7) + case Neptune extends Planet(1.024e+26, 2.4746e7) end Planet ``` @@ -80,11 +80,11 @@ It is also possible to define an explicit companion object for an enum: ```scala object Planet: - def main(args: Array[String]) = - val earthWeight = args(0).toDouble - val mass = earthWeight / Earth.surfaceGravity - for p <- values do - println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + def main(args: Array[String]) = + val earthWeight = args(0).toDouble + val mass = earthWeight / Earth.surfaceGravity + for p <- values do + println(s"Your weight on $p is ${p.surfaceWeight(mass)}") end Planet ``` @@ -96,9 +96,9 @@ To illustrate, say that the `Planet` enum originally had an additional case: ```diff enum Planet(mass: Double, radius: Double): - ... - case Neptune extends Planet(1.024e+26, 2.4746e7) -+ case Pluto extends Planet(1.309e+22, 1.1883e3) + ... + case Neptune extends Planet(1.024e+26, 2.4746e7) ++ case Pluto extends Planet(1.309e+22, 1.1883e3) end Planet ``` @@ -106,12 +106,12 @@ We now want to deprecate the `Pluto` case. First we add the `scala.deprecated` a ```diff enum Planet(mass: Double, radius: Double): - ... - case Neptune extends Planet(1.024e+26, 2.4746e7) -- case Pluto extends Planet(1.309e+22, 1.1883e3) + ... + case Neptune extends Planet(1.024e+26, 2.4746e7) +- case Pluto extends Planet(1.309e+22, 1.1883e3) + -+ @deprecated("refer to IAU definition of planet") -+ case Pluto extends Planet(1.309e+22, 1.1883e3) ++ @deprecated("refer to IAU definition of planet") ++ case Pluto extends Planet(1.309e+22, 1.1883e3) end Planet ``` @@ -119,14 +119,14 @@ Outside the lexical scopes of `enum Planet` or `object Planet`, references to `P ```scala trait Deprecations[T <: reflect.Enum] { - extension (t: T) def isDeprecatedCase: Boolean + extension (t: T) def isDeprecatedCase: Boolean } object Planet { - given Deprecations[Planet] with { - extension (p: Planet) - def isDeprecatedCase = p == Pluto - } + given Deprecations[Planet] with { + extension (p: Planet) + def isDeprecatedCase = p == Pluto + } } ``` @@ -164,8 +164,8 @@ package scala.reflect /** A base trait of all Scala enum definitions */ transparent trait Enum extends Any, Product, Serializable: - /** A number uniquely identifying a case of an enum */ - def ordinal: Int + /** A number uniquely identifying a case of an enum */ + def ordinal: Int ``` Enum values with `extends` clauses get expanded to anonymous class instances. @@ -173,9 +173,9 @@ For instance, the `Venus` value above would be defined like this: ```scala val Venus: Planet = new Planet(4.869E24, 6051800.0): - def ordinal: Int = 1 - override def productPrefix: String = "Venus" - override def toString: String = "Venus" + def ordinal: Int = 1 + override def productPrefix: String = "Venus" + override def toString: String = "Venus" ``` Enum values without `extends` clauses all share a single implementation diff --git a/docs/docs/reference/experimental/erased-defs.md b/docs/docs/reference/experimental/erased-defs.md index bd22a5149614..b2d57584a1a7 100644 --- a/docs/docs/reference/experimental/erased-defs.md +++ b/docs/docs/reference/experimental/erased-defs.md @@ -27,10 +27,10 @@ final class Off extends State @implicitNotFound("State must be Off") class IsOff[S <: State] object IsOff: - given isOff: IsOff[Off] = new IsOff[Off] + given isOff: IsOff[Off] = new IsOff[Off] class Machine[S <: State]: - def turnedOn(using IsOff[S]): Machine[On] = new Machine[On] + def turnedOn(using IsOff[S]): Machine[On] = new Machine[On] val m = new Machine[Off] m.turnedOn @@ -57,7 +57,7 @@ in front of a parameter list (like `given`). def methodWithErasedEv(erased ev: Ev): Int = 42 val lambdaWithErasedEv: erased Ev => Int = - (erased ev: Ev) => 42 + (erased ev: Ev) => 42 ``` `erased` parameters will not be usable for computations, though they can be used @@ -65,10 +65,10 @@ as arguments to other `erased` parameters. ```scala def methodWithErasedInt1(erased i: Int): Int = - i + 42 // ERROR: can not use i + i + 42 // ERROR: can not use i def methodWithErasedInt2(erased i: Int): Int = - methodWithErasedInt1(i) // OK + methodWithErasedInt1(i) // OK ``` Not only parameters can be marked as erased, `val` and `def` can also be marked @@ -125,37 +125,37 @@ final class Off extends State @implicitNotFound("State must be Off") class IsOff[S <: State] object IsOff: - // will not be called at runtime for turnedOn, the - // compiler will only require that this evidence exists - given IsOff[Off] = new IsOff[Off] + // will not be called at runtime for turnedOn, the + // compiler will only require that this evidence exists + given IsOff[Off] = new IsOff[Off] @implicitNotFound("State must be On") class IsOn[S <: State] object IsOn: - // will not exist at runtime, the compiler will only - // require that this evidence exists at compile time - erased given IsOn[On] = new IsOn[On] + // will not exist at runtime, the compiler will only + // require that this evidence exists at compile time + erased given IsOn[On] = new IsOn[On] class Machine[S <: State] private (): - // ev will disappear from both functions - def turnedOn(using erased ev: IsOff[S]): Machine[On] = new Machine[On] - def turnedOff(using erased ev: IsOn[S]): Machine[Off] = new Machine[Off] + // ev will disappear from both functions + def turnedOn(using erased ev: IsOff[S]): Machine[On] = new Machine[On] + def turnedOff(using erased ev: IsOn[S]): Machine[Off] = new Machine[Off] object Machine: - def newMachine(): Machine[Off] = new Machine[Off] + def newMachine(): Machine[Off] = new Machine[Off] @main def test = - val m = Machine.newMachine() - m.turnedOn - m.turnedOn.turnedOff + val m = Machine.newMachine() + m.turnedOn + m.turnedOn.turnedOff - // m.turnedOff - // ^ - // State must be On + // m.turnedOff + // ^ + // State must be On - // m.turnedOn.turnedOn - // ^ - // State must be Off + // m.turnedOn.turnedOn + // ^ + // State must be Off ``` Note that in [Inline](../metaprogramming/inline.md) we discussed `erasedValue` and inline @@ -170,27 +170,27 @@ final class On extends State final class Off extends State class Machine[S <: State]: - transparent inline def turnOn(): Machine[On] = - inline erasedValue[S] match - case _: Off => new Machine[On] - case _: On => error("Turning on an already turned on machine") + transparent inline def turnOn(): Machine[On] = + inline erasedValue[S] match + case _: Off => new Machine[On] + case _: On => error("Turning on an already turned on machine") - transparent inline def turnOff(): Machine[Off] = - inline erasedValue[S] match - case _: On => new Machine[Off] - case _: Off => error("Turning off an already turned off machine") + transparent inline def turnOff(): Machine[Off] = + inline erasedValue[S] match + case _: On => new Machine[Off] + case _: Off => error("Turning off an already turned off machine") object Machine: - def newMachine(): Machine[Off] = - println("newMachine") - new Machine[Off] + def newMachine(): Machine[Off] = + println("newMachine") + new Machine[Off] end Machine @main def test = - val m = Machine.newMachine() - m.turnOn() - m.turnOn().turnOff() - m.turnOn().turnOn() // error: Turning on an already turned on machine + val m = Machine.newMachine() + m.turnOn() + m.turnOn().turnOff() + m.turnOn().turnOn() // error: Turning on an already turned on machine ``` ## Erased Classes diff --git a/docs/docs/reference/metaprogramming/compiletime-ops.md b/docs/docs/reference/metaprogramming/compiletime-ops.md index 86d146818dd2..189ee704ca57 100644 --- a/docs/docs/reference/metaprogramming/compiletime-ops.md +++ b/docs/docs/reference/metaprogramming/compiletime-ops.md @@ -17,9 +17,9 @@ import scala.compiletime.constValue import scala.compiletime.ops.int.S transparent inline def toIntC[N]: Int = - inline constValue[N] match - case 0 => 0 - case _: S[n1] => 1 + toIntC[n1] + inline constValue[N] match + case 0 => 0 + case _: S[n1] => 1 + toIntC[n1] inline val ctwo = toIntC[2] ``` @@ -52,17 +52,17 @@ Using `erasedValue`, we can then define `defaultValue` as follows: import scala.compiletime.erasedValue inline def defaultValue[T] = - inline erasedValue[T] match - case _: Byte => Some(0: Byte) - case _: Char => Some(0: Char) - case _: Short => Some(0: Short) - case _: Int => Some(0) - case _: Long => Some(0L) - case _: Float => Some(0.0f) - case _: Double => Some(0.0d) - case _: Boolean => Some(false) - case _: Unit => Some(()) - case _ => None + inline erasedValue[T] match + case _: Byte => Some(0: Byte) + case _: Char => Some(0: Char) + case _: Short => Some(0: Short) + case _: Int => Some(0) + case _: Long => Some(0L) + case _: Float => Some(0.0f) + case _: Double => Some(0.0d) + case _: Boolean => Some(false) + case _: Unit => Some(()) + case _ => None ``` Then: @@ -82,9 +82,9 @@ Match_ section above. Here is how `toIntT` can be defined: ```scala transparent inline def toIntT[N <: Nat]: Int = - inline scala.compiletime.erasedValue[N] match - case _: Zero.type => 0 - case _: Succ[n] => toIntT[n] + 1 + inline scala.compiletime.erasedValue[N] match + case _: Zero.type => 0 + case _: Succ[n] => toIntT[n] + 1 inline val two = toIntT[Succ[Succ[Zero.type]]] ``` @@ -109,7 +109,7 @@ produces an error message containing the given `msgStr`. import scala.compiletime.{error, code} inline def fail() = - error("failed for a reason") + error("failed for a reason") fail() // error: failed for a reason ``` @@ -118,7 +118,7 @@ or ```scala inline def fail(p1: => Any) = - error(code"failed on: $p1") + error(code"failed on: $p1") fail(identity("foo")) // error: failed on: identity("foo") ``` @@ -162,8 +162,8 @@ import scala.compiletime.ops.* import scala.annotation.infix type +[X <: Int | String, Y <: Int | String] = (X, Y) match - case (Int, Int) => int.+[X, Y] - case (String, String) => string.+[X, Y] + case (Int, Int) => int.+[X, Y] + case (String, String) => string.+[X, Y] val concat: "a" + "b" = "ab" val addition: 1 + 1 = 2 @@ -183,10 +183,10 @@ not. We can create a set of implicit definitions like this: trait SetFor[T, S <: Set[T]] class LowPriority: - implicit def hashSetFor[T]: SetFor[T, HashSet[T]] = ... + implicit def hashSetFor[T]: SetFor[T, HashSet[T]] = ... object SetsFor extends LowPriority: - implicit def treeSetFor[T: Ordering]: SetFor[T, TreeSet[T]] = ... + implicit def treeSetFor[T: Ordering]: SetFor[T, TreeSet[T]] = ... ``` Clearly, this is not pretty. Besides all the usual indirection of implicit @@ -212,8 +212,8 @@ would use it as follows: import scala.compiletime.summonFrom inline def setFor[T]: Set[T] = summonFrom { - case ord: Ordering[T] => new TreeSet[T](using ord) - case _ => new HashSet[T] + case ord: Ordering[T] => new TreeSet[T](using ord) + case _ => new HashSet[T] } ``` @@ -228,8 +228,8 @@ Alternatively, one can also use a pattern-bound given instance, which avoids the import scala.compiletime.summonFrom inline def setFor[T]: Set[T] = summonFrom { - case given Ordering[T] => new TreeSet[T] - case _ => new HashSet[T] + case given Ordering[T] => new TreeSet[T] + case _ => new HashSet[T] } ``` @@ -254,7 +254,7 @@ given a1: A = new A given a2: A = new A inline def f: Any = summonFrom { - case given _: A => ??? // error: ambiguous givens + case given _: A => ??? // error: ambiguous givens } ``` @@ -264,7 +264,7 @@ The shorthand `summonInline` provides a simple way to write a `summon` that is d ```scala transparent inline def summonInline[T]: T = summonFrom { - case t: T => t + case t: T => t } ``` diff --git a/docs/docs/reference/metaprogramming/inline.md b/docs/docs/reference/metaprogramming/inline.md index ee8ebe9d01d7..43ceb553fb49 100644 --- a/docs/docs/reference/metaprogramming/inline.md +++ b/docs/docs/reference/metaprogramming/inline.md @@ -10,21 +10,21 @@ definition will be inlined at the point of use. Example: ```scala object Config: - inline val logging = false + inline val logging = false object Logger: - private var indent = 0 - - inline def log[T](msg: String, indentMargin: =>Int)(op: => T): T = - if Config.logging then - println(s"${" " * indent}start $msg") - indent += indentMargin - val result = op - indent -= indentMargin - println(s"${" " * indent}$msg = $result") - result - else op + private var indent = 0 + + inline def log[T](msg: String, indentMargin: =>Int)(op: => T): T = + if Config.logging then + println(s"${" " * indent}start $msg") + indent += indentMargin + val result = op + indent -= indentMargin + println(s"${" " * indent}$msg = $result") + result + else op end Logger ``` @@ -49,18 +49,18 @@ Here's an example: var indentSetting = 2 def factorial(n: BigInt): BigInt = - log(s"factorial($n)", indentSetting) { - if n == 0 then 1 - else n * factorial(n - 1) - } + log(s"factorial($n)", indentSetting) { + if n == 0 then 1 + else n * factorial(n - 1) + } ``` If `Config.logging == false`, this will be rewritten (simplified) to: ```scala def factorial(n: BigInt): BigInt = - if n == 0 then 1 - else n * factorial(n - 1) + if n == 0 then 1 + else n * factorial(n - 1) ``` As you notice, since neither `msg` or `indentMargin` were used, they do not @@ -73,15 +73,15 @@ In the `true` case the code will be rewritten to: ```scala def factorial(n: BigInt): BigInt = - val msg = s"factorial($n)" - println(s"${" " * indent}start $msg") - Logger.inline$indent_=(indent.+(indentSetting)) - val result = - if n == 0 then 1 - else n * factorial(n - 1) - Logger.inline$indent_=(indent.-(indentSetting)) - println(s"${" " * indent}$msg = $result") - result + val msg = s"factorial($n)" + println(s"${" " * indent}start $msg") + Logger.inline$indent_=(indent.+(indentSetting)) + val result = + if n == 0 then 1 + else n * factorial(n - 1) + Logger.inline$indent_=(indent.-(indentSetting)) + println(s"${" " * indent}$msg = $result") + result ``` Note that the by-value parameter `msg` is evaluated only once, per the usual Scala @@ -97,20 +97,20 @@ straight inline code without any loop or recursion. ```scala inline def power(x: Double, n: Int): Double = - if n == 0 then 1.0 - else if n == 1 then x - else - val y = power(x, n / 2) - if n % 2 == 0 then y * y else y * y * x + if n == 0 then 1.0 + else if n == 1 then x + else + val y = power(x, n / 2) + if n % 2 == 0 then y * y else y * y * x power(expr, 10) // translates to // -// val x = expr -// val y1 = x * x // ^2 -// val y2 = y1 * y1 // ^4 -// val y3 = y2 * x // ^5 -// y3 * y3 // ^10 +// val x = expr +// val y1 = x * x // ^2 +// val y2 = y1 * y1 // ^4 +// val y3 = y2 * x // ^5 +// y3 * y3 // ^10 ``` Parameters of inline methods can have an `inline` modifier as well. This means @@ -124,16 +124,16 @@ parameters: ```scala inline def funkyAssertEquals(actual: Double, expected: =>Double, inline delta: Double): Unit = - if (actual - expected).abs > delta then - throw new AssertionError(s"difference between ${expected} and ${actual} was larger than ${delta}") + if (actual - expected).abs > delta then + throw new AssertionError(s"difference between ${expected} and ${actual} was larger than ${delta}") funkyAssertEquals(computeActual(), computeExpected(), computeDelta()) // translates to // -// val actual = computeActual() -// def expected = computeExpected() -// if (actual - expected).abs > computeDelta() then -// throw new AssertionError(s"difference between ${expected} and ${actual} was larger than ${computeDelta()}") +// val actual = computeActual() +// def expected = computeExpected() +// if (actual - expected).abs > computeDelta() then +// throw new AssertionError(s"difference between ${expected} and ${actual} was larger than ${computeDelta()}") ``` ### Rules for Overriding @@ -144,12 +144,12 @@ Inline methods can override other non-inline methods. The rules are as follows: ```scala abstract class A: - def f: Int - def g: Int = f + def f: Int + def g: Int = f class B extends A: - inline def f = 22 - override inline def g = f + 11 + inline def f = 22 + override inline def g = f + 11 val b = new B val a: A = b @@ -169,10 +169,10 @@ Inline methods can override other non-inline methods. The rules are as follows: ```scala abstract class A: - inline def f: Int + inline def f: Int object B extends A: - inline def f: Int = 22 + inline def f: Int = 22 B.f // OK val a: A = B @@ -231,10 +231,10 @@ It is also possible to have inline vals of types that do not have a syntax, such ```scala trait InlineConstants: - inline val myShort: Short + inline val myShort: Short object Constants extends InlineConstants: - inline val myShort/*: Short(4)*/ = 4 + inline val myShort/*: Short(4)*/ = 4 ``` ## Transparent Inline Methods @@ -246,10 +246,10 @@ specialized to a more precise type upon expansion. Example: ```scala class A class B extends A: - def m = true + def m = true transparent inline def choose(b: Boolean): A = - if b then new A else new B + if b then new A else new B val obj1 = choose(true) // static type is A val obj2 = choose(false) // static type is B @@ -309,8 +309,8 @@ Example: ```scala inline def update(delta: Int) = - inline if delta >= 0 then increaseBy(delta) - else decreaseBy(-delta) + inline if delta >= 0 then increaseBy(delta) + else decreaseBy(-delta) ``` A call `update(22)` would rewrite to `increaseBy(22)`. But if `update` was called with @@ -318,13 +318,13 @@ a value that was not a compile-time constant, we would get a compile time error below: ```scala - | inline if delta >= 0 then ??? - | ^ - | cannot reduce inline if - | its condition - | delta >= 0 - | is not a constant value - | This location is in code that was inlined at ... + | inline if delta >= 0 then ??? + | ^ + | cannot reduce inline if + | its condition + | delta >= 0 + | is not a constant value + | This location is in code that was inlined at ... ``` In a transparent inline, an `inline if` will force the inlining of any inline definition in its condition during type checking. @@ -342,9 +342,9 @@ single inline match expression that picks a case based on its static type: ```scala transparent inline def g(x: Any): Any = - inline x match - case x: String => (x, x) // Tuple2[String, String](x, x) - case x: Double => x + inline x match + case x: String => (x, x) // Tuple2[String, String](x, x) + case x: Double => x g(1.0d) // Has type 1.0d which is a subtype of Double g("test") // Has type (String, String) @@ -362,9 +362,9 @@ case object Zero extends Nat case class Succ[N <: Nat](n: N) extends Nat transparent inline def toInt(n: Nat): Int = - inline n match - case Zero => 0 - case Succ(n1) => toInt(n1) + 1 + inline n match + case Zero => 0 + case Succ(n1) => toInt(n1) + 1 inline val natTwo = toInt(Succ(Succ(Zero))) val intTwo: 2 = natTwo diff --git a/docs/docs/reference/metaprogramming/macros-spec.md b/docs/docs/reference/metaprogramming/macros-spec.md index e03bb2fc2d20..4b5aaada9534 100644 --- a/docs/docs/reference/metaprogramming/macros-spec.md +++ b/docs/docs/reference/metaprogramming/macros-spec.md @@ -176,25 +176,25 @@ implementation of `power` otherwise. import scala.quoted.* inline def power(x: Double, n: Int): Double = - ${ powerExpr('x, 'n) } + ${ powerExpr('x, 'n) } private def powerExpr(x: Expr[Double], n: Expr[Int]) (using Quotes): Expr[Double] = - n.value match - case Some(m) => powerExpr(x, m) - case _ => '{ dynamicPower($x, $n) } + n.value match + case Some(m) => powerExpr(x, m) + case _ => '{ dynamicPower($x, $n) } private def powerExpr(x: Expr[Double], n: Int) (using Quotes): Expr[Double] = - if n == 0 then '{ 1.0 } - else if n == 1 then x - else if n % 2 == 0 then '{ val y = $x * $x; ${ powerExpr('y, n / 2) } } - else '{ $x * ${ powerExpr(x, n - 1) } } + if n == 0 then '{ 1.0 } + else if n == 1 then x + else if n % 2 == 0 then '{ val y = $x * $x; ${ powerExpr('y, n / 2) } } + else '{ $x * ${ powerExpr(x, n - 1) } } private def dynamicPower(x: Double, n: Int): Double = - if n == 0 then 1.0 - else if n % 2 == 0 then dynamicPower(x * x, n / 2) - else x * dynamicPower(x, n - 1) + if n == 0 then 1.0 + else if n % 2 == 0 then dynamicPower(x * x, n / 2) + else x * dynamicPower(x, n - 1) ``` In the above, the method `.value` maps a constant expression of the type @@ -205,15 +205,15 @@ that maps expressions over functions to functions over expressions can be implemented in user code: ```scala given AsFunction1[T, U]: Conversion[Expr[T => U], Expr[T] => Expr[U]] with - def apply(f: Expr[T => U]): Expr[T] => Expr[U] = - (x: Expr[T]) => f match - case Lambda(g) => g(x) - case _ => '{ ($f)($x) } + def apply(f: Expr[T => U]): Expr[T] => Expr[U] = + (x: Expr[T]) => f match + case Lambda(g) => g(x) + case _ => '{ ($f)($x) } ``` This assumes an extractor ```scala object Lambda: - def unapply[T, U](x: Expr[T => U]): Option[Expr[T] => Expr[U]] + def unapply[T, U](x: Expr[T => U]): Option[Expr[T] => Expr[U]] ``` Once we allow inspection of code via extractors, it’s tempting to also add constructors that create typed trees directly without going diff --git a/docs/docs/reference/metaprogramming/macros.md b/docs/docs/reference/metaprogramming/macros.md index 890e4e9da4e6..cd0166e4120c 100644 --- a/docs/docs/reference/metaprogramming/macros.md +++ b/docs/docs/reference/metaprogramming/macros.md @@ -32,15 +32,15 @@ prints it again in an error message if it evaluates to `false`. import scala.quoted.* inline def assert(inline expr: Boolean): Unit = - ${ assertImpl('expr) } + ${ assertImpl('expr) } def assertImpl(expr: Expr[Boolean])(using Quotes) = '{ - if !$expr then - throw AssertionError(s"failed assertion: ${${ showExpr(expr) }}") + if !$expr then + throw AssertionError(s"failed assertion: ${${ showExpr(expr) }}") } def showExpr(expr: Expr[Boolean])(using Quotes): Expr[String] = - '{ "" } // Better implementation later in this document + '{ "" } // Better implementation later in this document ``` If `e` is an expression, then `'{e}` represents the typed @@ -140,10 +140,10 @@ These conversions can be implemented as follows: ```scala def to[T: Type, R: Type](f: Expr[T] => Expr[R])(using Quotes): Expr[T => R] = - '{ (x: T) => ${ f('x) } } + '{ (x: T) => ${ f('x) } } def from[T: Type, R: Type](f: Expr[T => R])(using Quotes): Expr[T] => Expr[R] = - (x: Expr[T]) => '{ $f($x) } + (x: Expr[T]) => '{ $f($x) } ``` Note how the fundamental phase consistency principle works in two @@ -155,10 +155,10 @@ They can be used as follows: ```scala val f1: Expr[Int => String] = - to((x: Expr[Int]) => '{ $x.toString }) // '{ (x: Int) => x.toString } + to((x: Expr[Int]) => '{ $x.toString }) // '{ (x: Int) => x.toString } val f2: Expr[Int] => Expr[String] = - from('{ (x: Int) => x.toString }) // (x: Expr[Int]) => '{ ((x: Int) => x.toString)($x) } + from('{ (x: Int) => x.toString }) // (x: Expr[Int]) => '{ ((x: Int) => x.toString)($x) } f2('{2}) // '{ ((x: Int) => x.toString)(2) } ``` @@ -168,8 +168,8 @@ describing a function into a function mapping trees to trees. ```scala object Expr: - ... - def betaReduce[...](...)(...): ... = ... + ... + def betaReduce[...](...)(...): ... = ... ``` The definition of `Expr.betaReduce(f)(x)` is assumed to be functionally the same as @@ -192,7 +192,7 @@ usage. But the code can be rewritten by adding an explicit binding of a `Type[T] ```scala def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T])(using Type[R], Quotes): Expr[T => R] = - '{ (x: t.Underlying) => ${ f('x) } } + '{ (x: t.Underlying) => ${ f('x) } } ``` In this version of `to`, the type of `x` is now the result of @@ -208,17 +208,17 @@ For instance, the user-level definition of `to`: ```scala def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T], r: Type[R])(using Quotes): Expr[T => R] = - '{ (x: T) => ${ f('x) } } + '{ (x: T) => ${ f('x) } } ``` would be rewritten to ```scala def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T], r: Type[R])(using Quotes): Expr[T => R] = - '{ - type T = t.Underlying - (x: T) => ${ f('x) } - } + '{ + type T = t.Underlying + (x: T) => ${ f('x) } + } ``` The `summon` query succeeds because there is a given instance of @@ -236,10 +236,10 @@ a compiler through staging. import scala.quoted.* enum Exp: - case Num(n: Int) - case Plus(e1: Exp, e2: Exp) - case Var(x: String) - case Let(x: String, e: Exp, in: Exp) + case Num(n: Int) + case Plus(e1: Exp, e2: Exp) + case Var(x: String) + case Let(x: String, e: Exp, in: Exp) import Exp.* ``` @@ -260,15 +260,15 @@ The compiler takes an environment that maps variable names to Scala `Expr`s. import scala.quoted.* def compile(e: Exp, env: Map[String, Expr[Int]])(using Quotes): Expr[Int] = - e match - case Num(n) => - Expr(n) - case Plus(e1, e2) => - '{ ${ compile(e1, env) } + ${ compile(e2, env) } } - case Var(x) => - env(x) - case Let(x, e, body) => - '{ val y = ${ compile(e, env) }; ${ compile(body, env + (x -> 'y)) } } + e match + case Num(n) => + Expr(n) + case Plus(e1, e2) => + '{ ${ compile(e1, env) } + ${ compile(e2, env) } } + case Var(x) => + env(x) + case Let(x, e, body) => + '{ val y = ${ compile(e, env) }; ${ compile(body, env + (x -> 'y)) } } ``` Running `compile(letExp, Map())` would yield the following Scala code: @@ -289,9 +289,9 @@ The `Expr.apply` method is defined in package `quoted`: package quoted object Expr: - ... - def apply[T: ToExpr](x: T)(using Quotes): Expr[T] = - summon[ToExpr[T]].toExpr(x) + ... + def apply[T: ToExpr](x: T)(using Quotes): Expr[T] = + summon[ToExpr[T]].toExpr(x) ``` This method says that values of types implementing the `ToExpr` type class can be @@ -309,8 +309,8 @@ instance, here is a possible instance of `ToExpr[Boolean]`: ```scala given ToExpr[Boolean] with - def toExpr(b: Boolean) = - if b then '{ true } else '{ false } + def toExpr(b: Boolean) = + if b then '{ true } else '{ false } ``` Once we can lift bits, we can work our way up. For instance, here is a @@ -319,12 +319,12 @@ tree machinery: ```scala given ToExpr[Int] with - def toExpr(n: Int) = n match - case Int.MinValue => '{ Int.MinValue } - case _ if n < 0 => '{ - ${ toExpr(-n) } } - case 0 => '{ 0 } - case _ if n % 2 == 0 => '{ ${ toExpr(n / 2) } * 2 } - case _ => '{ ${ toExpr(n / 2) } * 2 + 1 } + def toExpr(n: Int) = n match + case Int.MinValue => '{ Int.MinValue } + case _ if n < 0 => '{ - ${ toExpr(-n) } } + case 0 => '{ 0 } + case _ if n % 2 == 0 => '{ ${ toExpr(n / 2) } * 2 } + case _ => '{ ${ toExpr(n / 2) } * 2 + 1 } ``` Since `ToExpr` is a type class, its instances can be conditional. For example, @@ -332,9 +332,9 @@ a `List` is liftable if its element type is: ```scala given [T: ToExpr : Type]: ToExpr[List[T]] with - def toExpr(xs: List[T]) = xs match - case head :: tail => '{ ${ Expr(head) } :: ${ toExpr(tail) } } - case Nil => '{ Nil: List[T] } + def toExpr(xs: List[T]) = xs match + case head :: tail => '{ ${ Expr(head) } :: ${ toExpr(tail) } } + case Nil => '{ Nil: List[T] } ``` In the end, `ToExpr` resembles very much a serialization @@ -347,8 +347,8 @@ Using lifting, we can now give the missing definition of `showExpr` in the intro ```scala def showExpr[T](expr: Expr[T])(using Quotes): Expr[String] = - val code: String = expr.show - Expr(code) + val code: String = expr.show + Expr(code) ``` That is, the `showExpr` method converts its `Expr` argument to a string (`code`), and lifts @@ -397,24 +397,24 @@ again together with a program that calls `assert`. ```scala object Macros: - inline def assert(inline expr: Boolean): Unit = - ${ assertImpl('expr) } + inline def assert(inline expr: Boolean): Unit = + ${ assertImpl('expr) } - def assertImpl(expr: Expr[Boolean])(using Quotes) = - val failMsg: Expr[String] = Expr("failed assertion: " + expr.show) - '{ if !($expr) then throw new AssertionError($failMsg) } + def assertImpl(expr: Expr[Boolean])(using Quotes) = + val failMsg: Expr[String] = Expr("failed assertion: " + expr.show) + '{ if !($expr) then throw new AssertionError($failMsg) } @main def program = - val x = 1 - Macros.assert(x != 0) + val x = 1 + Macros.assert(x != 0) ``` Inlining the `assert` function would give the following program: ```scala @main def program = - val x = 1 - ${ Macros.assertImpl('{ x != 0) } } + val x = 1 + ${ Macros.assertImpl('{ x != 0) } } ``` The example is only phase correct because `Macros` is a global value and @@ -435,8 +435,8 @@ should be treated by the compiler as if it was quoted: ```scala @main def program = '{ - val x = 1 - ${ Macros.assertImpl('{ x != 0 }) } + val x = 1 + ${ Macros.assertImpl('{ x != 0 }) } } ``` @@ -469,15 +469,15 @@ implementation of the `power` function that makes use of a statically known expo inline def power(x: Double, inline n: Int) = ${ powerCode('x, 'n) } private def powerCode(x: Expr[Double], n: Expr[Int])(using Quotes): Expr[Double] = - n.value match - case Some(m) => powerCode(x, m) - case None => '{ Math.pow($x, $n.toDouble) } + n.value match + case Some(m) => powerCode(x, m) + case None => '{ Math.pow($x, $n.toDouble) } private def powerCode(x: Expr[Double], n: Int)(using Quotes): Expr[Double] = - if n == 0 then '{ 1.0 } - else if n == 1 then x - else if n % 2 == 0 then '{ val y = $x * $x; ${ powerCode('y, n / 2) } } - else '{ $x * ${ powerCode(x, n - 1) } } + if n == 0 then '{ 1.0 } + else if n == 1 then x + else if n % 2 == 0 then '{ val y = $x * $x; ${ powerCode('y, n / 2) } } + else '{ $x * ${ powerCode(x, n - 1) } } ``` ## Scope Extrusion @@ -531,22 +531,22 @@ function `f` and one `sum` that performs a sum by delegating to `map`. ```scala object Macros: - def map[T](arr: Expr[Array[T]], f: Expr[T] => Expr[Unit]) - (using Type[T], Quotes): Expr[Unit] = '{ - var i: Int = 0 - while i < ($arr).length do - val element: T = ($arr)(i) - ${f('element)} - i += 1 - } + def map[T](arr: Expr[Array[T]], f: Expr[T] => Expr[Unit]) + (using Type[T], Quotes): Expr[Unit] = '{ + var i: Int = 0 + while i < ($arr).length do + val element: T = ($arr)(i) + ${f('element)} + i += 1 + } - def sum(arr: Expr[Array[Int]])(using Quotes): Expr[Int] = '{ - var sum = 0 - ${ map(arr, x => '{sum += $x}) } - sum - } + def sum(arr: Expr[Array[Int]])(using Quotes): Expr[Int] = '{ + var sum = 0 + ${ map(arr, x => '{sum += $x}) } + sum + } - inline def sum_m(arr: Array[Int]): Int = ${sum('arr)} + inline def sum_m(arr: Array[Int]): Int = ${sum('arr)} end Macros ``` @@ -588,9 +588,9 @@ var sum = 0 val f = x => '{sum += $x} var i: Int = 0 while i < arr.length do - val element: Int = (arr)(i) - sum += element - i += 1 + val element: Int = (arr)(i) + sum += element + i += 1 sum ``` @@ -601,9 +601,9 @@ val arr: Array[Int] = Array.apply(1, [2,3 : Int]:Int*) var sum = 0 var i: Int = 0 while i < arr.length do - val element: Int = arr(i) - sum += element - i += 1 + val element: Int = arr(i) + sum += element + i += 1 sum ``` @@ -617,9 +617,9 @@ import scala.collection.immutable.{ TreeSet, HashSet } inline def setFor[T]: Set[T] = ${ setForExpr[T] } def setForExpr[T: Type](using Quotes): Expr[Set[T]] = - Expr.summon[Ordering[T]] match - case Some(ord) => '{ new TreeSet[T]()($ord) } - case _ => '{ new HashSet[T] } + Expr.summon[Ordering[T]] match + case Some(ord) => '{ new TreeSet[T]()($ord) } + case _ => '{ new HashSet[T] } ``` ## Relationship with Transparent Inline @@ -630,12 +630,12 @@ inline method that can calculate either a value of type `Int` or a value of type ```scala transparent inline def defaultOf(inline str: String) = - ${ defaultOfImpl('str) } + ${ defaultOfImpl('str) } def defaultOfImpl(strExpr: Expr[String])(using Quotes): Expr[Any] = - strExpr.valueOrError match - case "int" => '{1} - case "string" => '{"a"} + strExpr.valueOrError match + case "int" => '{1} + case "string" => '{"a"} // in a separate file val a: Int = defaultOf("int") @@ -670,17 +670,17 @@ These could be used in the following way to optimize any call to `sum` that has ```scala inline def sum(inline args: Int*): Int = ${ sumExpr('args) } private def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes): Expr[Int] = - argsExpr match - case Varargs(args @ Exprs(argValues)) => - // args is of type Seq[Expr[Int]] - // argValues is of type Seq[Int] - Expr(argValues.sum) // precompute result of sum - case Varargs(argExprs) => // argExprs is of type Seq[Expr[Int]] - val staticSum: Int = argExprs.map(_.value.getOrElse(0)).sum - val dynamicSum: Seq[Expr[Int]] = argExprs.filter(_.value.isEmpty) - dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg }) - case _ => - '{ $argsExpr.sum } + argsExpr match + case Varargs(args @ Exprs(argValues)) => + // args is of type Seq[Expr[Int]] + // argValues is of type Seq[Int] + Expr(argValues.sum) // precompute result of sum + case Varargs(argExprs) => // argExprs is of type Seq[Expr[Int]] + val staticSum: Int = argExprs.map(_.value.getOrElse(0)).sum + val dynamicSum: Seq[Expr[Int]] = argExprs.filter(_.value.isEmpty) + dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg }) + case _ => + '{ $argsExpr.sum } ``` ### Quoted patterns @@ -700,24 +700,24 @@ optimize { def sum(args: Int*): Int = args.sum inline def optimize(inline arg: Int): Int = ${ optimizeExpr('arg) } private def optimizeExpr(body: Expr[Int])(using Quotes): Expr[Int] = - body match - // Match a call to sum without any arguments - case '{ sum() } => Expr(0) - // Match a call to sum with an argument $n of type Int. - // n will be the Expr[Int] representing the argument. - case '{ sum($n) } => n - // Match a call to sum and extracts all its args in an `Expr[Seq[Int]]` - case '{ sum(${Varargs(args)}: _*) } => sumExpr(args) - case body => body + body match + // Match a call to sum without any arguments + case '{ sum() } => Expr(0) + // Match a call to sum with an argument $n of type Int. + // n will be the Expr[Int] representing the argument. + case '{ sum($n) } => n + // Match a call to sum and extracts all its args in an `Expr[Seq[Int]]` + case '{ sum(${Varargs(args)}: _*) } => sumExpr(args) + case body => body private def sumExpr(args1: Seq[Expr[Int]])(using Quotes): Expr[Int] = - def flatSumArgs(arg: Expr[Int]): Seq[Expr[Int]] = arg match - case '{ sum(${Varargs(subArgs)}: _*) } => subArgs.flatMap(flatSumArgs) - case arg => Seq(arg) - val args2 = args1.flatMap(flatSumArgs) - val staticSum: Int = args2.map(_.value.getOrElse(0)).sum - val dynamicSum: Seq[Expr[Int]] = args2.filter(_.value.isEmpty) - dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg }) + def flatSumArgs(arg: Expr[Int]): Seq[Expr[Int]] = arg match + case '{ sum(${Varargs(subArgs)}: _*) } => subArgs.flatMap(flatSumArgs) + case arg => Seq(arg) + val args2 = args1.flatMap(flatSumArgs) + val staticSum: Int = args2.map(_.value.getOrElse(0)).sum + val dynamicSum: Seq[Expr[Int]] = args2.filter(_.value.isEmpty) + dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg }) ``` ### Recovering precise types using patterns @@ -726,47 +726,47 @@ Sometimes it is necessary to get a more precise type for an expression. This can ```scala def f(expr: Expr[Any])(using Quotes) = expr match - case '{ $x: t } => - // If the pattern match succeeds, then there is - // some type `t` such that - // - `x` is bound to a variable of type `Expr[t]` - // - `t` is bound to a new type `t` and a given - // instance `Type[t]` is provided for it - // That is, we have `x: Expr[t]` and `given Type[t]`, - // for some (unknown) type `t`. + case '{ $x: t } => + // If the pattern match succeeds, then there is + // some type `t` such that + // - `x` is bound to a variable of type `Expr[t]` + // - `t` is bound to a new type `t` and a given + // instance `Type[t]` is provided for it + // That is, we have `x: Expr[t]` and `given Type[t]`, + // for some (unknown) type `t`. ``` This might be used to then perform an implicit search as in: ```scala extension (inline sc: StringContext) - inline def showMe(inline args: Any*): String = ${ showMeExpr('sc, 'args) } + inline def showMe(inline args: Any*): String = ${ showMeExpr('sc, 'args) } private def showMeExpr(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using Quotes): Expr[String] = - import quotes.reflect.report - argsExpr match - case Varargs(argExprs) => - val argShowedExprs = argExprs.map { - case '{ $arg: tp } => - Expr.summon[Show[tp]] match - case Some(showExpr) => - '{ $showExpr.show($arg) } - case None => - report.error(s"could not find implicit for ${Type.show[Show[tp]]}", arg); '{???} - } - val newArgsExpr = Varargs(argShowedExprs) - '{ $sc.s($newArgsExpr: _*) } - case _ => - // `new StringContext(...).showMeExpr(args: _*)` not an explicit `showMeExpr"..."` - report.error(s"Args must be explicit", argsExpr) - '{???} + import quotes.reflect.report + argsExpr match + case Varargs(argExprs) => + val argShowedExprs = argExprs.map { + case '{ $arg: tp } => + Expr.summon[Show[tp]] match + case Some(showExpr) => + '{ $showExpr.show($arg) } + case None => + report.error(s"could not find implicit for ${Type.show[Show[tp]]}", arg); '{???} + } + val newArgsExpr = Varargs(argShowedExprs) + '{ $sc.s($newArgsExpr: _*) } + case _ => + // `new StringContext(...).showMeExpr(args: _*)` not an explicit `showMeExpr"..."` + report.error(s"Args must be explicit", argsExpr) + '{???} trait Show[-T]: - def show(x: T): String + def show(x: T): String // in a different file given Show[Boolean] with - def show(b: Boolean) = "boolean!" + def show(b: Boolean) = "boolean!" println(showMe"${true}") ``` @@ -778,8 +778,8 @@ then the rest of the quote can refer to this definition. ```scala '{ - val x: Int = 4 - x * x + val x: Int = 4 + x * x } ``` @@ -796,21 +796,21 @@ the subexpression of type `Expr[Int]` is bound to `body` as an `Expr[Int => Int] inline def eval(inline e: Int): Int = ${ evalExpr('e) } private def evalExpr(e: Expr[Int])(using Quotes): Expr[Int] = e match - case '{ val y: Int = $x; $body(y): Int } => - // body: Expr[Int => Int] where the argument represents - // references to y - evalExpr(Expr.betaReduce('{$body(${evalExpr(x)})})) - case '{ ($x: Int) * ($y: Int) } => - (x.value, y.value) match - case (Some(a), Some(b)) => Expr(a * b) - case _ => e - case _ => e + case '{ val y: Int = $x; $body(y): Int } => + // body: Expr[Int => Int] where the argument represents + // references to y + evalExpr(Expr.betaReduce('{$body(${evalExpr(x)})})) + case '{ ($x: Int) * ($y: Int) } => + (x.value, y.value) match + case (Some(a), Some(b)) => Expr(a * b) + case _ => e + case _ => e ``` ```scala eval { // expands to the code: (16: Int) - val x: Int = 4 - x * x + val x: Int = 4 + x * x } ``` diff --git a/docs/docs/reference/metaprogramming/reflection.md b/docs/docs/reference/metaprogramming/reflection.md index a6c50a6c6038..af1bdafc83d0 100644 --- a/docs/docs/reference/metaprogramming/reflection.md +++ b/docs/docs/reference/metaprogramming/reflection.md @@ -28,8 +28,8 @@ import scala.quoted.* inline def natConst(inline x: Int): Int = ${natConstImpl('{x})} def natConstImpl(x: Expr[Int])(using Quotes): Expr[Int] = - import quotes.reflect.* - ... + import quotes.reflect.* + ... ``` ### Extractors @@ -39,18 +39,18 @@ For example the `Literal(_)` extractor used below. ```scala def natConstImpl(x: Expr[Int])(using Quotes): Expr[Int] = - import quotes.reflect.* - val tree: Term = x.asTerm - tree match - case Inlined(_, _, Literal(IntConstant(n))) => - if n <= 0 then - report.error("Parameter must be natural number") - '{0} - else - tree.asExprOf[Int] - case _ => - report.error("Parameter must be a known constant") - '{0} + import quotes.reflect.* + val tree: Term = x.asTerm + tree match + case Inlined(_, _, Literal(IntConstant(n))) => + if n <= 0 then + report.error("Parameter must be natural number") + '{0} + else + tree.asExprOf[Int] + case _ => + report.error("Parameter must be a known constant") + '{0} ``` We can easily know which extractors are needed using `Printer.TreeStructure.show`, @@ -78,18 +78,18 @@ expansion point. ```scala def macroImpl()(quotes: Quotes): Expr[Unit] = - import quotes.reflect.* - val pos = Position.ofMacroExpansion - - val path = pos.sourceFile.jpath.toString - val start = pos.start - val end = pos.end - val startLine = pos.startLine - val endLine = pos.endLine - val startColumn = pos.startColumn - val endColumn = pos.endColumn - val sourceCode = pos.sourceCode - ... + import quotes.reflect.* + val pos = Position.ofMacroExpansion + + val path = pos.sourceFile.jpath.toString + val start = pos.start + val end = pos.end + val startLine = pos.startLine + val endLine = pos.endLine + val startColumn = pos.startColumn + val endColumn = pos.endColumn + val sourceCode = pos.sourceCode + ... ``` ### Tree Utilities @@ -104,14 +104,14 @@ example, collects the `val` definitions in the tree. ```scala def collectPatternVariables(tree: Tree)(using ctx: Context): List[Symbol] = - val acc = new TreeAccumulator[List[Symbol]]: - def foldTree(syms: List[Symbol], tree: Tree)(owner: Symbol): List[Symbol] = tree match - case ValDef(_, _, rhs) => - val newSyms = tree.symbol :: syms - foldTree(newSyms, body)(tree.symbol) - case _ => - foldOverTree(syms, tree)(owner) - acc(Nil, tree) + val acc = new TreeAccumulator[List[Symbol]]: + def foldTree(syms: List[Symbol], tree: Tree)(owner: Symbol): List[Symbol] = tree match + case ValDef(_, _, rhs) => + val newSyms = tree.symbol :: syms + foldTree(newSyms, body)(tree.symbol) + case _ => + foldOverTree(syms, tree)(owner) + acc(Nil, tree) ``` A `TreeTraverser` extends a `TreeAccumulator` and performs the same traversal diff --git a/docs/docs/reference/metaprogramming/staging.md b/docs/docs/reference/metaprogramming/staging.md index 633f7e2984b4..dac922a2eaa8 100644 --- a/docs/docs/reference/metaprogramming/staging.md +++ b/docs/docs/reference/metaprogramming/staging.md @@ -110,10 +110,10 @@ import scala.quoted.* given staging.Compiler = staging.Compiler.make(getClass.getClassLoader) val f: Array[Int] => Int = staging.run { - val stagedSum: Expr[Array[Int] => Int] = - '{ (arr: Array[Int]) => ${sum('arr)}} - println(stagedSum.show) // Prints "(arr: Array[Int]) => { var sum = 0; ... }" - stagedSum + val stagedSum: Expr[Array[Int] => Int] = + '{ (arr: Array[Int]) => ${sum('arr)}} + println(stagedSum.show) // Prints "(arr: Array[Int]) => { var sum = 0; ... }" + stagedSum } f.apply(Array(1, 2, 3)) // Returns 6 diff --git a/docs/docs/reference/new-types/dependent-function-types-spec.md b/docs/docs/reference/new-types/dependent-function-types-spec.md index e1dd839a9162..6997b5c451bc 100644 --- a/docs/docs/reference/new-types/dependent-function-types-spec.md +++ b/docs/docs/reference/new-types/dependent-function-types-spec.md @@ -26,7 +26,7 @@ refinement types of `scala.FunctionN`. A dependent function type ```scala FunctionN[K1, ..., Kn, R']: - def apply(x1: K1, ..., xN: KN): R + def apply(x1: K1, ..., xN: KN): R ``` where the result type parameter `R'` is the least upper approximation of the @@ -55,15 +55,15 @@ type DF = (x: C) => x.M type IDF = (x: C) ?=> x.M @main def test = - val c = new C { type M = Int; val m = 3 } + val c = new C { type M = Int; val m = 3 } - val depfun: DF = (x: C) => x.m - val t = depfun(c) - println(s"t=$t") // prints "t=3" + val depfun: DF = (x: C) => x.m + val t = depfun(c) + println(s"t=$t") // prints "t=3" - val idepfun: IDF = summon[C].m - val u = idepfun(using c) - println(s"u=$u") // prints "u=3" + val idepfun: IDF = summon[C].m + val u = idepfun(using c) + println(s"u=$u") // prints "u=3" ``` @@ -76,8 +76,8 @@ trait Effect // Type X => Y abstract class Fun[-X, +Y]: - type Eff <: Effect - def apply(x: X): Eff ?=> Y + type Eff <: Effect + def apply(x: X): Eff ?=> Y class CanThrow extends Effect class CanIO extends Effect @@ -86,37 +86,37 @@ given ct: CanThrow = new CanThrow given ci: CanIO = new CanIO class I2S extends Fun[Int, String]: - type Eff = CanThrow - def apply(x: Int) = x.toString + type Eff = CanThrow + def apply(x: Int) = x.toString class S2I extends Fun[String, Int]: - type Eff = CanIO - def apply(x: String) = x.length + type Eff = CanIO + def apply(x: String) = x.length // def map(f: A => B)(xs: List[A]): List[B] def map[A, B](f: Fun[A, B])(xs: List[A]): f.Eff ?=> List[B] = - xs.map(f.apply) + xs.map(f.apply) // def mapFn[A, B]: (A => B) -> List[A] -> List[B] def mapFn[A, B]: (f: Fun[A, B]) => List[A] => f.Eff ?=> List[B] = - f => xs => map(f)(xs) + f => xs => map(f)(xs) // def compose(f: A => B)(g: B => C)(x: A): C def compose[A, B, C](f: Fun[A, B])(g: Fun[B, C])(x: A): - f.Eff ?=> g.Eff ?=> C = - g(f(x)) + f.Eff ?=> g.Eff ?=> C = + g(f(x)) // def composeFn: (A => B) -> (B => C) -> A -> C def composeFn[A, B, C]: - (f: Fun[A, B]) => (g: Fun[B, C]) => A => f.Eff ?=> g.Eff ?=> C = - f => g => x => compose(f)(g)(x) + (f: Fun[A, B]) => (g: Fun[B, C]) => A => f.Eff ?=> g.Eff ?=> C = + f => g => x => compose(f)(g)(x) @main def test = - val i2s = new I2S - val s2i = new S2I + val i2s = new I2S + val s2i = new S2I - assert(mapFn(i2s)(List(1, 2, 3)).mkString == "123") - assert(composeFn(i2s)(s2i)(22) == 2) + assert(mapFn(i2s)(List(1, 2, 3)).mkString == "123") + assert(composeFn(i2s)(s2i)(22) == 2) ``` ### Type Checking diff --git a/docs/docs/reference/new-types/dependent-function-types.md b/docs/docs/reference/new-types/dependent-function-types.md index 07becacc82ba..134e80352d3d 100644 --- a/docs/docs/reference/new-types/dependent-function-types.md +++ b/docs/docs/reference/new-types/dependent-function-types.md @@ -42,7 +42,7 @@ refinement. In fact, the dependent function type above is just syntactic sugar f ```scala Function1[Entry, Entry#Key]: - def apply(e: Entry): e.Key + def apply(e: Entry): e.Key ``` [More details](./dependent-function-types-spec.md) diff --git a/docs/docs/reference/new-types/intersection-types.md b/docs/docs/reference/new-types/intersection-types.md index a2cfc1f380c8..2ec36a8d397d 100644 --- a/docs/docs/reference/new-types/intersection-types.md +++ b/docs/docs/reference/new-types/intersection-types.md @@ -11,14 +11,14 @@ The type `S & T` represents values that are of the type `S` and `T` at the same ```scala trait Resettable: - def reset(): Unit + def reset(): Unit trait Growable[T]: - def add(t: T): Unit + def add(t: T): Unit def f(x: Resettable & Growable[String]) = - x.reset() - x.add("first") + x.reset() + x.add("first") ``` The parameter `x` is required to be _both_ a `Resettable` and a @@ -35,10 +35,10 @@ of its type in `A` and its type in `B`. For instance, assume the definitions: ```scala trait A: - def children: List[A] + def children: List[A] trait B: - def children: List[B] + def children: List[B] val x: A & B = new C val ys: List[A & B] = x.children @@ -60,7 +60,7 @@ to give at that point a definition of a `children` method with the required type ```scala class C extends A, B: - def children: List[A & B] = ??? + def children: List[A & B] = ??? ``` diff --git a/docs/docs/reference/new-types/match-types.md b/docs/docs/reference/new-types/match-types.md index 7be51e6a09bd..a73c36df2c26 100644 --- a/docs/docs/reference/new-types/match-types.md +++ b/docs/docs/reference/new-types/match-types.md @@ -8,9 +8,9 @@ its scrutinee. For example: ```scala type Elem[X] = X match - case String => Char - case Array[t] => t - case Iterable[t] => t + case String => Char + case Array[t] => t + case Iterable[t] => t ``` This defines a type that reduces as follows: @@ -38,18 +38,18 @@ Match types can form part of recursive type definitions. Example: ```scala type LeafElem[X] = X match - case String => Char - case Array[t] => LeafElem[t] - case Iterable[t] => LeafElem[t] - case AnyVal => X + case String => Char + case Array[t] => LeafElem[t] + case Iterable[t] => LeafElem[t] + case AnyVal => X ``` Recursive match type definitions can also be given an upper bound, like this: ```scala type Concat[Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match - case EmptyTuple => Ys - case x *: xs => x *: Concat[xs, Ys] + case EmptyTuple => Ys + case x *: xs => x *: Concat[xs, Ys] ``` In this definition, every instance of `Concat[A, B]`, whether reducible or not, @@ -65,10 +65,10 @@ use of the match type as the return type): ```scala def leafElem[X](x: X): LeafElem[X] = x match - case x: String => x.charAt(0) - case x: Array[t] => leafElem(x(9)) - case x: Iterable[t] => leafElem(x.head) - case x: AnyVal => x + case x: String => x.charAt(0) + case x: Array[t] => leafElem(x(9)) + case x: Iterable[t] => leafElem(x.head) + case x: AnyVal => x ``` This special mode of typing for match expressions is only used when the @@ -191,7 +191,7 @@ error message: ```scala type L[X] = X match - case Int => L[X] + case Int => L[X] def g[X]: L[X] = ??? ``` diff --git a/docs/docs/reference/new-types/polymorphic-function-types.md b/docs/docs/reference/new-types/polymorphic-function-types.md index 1be8baca17ad..18749a366190 100644 --- a/docs/docs/reference/new-types/polymorphic-function-types.md +++ b/docs/docs/reference/new-types/polymorphic-function-types.md @@ -49,8 +49,8 @@ in a strongly-typed way: ```scala enum Expr[A]: - case Var(name: String) - case Apply[A, B](fun: Expr[B => A], arg: Expr[B]) extends Expr[A] + case Var(name: String) + case Apply[A, B](fun: Expr[B => A], arg: Expr[B]) extends Expr[A] ``` We would like to provide a way for users to map a function @@ -61,9 +61,9 @@ Here is how to implement this using polymorphic function types: ```scala def mapSubexpressions[A](e: Expr[A])(f: [B] => Expr[B] => Expr[B]): Expr[A] = - e match - case Apply(fun, arg) => Apply(f(fun), f(arg)) - case Var(n) => Var(n) + e match + case Apply(fun, arg) => Apply(f(fun), f(arg)) + case Var(n) => Var(n) ``` And here is how to use this function to _wrap_ each subexpression @@ -73,7 +73,7 @@ defined as a variable: ```scala val e0 = Apply(Var("f"), Var("a")) val e1 = mapSubexpressions(e0)( - [B] => (se: Expr[B]) => Apply(Var[B => B]("wrap"), se)) + [B] => (se: Expr[B]) => Apply(Var[B => B]("wrap"), se)) println(e1) // Apply(Apply(Var(wrap),Var(f)),Apply(Var(wrap),Var(a))) ``` diff --git a/docs/docs/reference/new-types/union-types.md b/docs/docs/reference/new-types/union-types.md index 4de0fd842421..6b5b8f8f1a63 100644 --- a/docs/docs/reference/new-types/union-types.md +++ b/docs/docs/reference/new-types/union-types.md @@ -11,10 +11,10 @@ case class UserName(name: String) case class Password(hash: Hash) def help(id: UserName | Password) = - val user = id match - case UserName(name) => lookupName(name) - case Password(hash) => lookupPassword(hash) - ... + val user = id match + case UserName(name) => lookupName(name) + case Password(hash) => lookupPassword(hash) + ... ``` Union types are duals of intersection types. `|` is _commutative_: diff --git a/docs/docs/reference/other-new-features/control-syntax.md b/docs/docs/reference/other-new-features/control-syntax.md index 544eb5ebd584..9071383b7bbf 100644 --- a/docs/docs/reference/other-new-features/control-syntax.md +++ b/docs/docs/reference/other-new-features/control-syntax.md @@ -8,11 +8,11 @@ enclosing the condition in parentheses, and also allows to drop parentheses or b around the generators of a `for`-expression. Examples: ```scala if x < 0 then - "negative" + "negative" else if x == 0 then - "zero" + "zero" else - "positive" + "positive" if x < 0 then -x else x @@ -22,10 +22,10 @@ for x <- xs if x > 0 yield x * x for - x <- xs - y <- ys + x <- xs + y <- ys do - println(x + y) + println(x + y) try body catch case ex: IOException => handle diff --git a/docs/docs/reference/other-new-features/creator-applications.md b/docs/docs/reference/other-new-features/creator-applications.md index 219fb16d2ea0..8cc3e41ff1d5 100644 --- a/docs/docs/reference/other-new-features/creator-applications.md +++ b/docs/docs/reference/other-new-features/creator-applications.md @@ -10,7 +10,7 @@ Scala 3 generalizes this scheme to all concrete classes. Example: ```scala class StringBuilder(s: String): - def this() = this("") + def this() = this("") StringBuilder("abc") // old: new StringBuilder("abc") StringBuilder() // old: new StringBuilder() @@ -21,8 +21,8 @@ is generated together with the class. The object looks like this: ```scala object StringBuilder: - inline def apply(s: String): StringBuilder = new StringBuilder(s) - inline def apply(): StringBuilder = new StringBuilder() + inline def apply(s: String): StringBuilder = new StringBuilder(s) + inline def apply(): StringBuilder = new StringBuilder() ``` The synthetic object `StringBuilder` and its `apply` methods are called _constructor proxies_. diff --git a/docs/docs/reference/other-new-features/explicit-nulls.md b/docs/docs/reference/other-new-features/explicit-nulls.md index 1eb245fd1cec..29ea6701a9ff 100644 --- a/docs/docs/reference/other-new-features/explicit-nulls.md +++ b/docs/docs/reference/other-new-features/explicit-nulls.md @@ -72,8 +72,8 @@ The unsoundness happens because uninitialized fields in a class start out as `nu ```scala class C: - val f: String = foo(f) - def foo(f2: String): String = f2 + val f: String = foo(f) + def foo(f2: String): String = f2 val c = new C() // c.f == "field is null" @@ -123,8 +123,8 @@ We illustrate the rules with following examples: ```java class C { - String s; - int x; + String s; + int x; } ``` @@ -132,8 +132,8 @@ We illustrate the rules with following examples: ```scala class C: - val s: String | Null - val x: Int + val s: String | Null + val x: Int ``` - We nullify type parameters because in Java a type parameter is always nullable, so the following code compiles. @@ -152,8 +152,8 @@ We illustrate the rules with following examples: ```scala class InScala: - val c: C[Bool] = ??? // C as above - val b: Bool = c.foo() // no longer typechecks, since foo now returns Bool | Null + val c: C[Bool] = ??? // C as above + val b: Bool = c.foo() // no longer typechecks, since foo now returns Bool | Null ``` - We can reduce the number of redundant nullable types we need to add. Consider @@ -193,8 +193,8 @@ We illustrate the rules with following examples: ```scala class BoxFactory[T]: - def makeBox(): Box[T | Null] | Null - def makeCrazyBoxes(): java.util.List[Box[java.util.List[T] | Null]] | Null + def makeBox(): Box[T | Null] | Null + def makeCrazyBoxes(): java.util.List[Box[java.util.List[T] | Null]] | Null ``` In this case, since `Box` is Scala-defined, we will get `Box[T | Null] | Null`. @@ -209,11 +209,11 @@ We illustrate the rules with following examples: ```java class Constants { - final String NAME = "name"; - final int AGE = 0; - final char CHAR = 'a'; + final String NAME = "name"; + final int AGE = 0; + final char CHAR = 'a'; - final String NAME_GENERATED = getNewName(); + final String NAME_GENERATED = getNewName(); } ``` @@ -221,11 +221,11 @@ We illustrate the rules with following examples: ```scala class Constants: - val NAME: String("name") = "name" - val AGE: Int(0) = 0 - val CHAR: Char('a') = 'a' + val NAME: String("name") = "name" + val AGE: Int(0) = 0 + val CHAR: Char('a') = 'a' - val NAME_GENERATED: String | Null = getNewName() + val NAME_GENERATED: String | Null = getNewName() ``` - We don't append `Null` to a field nor to a return type of a method which is annotated with a @@ -233,9 +233,9 @@ We illustrate the rules with following examples: ```java class C { - @NotNull String name; - @NotNull List getNames(String prefix); // List is Java-defined - @NotNull Box getBoxedName(); // Box is Scala-defined + @NotNull String name; + @NotNull List getNames(String prefix); // List is Java-defined + @NotNull Box getBoxedName(); // Box is Scala-defined } ``` @@ -243,9 +243,9 @@ We illustrate the rules with following examples: ```scala class C: - val name: String - def getNames(prefix: String | Null): java.util.List[String] // we still need to nullify the paramter types - def getBoxedName(): Box[String | Null] // we don't append `Null` to the outmost level, but we still need to nullify inside + val name: String + def getNames(prefix: String | Null): java.util.List[String] // we still need to nullify the paramter types + def getBoxedName(): Box[String | Null] // we don't append `Null` to the outmost level, but we still need to nullify inside ``` The annotation must be from the list below to be recognized as `NotNull` by the compiler. @@ -304,7 +304,7 @@ Example: ```scala val s: String | Null = ??? if s != null then - // s: String + // s: String // s: String | Null @@ -316,9 +316,9 @@ A similar inference can be made for the `else` case if the test is `p == null` ```scala if s == null then - // s: String | Null + // s: String | Null else - // s: String + // s: String ``` `==` and `!=` is considered a comparison for the purposes of the flow inference. @@ -331,15 +331,15 @@ We also support logical operators (`&&`, `||`, and `!`): val s: String | Null = ??? val s2: String | Null = ??? if s != null && s2 != null then - // s: String - // s2: String + // s: String + // s2: String if s == null || s2 == null then - // s: String | Null - // s2: String | Null + // s: String | Null + // s2: String | Null else - // s: String - // s2: String + // s: String + // s2: String ``` ### Inside Conditions @@ -350,12 +350,12 @@ We also support type specialization _within_ the condition, taking into account val s: String | Null = ??? if s != null && s.length > 0 then // s: String in `s.length > 0` - // s: String + // s: String if s == null || s.length > 0 then // s: String in `s.length > 0` - // s: String | Null + // s: String | Null else - // s: String + // s: String ``` ### Match Case @@ -366,8 +366,8 @@ The non-null cases can be detected in match statements. val s: String | Null = ??? s match - case _: String => // s: String - case _ => + case _: String => // s: String + case _ => ``` ### Mutable Variable @@ -380,13 +380,13 @@ class C(val x: Int, val next: C | Null) var xs: C | Null = C(1, C(2, null)) // xs is trackable, since all assignments are in the same method while xs != null do - // xs: C - val xsx: Int = xs.x - val xscpy: C = xs - xs = xscpy // since xscpy is non-null, xs still has type C after this line - // xs: C - xs = xs.next // after this assignment, xs can be null again - // xs: C | Null + // xs: C + val xsx: Int = xs.x + val xscpy: C = xs + xs = xscpy // since xscpy is non-null, xs still has type C after this line + // xs: C + xs = xs.next // after this assignment, xs can be null again + // xs: C | Null ``` When dealing with local mutable variables, there are two questions: @@ -399,7 +399,7 @@ When dealing with local mutable variables, there are two questions: ```scala var x: String | Null = ??? def y = - x = null + x = null if x != null then // y can be called here, which would break the fact @@ -416,13 +416,13 @@ When dealing with local mutable variables, there are two questions: ```scala var x: String | Null = ??? def y = - if x != null then - // not safe to use the fact (x != null) here - // since y can be executed at the same time as the outer block - val _: String = x + if x != null then + // not safe to use the fact (x != null) here + // since y can be executed at the same time as the outer block + val _: String = x if x != null then - val a: String = x // ok to use the fact here - x = null + val a: String = x // ok to use the fact here + x = null ``` See [more examples](https://github.com/lampepfl/dotty/blob/master/tests/explicit-nulls/neg/flow-varref-in-closure.scala). @@ -441,8 +441,8 @@ We don't support: val s: String | Null = ??? val s2: String | Null = ??? if s != null && s == s2 then - // s: String inferred - // s2: String not inferred + // s: String inferred + // s2: String not inferred ``` ### UnsafeNulls diff --git a/docs/docs/reference/other-new-features/export.md b/docs/docs/reference/other-new-features/export.md index 1f7d25cbc79b..3f57cf59d713 100644 --- a/docs/docs/reference/other-new-features/export.md +++ b/docs/docs/reference/other-new-features/export.md @@ -10,22 +10,22 @@ class BitMap class InkJet class Printer: - type PrinterType - def print(bits: BitMap): Unit = ??? - def status: List[String] = ??? + type PrinterType + def print(bits: BitMap): Unit = ??? + def status: List[String] = ??? class Scanner: - def scan(): BitMap = ??? - def status: List[String] = ??? + def scan(): BitMap = ??? + def status: List[String] = ??? class Copier: - private val printUnit = new Printer { type PrinterType = InkJet } - private val scanUnit = new Scanner + private val printUnit = new Printer { type PrinterType = InkJet } + private val scanUnit = new Scanner - export scanUnit.scan - export printUnit.{status => _, *} + export scanUnit.scan + export printUnit.{status => _, *} - def status: List[String] = printUnit.status ++ scanUnit.status + def status: List[String] = printUnit.status ++ scanUnit.status ``` The two `export` clauses define the following _export aliases_ in class `Copier`: diff --git a/docs/docs/reference/other-new-features/indentation-experimental.md b/docs/docs/reference/other-new-features/indentation-experimental.md index 48bc271df67f..ed6e838fd5a4 100644 --- a/docs/docs/reference/other-new-features/indentation-experimental.md +++ b/docs/docs/reference/other-new-features/indentation-experimental.md @@ -19,31 +19,31 @@ This variant is more contentious and less stable than the rest of the significan Similar to what is done for classes and objects, a `:` that follows a function reference at the end of a line means braces can be omitted for function arguments. Example: ```scala times(10): - println("ah") - println("ha") + println("ah") + println("ha") ``` The colon can also follow an infix operator: ```scala credentials ++ : - val file = Path.userHome / ".credentials" - if file.exists - then Seq(Credentials(file)) - else Seq() + val file = Path.userHome / ".credentials" + if file.exists + then Seq(Credentials(file)) + else Seq() ``` Function calls that take multiple argument lists can also be handled this way: ```scala val firstLine = files.get(fileName).fold: - val fileNames = files.values - s"""no file named $fileName found among - |${values.mkString(\n)}""".stripMargin - : - f => - val lines = f.iterator.map(_.readLine) - lines.mkString("\n) + val fileNames = files.values + s"""no file named $fileName found among + |${values.mkString(\n)}""".stripMargin + : + f => + val lines = f.iterator.map(_.readLine) + lines.mkString("\n) ``` @@ -52,10 +52,10 @@ val firstLine = files.get(fileName).fold: Braces can also be omitted around multiple line function value arguments: ```scala val xs = elems.map x => - val y = x - 1 - y * y + val y = x - 1 + y * y xs.foldLeft (x, y) => - x + y + x + y ``` Braces can be omitted if the lambda starts with a parameter list and `=>` or `=>?` at the end of one line and it has an indented body on the following lines. diff --git a/docs/docs/reference/other-new-features/indentation.md b/docs/docs/reference/other-new-features/indentation.md index a16f0bbee510..fe008e2d8a3c 100644 --- a/docs/docs/reference/other-new-features/indentation.md +++ b/docs/docs/reference/other-new-features/indentation.md @@ -103,9 +103,9 @@ It is an error if the indentation width of the token following an `` do ```scala if x < 0 then - -x + -x else // error: `else` does not align correctly - x + x ``` Indentation tokens are only inserted in regions where newline statement separators are also inferred: @@ -144,25 +144,25 @@ With these new rules, the following constructs are all valid: ```scala trait A: - def f: Int + def f: Int class C(x: Int) extends A: - def f = x + def f = x object O: - def f = 3 + def f = 3 enum Color: - case Red, Green, Blue + case Red, Green, Blue new A: - def f = 3 + def f = 3 package p: - def a = 1 + def a = 1 package q: - def b = 2 + def b = 2 ``` In each case, the `:` at the end of line can be replaced without change of meaning by a pair of braces that enclose the following indented definition(s). @@ -202,13 +202,13 @@ Indentation can be mixed freely with braces `{...}`, as well as brackets `[...]` For instance, consider: ```scala { - val x = f(x: Int, y => - x * ( - y + 1 - ) + - (x + - x) - ) + val x = f(x: Int, y => + x * ( + y + 1 + ) + + (x + + x) + ) } ``` - Here, the indentation width of the region enclosed by the braces is 3 (i.e. the indentation width of the @@ -250,12 +250,12 @@ To solve this problem, Scala 3 offers an optional `end` marker. Example: ```scala def largeMethod(...) = - ... - if ... then ... - else - ... // a large block - end if - ... // more code + ... + if ... then ... + else + ... // a large block + end if + ... // more code end largeMethod ``` @@ -282,47 +282,47 @@ For instance, the following end markers are all legal: ```scala package p1.p2: - abstract class C(): - - def this(x: Int) = - this() - if x > 0 then - val a :: b = - x :: Nil - end val - var y = - x - end y - while y > 0 do - println(y) - y -= 1 - end while - try - x match - case 0 => println("0") - case _ => - end match - finally - println("done") - end try - end if - end this - - def f: String - end C - - object C: - given C = - new C: - def f = "!" - end f - end new - end given - end C - - extension (x: C) - def ff: String = x.f ++ x.f - end extension + abstract class C(): + + def this(x: Int) = + this() + if x > 0 then + val a :: b = + x :: Nil + end val + var y = + x + end y + while y > 0 do + println(y) + y -= 1 + end while + try + x match + case 0 => println("0") + case _ => + end match + finally + println("done") + end try + end if + end this + + def f: String + end C + + object C: + given C = + new C: + def f = "!" + end f + end new + end given + end C + + extension (x: C) + def ff: String = x.f ++ x.f + end extension end p2 ``` @@ -354,50 +354,50 @@ Here is a (somewhat meta-circular) example of code using indentation. It provide ```scala enum IndentWidth: - case Run(ch: Char, n: Int) - case Conc(l: IndentWidth, r: Run) - - def <= (that: IndentWidth): Boolean = this match - case Run(ch1, n1) => - that match - case Run(ch2, n2) => n1 <= n2 && (ch1 == ch2 || n1 == 0) - case Conc(l, r) => this <= l - case Conc(l1, r1) => - that match - case Conc(l2, r2) => l1 == l2 && r1 <= r2 - case _ => false - - def < (that: IndentWidth): Boolean = - this <= that && !(that <= this) - - override def toString: String = - this match + case Run(ch: Char, n: Int) + case Conc(l: IndentWidth, r: Run) + + def <= (that: IndentWidth): Boolean = this match + case Run(ch1, n1) => + that match + case Run(ch2, n2) => n1 <= n2 && (ch1 == ch2 || n1 == 0) + case Conc(l, r) => this <= l + case Conc(l1, r1) => + that match + case Conc(l2, r2) => l1 == l2 && r1 <= r2 + case _ => false + + def < (that: IndentWidth): Boolean = + this <= that && !(that <= this) + + override def toString: String = + this match case Run(ch, n) => - val kind = ch match - case ' ' => "space" - case '\t' => "tab" - case _ => s"'$ch'-character" - val suffix = if n == 1 then "" else "s" - s"$n $kind$suffix" + val kind = ch match + case ' ' => "space" + case '\t' => "tab" + case _ => s"'$ch'-character" + val suffix = if n == 1 then "" else "s" + s"$n $kind$suffix" case Conc(l, r) => - s"$l, $r" + s"$l, $r" object IndentWidth: - private inline val MaxCached = 40 + private inline val MaxCached = 40 - private val spaces = IArray.tabulate(MaxCached + 1)(new Run(' ', _)) - private val tabs = IArray.tabulate(MaxCached + 1)(new Run('\t', _)) + private val spaces = IArray.tabulate(MaxCached + 1)(new Run(' ', _)) + private val tabs = IArray.tabulate(MaxCached + 1)(new Run('\t', _)) - def Run(ch: Char, n: Int): Run = - if n <= MaxCached && ch == ' ' then - spaces(n) - else if n <= MaxCached && ch == '\t' then - tabs(n) - else - new Run(ch, n) - end Run + def Run(ch: Char, n: Int): Run = + if n <= MaxCached && ch == ' ' then + spaces(n) + else if n <= MaxCached && ch == '\t' then + tabs(n) + else + new Run(ch, n) + end Run - val Zero = Run(' ', 0) + val Zero = Run(' ', 0) end IndentWidth ``` @@ -423,17 +423,17 @@ This variant is more contentious and less stable than the rest of the significan ```scala times(10): - println("ah") - println("ha") + println("ah") + println("ha") ``` or ```scala xs.map: - x => - val y = x - 1 - y * y + x => + val y = x - 1 + y * y ``` The colon is usable not only for lambdas and by-name parameters, but @@ -441,10 +441,10 @@ also even for ordinary parameters: ```scala credentials ++ : - val file = Path.userHome / ".credentials" - if file.exists - then Seq(Credentials(file)) - else Seq() + val file = Path.userHome / ".credentials" + if file.exists + then Seq(Credentials(file)) + else Seq() ``` How does this syntax variant work? Colons at the end of lines are their own token, distinct from normal `:`. diff --git a/docs/docs/reference/other-new-features/matchable.md b/docs/docs/reference/other-new-features/matchable.md index dd230a916537..b846d30005e7 100644 --- a/docs/docs/reference/other-new-features/matchable.md +++ b/docs/docs/reference/other-new-features/matchable.md @@ -21,7 +21,7 @@ However, there is a potential hole due to pattern matching. Consider: ```scala val imm: IArray[Int] = ... imm match - case a: Array[Int] => a(0) = 1 + case a: Array[Int] => a(0) = 1 ``` The test will succeed at runtime since `IArray`s _are_ represented as @@ -40,7 +40,7 @@ type `T` as match selector leads to the same problem: ```scala def f[T](x: T) = x match - case a: Array[Int] => a(0) = 0 + case a: Array[Int] => a(0) = 0 f(imm) ``` @@ -76,15 +76,15 @@ Here is the hierarchy of top-level classes and traits with their defined methods ```scala abstract class Any: - def getClass - def isInstanceOf - def asInstanceOf - def == - def != - def ## - def equals - def hashCode - def toString + def getClass + def isInstanceOf + def asInstanceOf + def == + def != + def ## + def equals + def hashCode + def toString trait Matchable extends Any @@ -104,10 +104,10 @@ Matchable warning is turned on. The most common such method is the universal ```scala class C(val x: String): - override def equals(that: Any): Boolean = - that.asInstanceOf[Matchable] match - case that: C => this.x == that.x - case _ => false + override def equals(that: Any): Boolean = + that.asInstanceOf[Matchable] match + case that: C => this.x == that.x + case _ => false ``` The cast of `that` to `Matchable` serves as an indication that universal equality @@ -128,13 +128,13 @@ def Second(x: Double) = x Here, universal `equals` will return true for ```scala - Meter(10).equals(Second(10)) + Meter(10).equals(Second(10)) ``` even though this is clearly false mathematically. With [multiversal equality](../contextual/multiversal-equality.md) one can mitigate that problem somewhat by turning ```scala - Meter(10) == Second(10) + Meter(10) == Second(10) ``` into a type error. diff --git a/docs/docs/reference/other-new-features/named-typeargs-spec.md b/docs/docs/reference/other-new-features/named-typeargs-spec.md index f56f97d89100..404f96852aca 100644 --- a/docs/docs/reference/other-new-features/named-typeargs-spec.md +++ b/docs/docs/reference/other-new-features/named-typeargs-spec.md @@ -20,7 +20,7 @@ Note in particular that named arguments cannot be passed to type constructors: class C[T] val x: C[T = Int] = // error - new C[T = Int] // error + new C[T = Int] // error class E extends C[T = Int] // error ``` diff --git a/docs/docs/reference/other-new-features/opaques-details.md b/docs/docs/reference/other-new-features/opaques-details.md index ef8d6ab0492f..6f7e2221ca85 100644 --- a/docs/docs/reference/other-new-features/opaques-details.md +++ b/docs/docs/reference/other-new-features/opaques-details.md @@ -34,7 +34,7 @@ A special case arises if the opaque type alias is defined in an object. Example: ```scala object o: - opaque type T = R + opaque type T = R ``` In this case we have inside the object (also for non-opaque types) that `o.T` is equal to @@ -45,8 +45,8 @@ also known that `o.T` is equal to `R`. This means the following code type-checks ```scala object o: - opaque type T = Int - val x: Int = id(2) + opaque type T = Int + val x: Int = id(2) def id(x: o.T): o.T = x ``` @@ -89,7 +89,7 @@ opaque type A = String val x: A = "abc" object obj: - val y: A = "abc" // error: found: "abc", required: A + val y: A = "abc" // error: found: "abc", required: A // in test2.scala def z: String = x // error: found: A, required: String @@ -97,11 +97,11 @@ def z: String = x // error: found: A, required: String This behavior becomes clear if one recalls that top-level definitions are placed in their own synthetic object. For instance, the code in `test1.scala` would expand to ```scala object test1$package: - opaque type A = String - val x: A = "abc" + opaque type A = String + val x: A = "abc" object obj: - val y: A = "abc" // error: cannot assign "abc" to opaque type alias A + val y: A = "abc" // error: cannot assign "abc" to opaque type alias A ``` The opaque type alias `A` is transparent in its scope, which includes the definition of `x`, but not the definitions of `obj` and `y`. diff --git a/docs/docs/reference/other-new-features/opaques.md b/docs/docs/reference/other-new-features/opaques.md index 3d1d5acd04a1..7bfac23d77a2 100644 --- a/docs/docs/reference/other-new-features/opaques.md +++ b/docs/docs/reference/other-new-features/opaques.md @@ -8,24 +8,24 @@ Opaque types aliases provide type abstraction without any overhead. Example: ```scala object MyMath: - opaque type Logarithm = Double + opaque type Logarithm = Double - object Logarithm: + object Logarithm: - // These are the two ways to lift to the Logarithm type + // These are the two ways to lift to the Logarithm type - def apply(d: Double): Logarithm = math.log(d) + def apply(d: Double): Logarithm = math.log(d) - def safe(d: Double): Option[Logarithm] = - if d > 0.0 then Some(math.log(d)) else None + def safe(d: Double): Option[Logarithm] = + if d > 0.0 then Some(math.log(d)) else None - end Logarithm + end Logarithm - // Extension methods define opaque types' public APIs - extension (x: Logarithm) - def toDouble: Double = math.exp(x) - def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) - def * (y: Logarithm): Logarithm = x + y + // Extension methods define opaque types' public APIs + extension (x: Logarithm) + def toDouble: Double = math.exp(x) + def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) + def * (y: Logarithm): Logarithm = x + y end MyMath ``` @@ -65,24 +65,24 @@ Opaque type aliases can also come with bounds. Example: ```scala object Access: - opaque type Permissions = Int - opaque type PermissionChoice = Int - opaque type Permission <: Permissions & PermissionChoice = Int - - extension (x: Permissions) - def & (y: Permissions): Permissions = x | y - extension (x: PermissionChoice) - def | (y: PermissionChoice): PermissionChoice = x | y - extension (granted: Permissions) - def is(required: Permissions) = (granted & required) == required - extension (granted: Permissions) - def isOneOf(required: PermissionChoice) = (granted & required) != 0 - - val NoPermission: Permission = 0 - val Read: Permission = 1 - val Write: Permission = 2 - val ReadWrite: Permissions = Read | Write - val ReadOrWrite: PermissionChoice = Read | Write + opaque type Permissions = Int + opaque type PermissionChoice = Int + opaque type Permission <: Permissions & PermissionChoice = Int + + extension (x: Permissions) + def & (y: Permissions): Permissions = x | y + extension (x: PermissionChoice) + def | (y: PermissionChoice): PermissionChoice = x | y + extension (granted: Permissions) + def is(required: Permissions) = (granted & required) == required + extension (granted: Permissions) + def isOneOf(required: PermissionChoice) = (granted & required) != 0 + + val NoPermission: Permission = 0 + val Read: Permission = 1 + val Write: Permission = 2 + val ReadWrite: Permissions = Read | Write + val ReadOrWrite: PermissionChoice = Read | Write end Access ``` @@ -111,22 +111,22 @@ two types. Hence, the following usage scenario type-checks. ```scala object User: - import Access.* + import Access.* - case class Item(rights: Permissions) + case class Item(rights: Permissions) - val roItem = Item(Read) // OK, since Permission <: Permissions - val rwItem = Item(ReadWrite) - val noItem = Item(NoPermission) + val roItem = Item(Read) // OK, since Permission <: Permissions + val rwItem = Item(ReadWrite) + val noItem = Item(NoPermission) - assert(!roItem.rights.is(ReadWrite)) - assert(roItem.rights.isOneOf(ReadOrWrite)) + assert(!roItem.rights.is(ReadWrite)) + assert(roItem.rights.isOneOf(ReadOrWrite)) - assert(rwItem.rights.is(ReadWrite)) - assert(rwItem.rights.isOneOf(ReadOrWrite)) + assert(rwItem.rights.is(ReadWrite)) + assert(rwItem.rights.isOneOf(ReadOrWrite)) - assert(!noItem.rights.is(ReadWrite)) - assert(!noItem.rights.isOneOf(ReadOrWrite)) + assert(!noItem.rights.is(ReadWrite)) + assert(!noItem.rights.isOneOf(ReadOrWrite)) end User ``` @@ -141,14 +141,14 @@ For example, we can redefine the above example of Logarithms as a class. ```scala class Logarithms: - opaque type Logarithm = Double + opaque type Logarithm = Double - def apply(d: Double): Logarithm = math.log(d) + def apply(d: Double): Logarithm = math.log(d) - def safe(d: Double): Option[Logarithm] = - if d > 0.0 then Some(math.log(d)) else None + def safe(d: Double): Option[Logarithm] = + if d > 0.0 then Some(math.log(d)) else None - def mul(x: Logarithm, y: Logarithm) = x + y + def mul(x: Logarithm, y: Logarithm) = x + y ``` Opaque type members of different instances are treated as different: diff --git a/docs/docs/reference/other-new-features/open-classes.md b/docs/docs/reference/other-new-features/open-classes.md index 7164476d0ad4..8378d86b42d6 100644 --- a/docs/docs/reference/other-new-features/open-classes.md +++ b/docs/docs/reference/other-new-features/open-classes.md @@ -10,18 +10,18 @@ package p open class Writer[T]: - /** Sends to stdout, can be overridden */ - def send(x: T) = println(x) + /** Sends to stdout, can be overridden */ + def send(x: T) = println(x) - /** Sends all arguments using `send` */ - def sendAll(xs: T*) = xs.foreach(send) + /** Sends all arguments using `send` */ + def sendAll(xs: T*) = xs.foreach(send) end Writer // File EncryptedWriter.scala package p class EncryptedWriter[T: Encryptable] extends Writer[T]: - override def send(x: T) = super.send(encrypt(x)) + override def send(x: T) = super.send(encrypt(x)) ``` An open class typically comes with some documentation that describes the internal calling patterns between methods of the class as well as hooks that can be overridden. We call this the _extension contract_ of the class. It is different from the _external contract_ between a class and its users. diff --git a/docs/docs/reference/other-new-features/parameter-untupling-spec.md b/docs/docs/reference/other-new-features/parameter-untupling-spec.md index 513538c39074..75fc248bf11f 100644 --- a/docs/docs/reference/other-new-features/parameter-untupling-spec.md +++ b/docs/docs/reference/other-new-features/parameter-untupling-spec.md @@ -16,14 +16,14 @@ Previously, the best way to do this was with a pattern-matching decomposition: ```scala xs.map { - case (x, y) => x + y + case (x, y) => x + y } ``` While correct, this is inconvenient. Instead, we propose to write it the following way: ```scala xs.map { - (x, y) => x + y + (x, y) => x + y } ``` @@ -67,10 +67,10 @@ is feasible for parameter untupling with the expected type `TupleN[T1, ..., Tn] ```scala (x: TupleN[T1, ..., Tn]) => - def p1: T1 = x._1 - ... - def pn: Tn = x._n - e + def p1: T1 = x._1 + ... + def pn: Tn = x._n + e ``` with the same expected type. diff --git a/docs/docs/reference/other-new-features/parameter-untupling.md b/docs/docs/reference/other-new-features/parameter-untupling.md index 5f8f322c5126..ee116e613015 100644 --- a/docs/docs/reference/other-new-features/parameter-untupling.md +++ b/docs/docs/reference/other-new-features/parameter-untupling.md @@ -14,7 +14,7 @@ their sum. Previously, the best way to do this was with a pattern-matching decom ```scala xs map { - case (x, y) => x + y + case (x, y) => x + y } ``` @@ -23,7 +23,7 @@ suggests that the pattern match could fail. As a shorter and clearer alternative ```scala xs.map { - (x, y) => x + y + (x, y) => x + y } ``` diff --git a/docs/docs/reference/other-new-features/safe-initialization.md b/docs/docs/reference/other-new-features/safe-initialization.md index c095a1ac6214..18cfeae62b63 100644 --- a/docs/docs/reference/other-new-features/safe-initialization.md +++ b/docs/docs/reference/other-new-features/safe-initialization.md @@ -15,12 +15,12 @@ Given the following code snippet: ``` scala abstract class AbstractFile: - def name: String - val extension: String = name.substring(4) + def name: String + val extension: String = name.substring(4) class RemoteFile(url: String) extends AbstractFile: - val localFile: String = s"${url.##}.tmp" // error: usage of `localFile` before it's initialized - def name: String = localFile + val localFile: String = s"${url.##}.tmp" // error: usage of `localFile` before it's initialized + def name: String = localFile ``` The checker will report: @@ -40,10 +40,10 @@ Given the code below: ``` scala object Trees: - class ValDef { counter += 1 } - class EmptyValDef extends ValDef - val theEmptyValDef = new EmptyValDef - private var counter = 0 // error + class ValDef { counter += 1 } + class EmptyValDef extends ValDef + val theEmptyValDef = new EmptyValDef + private var counter = 0 // error ``` The checker will report: @@ -64,13 +64,13 @@ Given the code below: ``` scala abstract class Parent: - val f: () => String = () => this.message - def message: String + val f: () => String = () => this.message + def message: String class Child extends Parent: - val a = f() - val b = "hello" // error - def message: String = b + val a = f() + val b = "hello" // error + def message: String = b ``` The checker reports: @@ -122,12 +122,12 @@ following example shows: ``` scala class MyException(val b: B) extends Exception("") class A: - val b = try { new B } catch { case myEx: MyException => myEx.b } - println(b.a) + val b = try { new B } catch { case myEx: MyException => myEx.b } + println(b.a) class B: - throw new MyException(this) - val a: Int = 1 + throw new MyException(this) + val a: Int = 1 ``` In the code above, the control effect teleport the uninitialized value @@ -141,12 +141,12 @@ object under initialization. As an example, the following code will be rejected: ``` scala trait Reporter: - def report(msg: String): Unit + def report(msg: String): Unit class FileReporter(ctx: Context) extends Reporter: - ctx.typer.reporter = this // ctx now reaches an uninitialized object - val file: File = new File("report.txt") - def report(msg: String) = file.write(msg) + ctx.typer.reporter = this // ctx now reaches an uninitialized object + val file: File = new File("report.txt") + def report(msg: String) = file.write(msg) ``` In the code above, suppose `ctx` points to a transitively initialized @@ -213,12 +213,12 @@ two classes are defined in the same project: ```Scala class Base: - private val map: mutable.Map[Int, String] = mutable.Map.empty - def enter(k: Int, v: String) = map(k) = v + private val map: mutable.Map[Int, String] = mutable.Map.empty + def enter(k: Int, v: String) = map(k) = v class Child extends Base: - enter(1, "one") - enter(2, "two") + enter(1, "one") + enter(2, "two") ``` However, when the class `Base` and `Child` are defined in two different diff --git a/docs/docs/reference/other-new-features/targetName.md b/docs/docs/reference/other-new-features/targetName.md index 572d7a5e2146..d5875f7776a5 100644 --- a/docs/docs/reference/other-new-features/targetName.md +++ b/docs/docs/reference/other-new-features/targetName.md @@ -9,9 +9,9 @@ A `@targetName` annotation on a definition defines an alternate name for the imp import scala.annotation.targetName object VecOps: - extension [T](xs: Vec[T]) - @targetName("append") - def ++= [T] (ys: Vec[T]): Vec[T] = ... + extension [T](xs: Vec[T]) + @targetName("append") + def ++= [T] (ys: Vec[T]): Vec[T] = ... ``` Here, the `++=` operation is implemented (in Byte code or native code) under the name `append`. The implementation name affects the code that is generated, and is the name under which code from other languages can call the method. For instance, `++=` could be invoked from Java like this: @@ -71,9 +71,9 @@ between two definitions that have otherwise the same names and types. So the fol ```scala import annotation.targetName class A: - def f(): Int = 1 + def f(): Int = 1 class B extends A: - @targetName("g") def f(): Int = 2 + @targetName("g") def f(): Int = 2 ``` The compiler reports here: @@ -99,9 +99,9 @@ be present in the original code. So the following example would also be in error ```scala import annotation.targetName class A: - def f(): Int = 1 + def f(): Int = 1 class B extends A: - @targetName("f") def g(): Int = 2 + @targetName("f") def g(): Int = 2 ``` Here, the original methods `g` and `f` do not override each other since they have diff --git a/docs/docs/reference/other-new-features/trait-parameters.md b/docs/docs/reference/other-new-features/trait-parameters.md index 5ccde10b05c1..f34a48ff856d 100644 --- a/docs/docs/reference/other-new-features/trait-parameters.md +++ b/docs/docs/reference/other-new-features/trait-parameters.md @@ -7,10 +7,10 @@ Scala 3 allows traits to have parameters, just like classes have parameters. ```scala trait Greeting(val name: String): - def msg = s"How are you, $name" + def msg = s"How are you, $name" class C extends Greeting("Bob"): - println(msg) + println(msg) ``` Arguments to a trait are evaluated immediately before the trait is initialized. @@ -36,7 +36,7 @@ Here's a trait extending the parameterized trait `Greeting`. ```scala trait FormalGreeting extends Greeting: - override def msg = s"How do you do, $name" + override def msg = s"How do you do, $name" ``` As is required, no arguments are passed to `Greeting`. However, this poses an issue when defining a class that extends `FormalGreeting`: @@ -65,10 +65,10 @@ case class ImpliedName(name: String): override def toString = name trait ImpliedGreeting(using val iname: ImpliedName): - def msg = s"How are you, $iname" + def msg = s"How are you, $iname" trait ImpliedFormalGreeting extends ImpliedGreeting: - override def msg = s"How do you do, $iname" + override def msg = s"How do you do, $iname" class F(using iname: ImpliedName) extends ImpliedFormalGreeting ``` @@ -76,9 +76,9 @@ class F(using iname: ImpliedName) extends ImpliedFormalGreeting The definition of `F` in the last line is implicitly expanded to ```scala class F(using iname: ImpliedName) extends - Object, - ImpliedGreeting(using iname), - ImpliedFormalGreeting(using iname) + Object, + ImpliedGreeting(using iname), + ImpliedFormalGreeting(using iname) ``` Note the inserted reference to the super trait `ImpliedGreeting`, which was not mentioned explicitly. diff --git a/docs/docs/reference/other-new-features/type-test.md b/docs/docs/reference/other-new-features/type-test.md index 8c1661fd07f2..04b0825003c8 100644 --- a/docs/docs/reference/other-new-features/type-test.md +++ b/docs/docs/reference/other-new-features/type-test.md @@ -10,17 +10,17 @@ The first case is an explicit type test using the ascription pattern notation. ```scala (x: X) match - case y: Y => + case y: Y => ``` The second case is when an extractor takes an argument that is not a subtype of the scrutinee type. ```scala (x: X) match - case y @ Y(n) => + case y @ Y(n) => object Y: - def unapply(x: Y): Some[Int] = ... + def unapply(x: Y): Some[Int] = ... ``` In both cases, a class test will be performed at runtime. @@ -32,7 +32,7 @@ A `TypeTest` can be provided to make this test possible. package scala.reflect trait TypeTest[-S, T]: - def unapply(s: S): Option[s.type & T] + def unapply(s: S): Option[s.type & T] ``` It provides an extractor that returns its argument typed as a `T` if the argument is a `T`. @@ -40,9 +40,9 @@ It can be used to encode a type test. ```scala def f[X, Y](x: X)(using tt: TypeTest[X, Y]): Option[Y] = x match - case tt(x @ Y(1)) => Some(x) - case tt(x) => Some(x) - case _ => None + case tt(x @ Y(1)) => Some(x) + case tt(x) => Some(x) + case _ => None ``` To avoid the syntactic overhead the compiler will look for a type test automatically if it detects that the type test is on abstract types. @@ -51,19 +51,19 @@ The previous code is equivalent to ```scala def f[X, Y](x: X)(using TypeTest[X, Y]): Option[Y] = x match - case x @ Y(1) => Some(x) - case x: Y => Some(x) - case _ => None + case x @ Y(1) => Some(x) + case x: Y => Some(x) + case _ => None ``` We could create a type test at call site where the type test can be performed with runtime class tests directly as follows ```scala val tt: TypeTest[Any, String] = - new TypeTest[Any, String]: - def unapply(s: Any): Option[s.type & String] = s match - case s: String => Some(s) - case _ => None + new TypeTest[Any, String]: + def unapply(s: Any): Option[s.type & String] = s match + case s: String => Some(s) + case _ => None f[AnyRef, String]("acb")(using tt) ``` @@ -72,9 +72,9 @@ The compiler will synthesize a new instance of a type test if none is found in s ```scala new TypeTest[A, B]: - def unapply(s: A): Option[s.type & B] = s match - case s: B => Some(s) - case _ => None + def unapply(s: A): Option[s.type & B] = s match + case s: B => Some(s) + case _ => None ``` If the type tests cannot be done there will be an unchecked warning that will be raised on the `case s: B =>` test. @@ -92,9 +92,9 @@ This alias can be used as ```scala def f[T: Typeable]: Boolean = - "abc" match - case x: T => true - case _ => false + "abc" match + case x: T => true + case _ => false f[String] // true f[Int] // false @@ -116,65 +116,65 @@ Given the following abstract definition of Peano numbers that provides two given import scala.reflect.* trait Peano: - type Nat - type Zero <: Nat - type Succ <: Nat + type Nat + type Zero <: Nat + type Succ <: Nat - def safeDiv(m: Nat, n: Succ): (Nat, Nat) + def safeDiv(m: Nat, n: Succ): (Nat, Nat) - val Zero: Zero + val Zero: Zero - val Succ: SuccExtractor - trait SuccExtractor: - def apply(nat: Nat): Succ - def unapply(succ: Succ): Some[Nat] + val Succ: SuccExtractor + trait SuccExtractor: + def apply(nat: Nat): Succ + def unapply(succ: Succ): Some[Nat] - given typeTestOfZero: TypeTest[Nat, Zero] - given typeTestOfSucc: TypeTest[Nat, Succ] + given typeTestOfZero: TypeTest[Nat, Zero] + given typeTestOfSucc: TypeTest[Nat, Succ] ``` together with an implementation of Peano numbers based on type `Int` ```scala object PeanoInt extends Peano: - type Nat = Int - type Zero = Int - type Succ = Int + type Nat = Int + type Zero = Int + type Succ = Int - def safeDiv(m: Nat, n: Succ): (Nat, Nat) = (m / n, m % n) + def safeDiv(m: Nat, n: Succ): (Nat, Nat) = (m / n, m % n) - val Zero: Zero = 0 + val Zero: Zero = 0 - val Succ: SuccExtractor = new: - def apply(nat: Nat): Succ = nat + 1 - def unapply(succ: Succ) = Some(succ - 1) + val Succ: SuccExtractor = new: + def apply(nat: Nat): Succ = nat + 1 + def unapply(succ: Succ) = Some(succ - 1) - def typeTestOfZero: TypeTest[Nat, Zero] = new: - def unapply(x: Nat): Option[x.type & Zero] = - if x == 0 then Some(x) else None + def typeTestOfZero: TypeTest[Nat, Zero] = new: + def unapply(x: Nat): Option[x.type & Zero] = + if x == 0 then Some(x) else None - def typeTestOfSucc: TypeTest[Nat, Succ] = new: - def unapply(x: Nat): Option[x.type & Succ] = - if x > 0 then Some(x) else None + def typeTestOfSucc: TypeTest[Nat, Succ] = new: + def unapply(x: Nat): Option[x.type & Succ] = + if x > 0 then Some(x) else None ``` it is possible to write the following program ```scala @main def test = - import PeanoInt.* + import PeanoInt.* - def divOpt(m: Nat, n: Nat): Option[(Nat, Nat)] = - n match - case Zero => None - case s @ Succ(_) => Some(safeDiv(m, s)) + def divOpt(m: Nat, n: Nat): Option[(Nat, Nat)] = + n match + case Zero => None + case s @ Succ(_) => Some(safeDiv(m, s)) - val two = Succ(Succ(Zero)) - val five = Succ(Succ(Succ(two))) + val two = Succ(Succ(Zero)) + val five = Succ(Succ(Succ(two))) - println(divOpt(five, two)) // prints "Some((2,1))" - println(divOpt(two, five)) // prints "Some((0,2))" - println(divOpt(two, Zero)) // prints "None" + println(divOpt(five, two)) // prints "Some((2,1))" + println(divOpt(two, five)) // prints "Some((0,2))" + println(divOpt(two, Zero)) // prints "None" ``` Note that without the `TypeTest[Nat, Succ]` the pattern `Succ.unapply(nat: Succ)` would be unchecked.