diff --git a/code-snippets/build.sbt b/code-snippets/build.sbt index 4246cc3b9..868e2ac1e 100644 --- a/code-snippets/build.sbt +++ b/code-snippets/build.sbt @@ -3,6 +3,7 @@ Global / onChangedBuildSource := ReloadOnSourceChanges lazy val `scala-3-snippets` = project .in(file(".")) .settings(ThisBuild / scalaVersion := "3.3.0") + .settings(ThisBuild / scalacOptions ++= Seq("-source", "3.3-migration")) .settings( name := "dotty-simple", version := "0.1.0", @@ -13,7 +14,8 @@ lazy val `scala-3-snippets` = project `intersection-and-union-types`, `enumerations`, `export-clause`, - `top-level-definitions`) + `top-level-definitions`, + `opaque-type-aliases`) lazy val `new-control-structure-syntax` = project.in(file("new-control-structure-syntax")) @@ -24,6 +26,8 @@ lazy val `enumerations` = project.in(file("enumerations")) lazy val `export-clause` = project.in(file("export-clause")) lazy val `intersection-and-union-types` = - project.in(file("intersection-and-union-types")).settings(scalacOptions ++= Seq("-source", "future-migration")) + project.in(file("intersection-and-union-types")) lazy val `top-level-definitions` = project.in(file("top-level-definitions")) + +lazy val `opaque-type-aliases` = project.in(file("opaque-type-aliases")) diff --git a/code-snippets/new-control-structure-syntax/src/main/scala/org/lunatech/dotty/NewControlStructures.scala b/code-snippets/new-control-structure-syntax/src/main/scala/org/lunatech/dotty/NewControlStructures.scala index 63fa1b4f3..5a3f63144 100644 --- a/code-snippets/new-control-structure-syntax/src/main/scala/org/lunatech/dotty/NewControlStructures.scala +++ b/code-snippets/new-control-structure-syntax/src/main/scala/org/lunatech/dotty/NewControlStructures.scala @@ -6,8 +6,6 @@ object NewControlStructures { val xs = Seq(1, 2, 3) val ys = Seq(3, 4, 5) - def body: Int = 6 - if x < 0 then "negative" else if x == 0 then "zero" else "positive" @@ -26,6 +24,12 @@ object NewControlStructures { y <- ys do println(x + y) - // try body - // catch case ex: IOException => handle + def body: Int = + throw new IllegalArgumentException("Bad argument") + 5 + + def handle = ??? + val result = + try body + catch case ex: IllegalArgumentException => handle } diff --git a/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/caseclasses/CaseClasses.scala b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/caseclasses/CaseClasses.scala new file mode 100644 index 000000000..6c46cef4d --- /dev/null +++ b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/caseclasses/CaseClasses.scala @@ -0,0 +1,11 @@ +package opaquetypelaliases.caseclasses + +case class Kilometres(value: Double) + +class Rocket(distanceTravelled: Kilometres): + def advance(distanceToAdvance: Kilometres): Rocket = new Rocket( + Kilometres(distanceTravelled.value + distanceToAdvance.value)) + +val rocket = Rocket(Kilometres(1000)) + +val r1 = rocket.advance(Kilometres(5000)) diff --git a/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/opaquetypealias/OpaqueTypeAliases.scala b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/opaquetypealias/OpaqueTypeAliases.scala new file mode 100644 index 000000000..4b878dfcf --- /dev/null +++ b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/opaquetypealias/OpaqueTypeAliases.scala @@ -0,0 +1,21 @@ +package opaquetypelaliases.opaquetypealias + +object OpaqueTypeAliasesDefinitions: + + opaque type Kilometres = Double + object Kilometres: + def apply(d: Double): Kilometres = d + + opaque type Miles = Double + object Miles: + def apply(d: Double): Miles = d + + extension (a: Kilometres) + @scala.annotation.targetName("plusKm") + def +(b: Kilometres): Kilometres = a + b + def toMiles: Miles = a / 1.6 + + extension (a: Miles) + @scala.annotation.targetName("plusMiles") + def +(b: Miles): Miles = a + b + def toKm: Kilometres = a * 1.6 diff --git a/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/opaquetypealias/UsingTheAliases.scala b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/opaquetypealias/UsingTheAliases.scala new file mode 100644 index 000000000..0eba8c072 --- /dev/null +++ b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/opaquetypealias/UsingTheAliases.scala @@ -0,0 +1,26 @@ +package opaquetypelaliases.opaquetypealias + +object UsingTheAliases { + import OpaqueTypeAliasesDefinitions.* + + class Rocket(distanceTravelled: Kilometres): + def advance(distanceToAdvance: Kilometres): Rocket = new Rocket(distanceTravelled + distanceToAdvance) + + type Conversion[A] = A => Kilometres + class Booster(): + def advanceRocket[A: Conversion](rocket: Rocket, distanceToAdvance: A): Rocket = { + val distanceInKm = summon[Conversion[A]](distanceToAdvance) + rocket.advance(distanceInKm) + } + + val rocket1 = new Rocket(Kilometres(0)) + val rocket2 = new Rocket(Kilometres(0)) + val booster = new Booster() + + given Conversion[Kilometres] = identity + given Conversion[Miles] = _.toKm + + val r1 = booster.advanceRocket(rocket1, Kilometres(100)) // No allocation of Kilometres object + val r2 = booster.advanceRocket(rocket2, Miles(200)) // No allocation of Miles object + +} diff --git a/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/parametricpolymorphism/ParametricPolymorphism.scala b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/parametricpolymorphism/ParametricPolymorphism.scala new file mode 100644 index 000000000..493881edf --- /dev/null +++ b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/parametricpolymorphism/ParametricPolymorphism.scala @@ -0,0 +1,25 @@ +package opaquetypelaliases.parametricpolymorphism + +case class Kilometres(value: Double) extends AnyVal +case class Miles(value: Double) extends AnyVal + +class Rocket(distanceTravelled: Kilometres): + def advance(distanceToAdvance: Kilometres): Rocket = new Rocket( + Kilometres(distanceTravelled.value + distanceToAdvance.value)) + +type Conversion[A] = A => Kilometres +class Booster(): + def advanceRocket[A: Conversion](rocket: Rocket, distanceToAdvance: A): Rocket = { + val distanceInKm = summon[Conversion[A]](distanceToAdvance) + rocket.advance(distanceInKm) + } + +val rocket1 = new Rocket(Kilometres(0)) +val rocket2 = new Rocket(Kilometres(0)) +val booster = new Booster() + +given Conversion[Kilometres] = identity +given Conversion[Miles] = miles => Kilometres(miles.value * 1.6) + +val r1 = booster.advanceRocket(rocket1, Kilometres(100)) // Allocation of Kilometres object +val r2 = booster.advanceRocket(rocket2, Miles(200)) diff --git a/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/subtyping/Subtyping.scala b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/subtyping/Subtyping.scala new file mode 100644 index 000000000..842c41387 --- /dev/null +++ b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/subtyping/Subtyping.scala @@ -0,0 +1,25 @@ +package opaquetypelaliases.subtyping + +sealed trait Distance extends Any +case class Kilometres(value: Double) extends AnyVal with Distance +case class Miles(value: Double) extends AnyVal with Distance + +class Rocket(distanceTravelled: Kilometres): + def advance(distanceToAdvance: Kilometres): Rocket = new Rocket( + Kilometres(distanceTravelled.value + distanceToAdvance.value)) + +class Booster(): + def advanceRocket(rocket: Rocket, distanceToAdvance: Distance): Rocket = { + val distanceInKm = distanceToAdvance match { + case miles: Miles => Kilometres(miles.value * 1.6) + case km: Kilometres => km + } + rocket.advance(distanceInKm) + } + +val rocket1 = new Rocket(Kilometres(0)) +val rocket2 = new Rocket(Kilometres(0)) +val booster = new Booster() + +val r1 = booster.advanceRocket(rocket1, Kilometres(100)) // Allocation of Kilometres object +val r2 = booster.advanceRocket(rocket2, Miles(200)) // Allocation of Miles object diff --git a/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/valueclasses/ValueClasses.scala b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/valueclasses/ValueClasses.scala new file mode 100644 index 000000000..bc16e317b --- /dev/null +++ b/code-snippets/opaque-type-aliases/src/main/scala/opaquetypealiases/valueclasses/ValueClasses.scala @@ -0,0 +1,11 @@ +package opaquetypelaliases.valueclasses + +case class Kilometres(value: Double) extends AnyVal + +class Rocket(distanceTravelled: Kilometres): + def advance(distanceToAdvance: Kilometres): Rocket = new Rocket( + Kilometres(distanceTravelled.value + distanceToAdvance.value)) + +val rocket1 = new Rocket(Kilometres(0)) + +val rocket2 = rocket1.advance(Kilometres(12000)) diff --git a/code-snippets/src/main/scala/org/lunatech/dotty/toplevel/TemperatureConverter.scala b/code-snippets/src/main/scala/org/lunatech/dotty/toplevel/TemperatureConverter.scala deleted file mode 100644 index 9106137fd..000000000 --- a/code-snippets/src/main/scala/org/lunatech/dotty/toplevel/TemperatureConverter.scala +++ /dev/null @@ -1,11 +0,0 @@ -package org.lunatech.dotty.toplevel - -object TemperatureConverter extends App { - - val bodyTempCelcius = Temperature(37, Celsius) - - val bodyTempFaren = convertToFarenheit(bodyTempCelcius) - - println(bodyTempCelcius) - println(bodyTempFaren) -} diff --git a/code-snippets/src/main/scala/org/lunatech/dotty/toplevel/TemperatureOps.scala b/code-snippets/src/main/scala/org/lunatech/dotty/toplevel/TemperatureOps.scala deleted file mode 100644 index f333ad2c9..000000000 --- a/code-snippets/src/main/scala/org/lunatech/dotty/toplevel/TemperatureOps.scala +++ /dev/null @@ -1,26 +0,0 @@ -package org.lunatech.dotty.toplevel - -// toplevel definitions accessible in the entire package - -sealed trait TemperatureScale { - def value: String -} -object Celsius extends TemperatureScale { - def value: String = "Celcuis" -} -object Farenheit extends TemperatureScale { - def value: String = "Farenheit" -} - -case class Temperature(value: Double, scale: TemperatureScale) { - override def toString: String = s"$value ${scale.value}" -} - -// A private toplevel definition is always visible from everywhere in the enclosing package. -private def convertToFarenheit(temperature: Temperature): Temperature = { - Temperature((temperature.value * 9 / 5) + 32, Farenheit) -} - -def convertToCelcius(temperature: Temperature): Temperature = { - Temperature((temperature.value - 32) * 5 / 9, Celsius) -} diff --git a/slides/index.html b/slides/index.html index 788ad9ef0..531cca424 100644 --- a/slides/index.html +++ b/slides/index.html @@ -4,7 +4,7 @@ -