From 50b341efe5e30ded9b65edf72a7a5de2d2f20e30 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 16:14:24 -0800 Subject: [PATCH 01/59] - --- project/build.properties | 2 +- src/main/scala/IntersectionTypes.scala | 2 +- src/main/scala/MultiversalEquality.scala | 18 +++++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/project/build.properties b/project/build.properties index c0bab04..6adcdc7 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.8 +sbt.version=1.3.3 diff --git a/src/main/scala/IntersectionTypes.scala b/src/main/scala/IntersectionTypes.scala index 9ebeed4..9f7d4e2 100644 --- a/src/main/scala/IntersectionTypes.scala +++ b/src/main/scala/IntersectionTypes.scala @@ -21,7 +21,7 @@ object IntersectionTypes { } def test: Unit = { - + // Seems like these parameters should be of type P: def euclideanDistance(p1: X & Y, p2: X & Y) = { Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) } diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index 5152bd7..0846b1b 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -4,22 +4,23 @@ import scala.language.strictEquality * Multiversal Equality: https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html * scala.Eq definition: https://github.com/lampepfl/dotty/blob/master/library/src/scala/Eql.scala */ -object MultiversalEquality { +object MultiversalEquality extends App { - def test: Unit = { + def test(): Unit = { // Values of types Int and String cannot be compared with == or !=, // unless we add the derived delegate instance like: given Eql[Int, String] = Eql.derived - println(3 == "3") + println("3 == \"3\": " + (3 == "3")) // By default, all numbers are comparable, because of; // implicit def eqlNumber: Eql[Number, Number] = derived - println(3 == 5.1) + println("3 == 5.1: " + (3 == 5.1)) // By default, all Sequences are comparable, because of; // implicit def eqlSeq[T, U](implicit eq: Eql[T, U]): Eql[GenSeq[T], GenSeq[U]] = derived - println(List(1, 2) == Vector(1, 2)) + // This fails, why? + println("List(1, 2) == Vector(1, 2)): " + List(1, 2) == Vector(1, 2)) class A(a: Int) class B(b: Int) @@ -27,12 +28,15 @@ object MultiversalEquality { val a = new A(4) val b = new B(4) + // Two arrays in Scala 2 do not compare equal so why should this work? + println("Array(1, 2) == Array(1, 2): " + Array(1, 2) == Array(1, 2)) + // scala.language.strictEquality is enabled, therefore we need some extra delegate instances // to compare instances of A and B. given Eql[A, B] = Eql.derived given Eql[B, A] = Eql.derived - println(a != b) - println(b == a) + println("a != b: " + (a != b)) + println("b == a: " + (b == a)) } } From 00f50150d3d8eb59d5547d1c883f0b233f3fccff Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 16:28:06 -0800 Subject: [PATCH 02/59] - --- src/main/scala/MultiversalEquality.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index 0846b1b..73bf5b7 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -4,7 +4,7 @@ import scala.language.strictEquality * Multiversal Equality: https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html * scala.Eq definition: https://github.com/lampepfl/dotty/blob/master/library/src/scala/Eql.scala */ -object MultiversalEquality extends App { + object MultiversalEquality extends App { def test(): Unit = { From 6cf73f0c8277c88fa52377c6562b7c395d5b71ad Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 16:29:08 -0800 Subject: [PATCH 03/59] - --- src/main/scala/MultiversalEquality.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index 73bf5b7..7a1f2c9 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -6,7 +6,7 @@ import scala.language.strictEquality */ object MultiversalEquality extends App { - def test(): Unit = { + def test: Unit = { // Values of types Int and String cannot be compared with == or !=, // unless we add the derived delegate instance like: From 08c5ddf442c2f4886563df135d4cf5e85ef78632 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 16:39:25 -0800 Subject: [PATCH 04/59] - --- src/main/scala/MultiversalEquality.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index 7a1f2c9..e73b37e 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -20,7 +20,7 @@ import scala.language.strictEquality // By default, all Sequences are comparable, because of; // implicit def eqlSeq[T, U](implicit eq: Eql[T, U]): Eql[GenSeq[T], GenSeq[U]] = derived // This fails, why? - println("List(1, 2) == Vector(1, 2)): " + List(1, 2) == Vector(1, 2)) + println("List(1, 2) == Vector(1, 2)): " + (List(1, 2) == Vector(1, 2))) class A(a: Int) class B(b: Int) @@ -29,7 +29,7 @@ import scala.language.strictEquality val b = new B(4) // Two arrays in Scala 2 do not compare equal so why should this work? - println("Array(1, 2) == Array(1, 2): " + Array(1, 2) == Array(1, 2)) + //println("Array(1, 2) == Array(1, 2): " + (Array(1, 2) == Array(1, 2))) // scala.language.strictEquality is enabled, therefore we need some extra delegate instances // to compare instances of A and B. From 5740b2ecf5d437922d0110645e778268b4086a35 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 17:00:41 -0800 Subject: [PATCH 05/59] - --- src/main/scala/AutoParamTupling.scala | 20 ++++++-------------- src/main/scala/ContextQueries.scala | 7 ++----- src/main/scala/Conversion.scala | 6 +----- src/main/scala/EnumTypes.scala | 12 ++++++------ src/main/scala/ImpliedInstances.scala | 23 +++++++++++------------ src/main/scala/IntersectionTypes.scala | 6 ++---- src/main/scala/Main.scala | 16 ---------------- src/main/scala/MultiversalEquality.scala | 5 ++--- src/main/scala/NamedTypeArguments.scala | 9 ++------- src/main/scala/PatternMatching.scala | 13 ++----------- src/main/scala/StructuralTypes.scala | 6 ++---- src/main/scala/TraitParams.scala | 3 +-- src/main/scala/TypeLambdas.scala | 5 +---- src/main/scala/UnionTypes.scala | 5 +---- 14 files changed, 39 insertions(+), 97 deletions(-) diff --git a/src/main/scala/AutoParamTupling.scala b/src/main/scala/AutoParamTupling.scala index b72bab8..c7a1e76 100644 --- a/src/main/scala/AutoParamTupling.scala +++ b/src/main/scala/AutoParamTupling.scala @@ -1,24 +1,16 @@ - /** * Automatic Tupling of Function Params: https://dotty.epfl.ch/docs/reference/other-new-features/auto-parameter-tupling.html */ -object AutoParamTupling { - +object AutoParamTupling extends App { def test: Unit = { - - /** - * In order to get thread safety, you need to put @volatile before lazy vals. - * https://dotty.epfl.ch/docs/reference/changed-features/lazy-vals.html - */ + /** In order to get thread safety, you need to put @volatile before lazy vals. + * https://dotty.epfl.ch/docs/reference/changed-features/lazy-vals.html */ @volatile lazy val xs: List[String] = List("d", "o", "t", "t", "y") - /** - * Current behaviour in Scala 2.12.2 : + /** Current behaviour in Scala 2.12.2 : * error: missing parameter type * Note: The expected type requires a one-argument function accepting a 2-Tuple. - * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` - */ + * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` */ xs.zipWithIndex.map((s, i) => println(s"$i: $s")) - } -} \ No newline at end of file +} diff --git a/src/main/scala/ContextQueries.scala b/src/main/scala/ContextQueries.scala index 52873b0..68d2e61 100644 --- a/src/main/scala/ContextQueries.scala +++ b/src/main/scala/ContextQueries.scala @@ -7,8 +7,7 @@ import scala.util.Try * - http://dotty.epfl.ch/docs/reference/contextual/query-types.html, * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ -object ContextQueries /* Formerly known as Implicit Function Types */ { - +object ContextQueries extends App /* Formerly known as Implicit Function Types */ { object context { // type alias Contextual type Contextual[T] = (given ExecutionContext) => T @@ -20,7 +19,6 @@ object ContextQueries /* Formerly known as Implicit Function Types */ { } object parse { - type Parseable[T] = (given ImpliedInstances.StringParser[T]) => Try[T] def sumStrings(x: String, y: String): Parseable[Int] = { @@ -36,13 +34,12 @@ object ContextQueries /* Formerly known as Implicit Function Types */ { } def test: Unit = { - import ExecutionContext.Implicits.global + context.asyncSum(3, 4).foreach(println) context.asyncMult(3, 4).foreach(println) println(parse.sumStrings("3", "4")) println(parse.sumStrings("3", "a")) } - } diff --git a/src/main/scala/Conversion.scala b/src/main/scala/Conversion.scala index 06b013e..ae6b3ee 100644 --- a/src/main/scala/Conversion.scala +++ b/src/main/scala/Conversion.scala @@ -3,8 +3,7 @@ import scala.language.implicitConversions /** * Conversions: http://dotty.epfl.ch/docs/reference/contextual/conversions.html */ -object Conversion { - +object Conversion extends App { case class IntWrapper(a: Int) extends AnyVal case class DoubleWrapper(b: Double) extends AnyVal @@ -31,7 +30,4 @@ object Conversion { println(useConversion) println(convert(new IntWrapper(42))) } - - - } diff --git a/src/main/scala/EnumTypes.scala b/src/main/scala/EnumTypes.scala index 7996626..d3a4eef 100644 --- a/src/main/scala/EnumTypes.scala +++ b/src/main/scala/EnumTypes.scala @@ -1,8 +1,7 @@ /** * Enum Types: http://dotty.epfl.ch/docs/reference/enums/adts.html */ -object EnumTypes { - +object EnumTypes extends App { enum ListEnum[+A] { case Cons(h: A, t: ListEnum[A]) case Empty @@ -10,7 +9,9 @@ object EnumTypes { 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) @@ -24,19 +25,18 @@ object EnumTypes { } def test: Unit = { - val emptyList = ListEnum.Empty val list = ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) println(emptyList) - println(s"${list}\n") + println(s"$list\n") - def calculateEarthWeightOnPlanets(earthWeight: Double) = { + def calculateEarthWeightOnPlanets(earthWeight: Double): Unit = { val mass = earthWeight/Planet.Earth.surfaceGravity for (p <- Planet.values) println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + () } calculateEarthWeightOnPlanets(80) } - } diff --git a/src/main/scala/ImpliedInstances.scala b/src/main/scala/ImpliedInstances.scala index e4f0433..5087892 100644 --- a/src/main/scala/ImpliedInstances.scala +++ b/src/main/scala/ImpliedInstances.scala @@ -4,36 +4,35 @@ import scala.util.{Success, Try} * Implied Instances: * - https://dotty.epfl.ch/docs/reference/contextual/instance-defs.html */ -object ImpliedInstances { - +object ImpliedInstances extends App { sealed trait StringParser[A] { def parse(s: String): Try[A] } object StringParser { - def apply[A](given parser: StringParser[A]): StringParser[A] = parser - private def baseParser[A](f: String ⇒ Try[A]): StringParser[A] = new StringParser[A] { - override def parse(s: String): Try[A] = f(s) - } + private def baseParser[A](f: String ⇒ Try[A]): StringParser[A] = + new StringParser[A] { + override def parse(s: String): Try[A] = f(s) + } given stringParser: StringParser[String] = baseParser(Success(_)) given intParser: StringParser[Int] = baseParser(s ⇒ Try(s.toInt)) - given optionParser[A](given parser: => StringParser[A]): StringParser[Option[A]] = new StringParser[Option[A]] { - override def parse(s: String): Try[Option[A]] = s match { - case "" ⇒ Success(None) // implicit parser not used. - case str ⇒ parser.parse(str).map(x ⇒ Some(x)) // implicit parser is evaluated at here + given optionParser[A](given parser: => StringParser[A]): StringParser[Option[A]] = + new StringParser[Option[A]] { + override def parse(s: String): Try[Option[A]] = s match { + case "" ⇒ Success(None) // implicit parser not used. + case str ⇒ parser.parse(str).map(x ⇒ Some(x)) // implicit parser is evaluated at here + } } - } } def test: Unit = { println(implicitly[StringParser[Option[Int]]].parse("21")) println(implicitly[StringParser[Option[Int]]].parse("")) println(implicitly[StringParser[Option[Int]]].parse("21a")) - println(implicitly[StringParser[Option[Int]]](StringParser.optionParser[Int]).parse("42")) } } diff --git a/src/main/scala/IntersectionTypes.scala b/src/main/scala/IntersectionTypes.scala index 9f7d4e2..cb4e200 100644 --- a/src/main/scala/IntersectionTypes.scala +++ b/src/main/scala/IntersectionTypes.scala @@ -2,7 +2,6 @@ * Intersection Types: https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html */ object IntersectionTypes { - sealed trait X { def x: Double def tpe: X @@ -13,6 +12,7 @@ object IntersectionTypes { def tpe: Y } + // The compiler treats P and PP as equivalent and interchangeable types type P = Y & X type PP = X & Y @@ -21,14 +21,12 @@ object IntersectionTypes { } def test: Unit = { - // Seems like these parameters should be of type P: - def euclideanDistance(p1: X & Y, p2: X & Y) = { + def euclideanDistance(p1: P, p2: P) = { Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) } val p1: P = Point(3, 4) val p2: PP = Point(6, 8) println(euclideanDistance(p1, p2)) - } } diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 18aed26..f3ba2a3 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,34 +1,19 @@ object Main { - def main(args: Array[String]): Unit = { - runExample("Trait Params")(TraitParams.test) - runExample("Enum Types")(EnumTypes.test) - runExample("Context Queries")(ContextQueries.test) - runExample("Implied Instances")(ImpliedInstances.test) - runExample("Conversion")(Conversion.test) - runExample("Union Types")(UnionTypes.test) - runExample("Intersection Types")(IntersectionTypes.test) - runExample("Type Lambda")(TypeLambdas.test) - runExample("Multiversal Equality")(MultiversalEquality.test) - runExample("Named Type Arguments")(NamedTypeArguments.test) - runExample("Auto Param Tupling")(AutoParamTupling.test) - runExample("Structural Types")(StructuralTypes.test) - runExample("Pattern Matching")(PatternMatching.test) - } private def runExample(name: String)(f: => Unit) = { @@ -36,5 +21,4 @@ object Main { f println() } - } diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index e73b37e..879838b 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -7,7 +7,6 @@ import scala.language.strictEquality object MultiversalEquality extends App { def test: Unit = { - // Values of types Int and String cannot be compared with == or !=, // unless we add the derived delegate instance like: given Eql[Int, String] = Eql.derived @@ -17,7 +16,7 @@ import scala.language.strictEquality // implicit def eqlNumber: Eql[Number, Number] = derived println("3 == 5.1: " + (3 == 5.1)) - // By default, all Sequences are comparable, because of; + // By default, all Sequences are comparable (except Array), because of; // implicit def eqlSeq[T, U](implicit eq: Eql[T, U]): Eql[GenSeq[T], GenSeq[U]] = derived // This fails, why? println("List(1, 2) == Vector(1, 2)): " + (List(1, 2) == Vector(1, 2))) @@ -28,7 +27,7 @@ import scala.language.strictEquality val a = new A(4) val b = new B(4) - // Two arrays in Scala 2 do not compare equal so why should this work? + // Two arrays in Scala do not compare equal so this is illegal code that must not compile? //println("Array(1, 2) == Array(1, 2): " + (Array(1, 2) == Array(1, 2))) // scala.language.strictEquality is enabled, therefore we need some extra delegate instances diff --git a/src/main/scala/NamedTypeArguments.scala b/src/main/scala/NamedTypeArguments.scala index 85cee9a..12a41f6 100644 --- a/src/main/scala/NamedTypeArguments.scala +++ b/src/main/scala/NamedTypeArguments.scala @@ -1,9 +1,7 @@ - /** * Named Type Arguments: https://dotty.epfl.ch/docs/reference/other-new-features/named-typeargs.html */ -object NamedTypeArguments { - +object NamedTypeArguments extends App { trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] } @@ -13,7 +11,6 @@ object NamedTypeArguments { } def test: Unit = { - def fmap[F[_], A, B](fa: F[A])(f: A => B)(implicit F: Functor[F]): F[B] = F.map(fa)(f) val result: List[Int] = fmap[F = List, A = Int, B = Int](List(1,2,3))(i => i + 1) @@ -25,7 +22,5 @@ object NamedTypeArguments { val compile: List[String] = fmap[F = List, B = String](List(1,2,3))(i => (i + 1).toString) println(compile) - } - -} \ No newline at end of file +} diff --git a/src/main/scala/PatternMatching.scala b/src/main/scala/PatternMatching.scala index 8e64e87..3193772 100644 --- a/src/main/scala/PatternMatching.scala +++ b/src/main/scala/PatternMatching.scala @@ -2,18 +2,14 @@ /** * Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html */ -object PatternMatching { - +object PatternMatching extends App { object booleanPattern { - object Even { def unapply(s: String): Boolean = s.length % 2 == 0 } - } object productPattern { - class Person(name: String, age: Int) extends Product { // if we not define that, it will give compile error. // we change the order @@ -29,11 +25,9 @@ object PatternMatching { object Person { def unapply(a: (String, Int)): Person = new Person(a._1, a._2) } - } object seqPattern { - // adapted from http://danielwestheide.com/blog/2012/11/28/the-neophytes-guide-to-scala-part-2-extracting-sequences.html object Names { def unapplySeq(name: String): Option[Seq[String]] = { @@ -46,7 +40,6 @@ object PatternMatching { } object namePattern { - class Name(val name: String) { def get: String = name def isEmpty = name.isEmpty @@ -59,7 +52,6 @@ object PatternMatching { } def test: Unit = { - import booleanPattern._ "even" match { @@ -98,6 +90,5 @@ object PatternMatching { case Name(n) => println(s"name is $n") case _ => println("empty name") } - } -} \ No newline at end of file +} diff --git a/src/main/scala/StructuralTypes.scala b/src/main/scala/StructuralTypes.scala index 4eb60a4..2994d81 100644 --- a/src/main/scala/StructuralTypes.scala +++ b/src/main/scala/StructuralTypes.scala @@ -2,8 +2,7 @@ /** * Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html */ -object StructuralTypes { - +object StructuralTypes extends App { case class Record(elems: (String, Any)*) extends Selectable { def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2 } @@ -20,9 +19,8 @@ object StructuralTypes { def test: Unit = { println(person.name) println(person.age) - println(invalidPerson.name) // age field is java.util.NoSuchElementException: None.get //println(invalidPerson.age) } -} \ No newline at end of file +} diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index 5d44099..a171226 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -1,7 +1,7 @@ /** * Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html */ -object TraitParams { +object TraitParams extends App { trait Base(val msg: String) class A extends Base("Hello") @@ -11,7 +11,6 @@ object TraitParams { private def printMessages(msgs: (A | B)*) = println(msgs.map(_.msg).mkString(" ")) def test: Unit = { - printMessages(new A, new B) // Sanity check the classpath: this won't run if the dotty jar is not present. diff --git a/src/main/scala/TypeLambdas.scala b/src/main/scala/TypeLambdas.scala index bcbb5b8..555977e 100644 --- a/src/main/scala/TypeLambdas.scala +++ b/src/main/scala/TypeLambdas.scala @@ -1,19 +1,16 @@ /** * Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html */ -object TypeLambdas { - +object TypeLambdas extends App { type T[+X, Y] = Map[Y, X] type Tuple = [X] =>> (X, X) def test: Unit = { - val m: T[String, Int] = Map(1 -> "1") println(m) val tuple: Tuple[String] = ("a", "b") println(tuple) } - } diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index ab3e365..472b8e1 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -1,8 +1,7 @@ /** * Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ -object UnionTypes { - +object UnionTypes extends App { sealed trait Division final case class DivisionByZero(msg: String) extends Division final case class Success(double: Double) extends Division @@ -24,7 +23,6 @@ object UnionTypes { } def test: Unit = { - val divisionResultSuccess: DivisionResult = safeDivide(4, 2) // commutative @@ -40,6 +38,5 @@ object UnionTypes { val emptyList: Empty | Cons[Any] = Empty() println(list) println(emptyList) - } } From 75418192ed1c82470f08339b0fe07dd8848c3a1d Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 17:01:16 -0800 Subject: [PATCH 06/59] - --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e6c916..95261e6 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.3.4") ### project/build.properties ```scala -sbt.version=1.2.8 +sbt.version=1.3.3 ``` Older versions of sbt are not supported. From 9e331c51284083d624124a233944fa3c530a8de1 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 17:09:07 -0800 Subject: [PATCH 07/59] - --- src/main/scala/UnionTypes.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index 472b8e1..5472fb7 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -10,7 +10,7 @@ object UnionTypes extends App { type DivisionResult = DivisionByZero | Success sealed trait List[+A] - final case class Empty() extends List[Nothing] + final class Empty extends List[Nothing] final case class Cons[+A](h: A, t: List[A]) extends List[A] private def safeDivide(a: Double, b: Double): DivisionResult = { @@ -25,13 +25,13 @@ object UnionTypes extends App { def test: Unit = { val divisionResultSuccess: DivisionResult = safeDivide(4, 2) - // commutative + // Commutative val divisionResultFailure: Success | DivisionByZero = safeDivide(4, 0) - // calling `either` function with union typed value. + // Calling `either` function with union typed value. println(either(divisionResultSuccess)) - // calling `either` function with union typed value. + // Calling `either` function with union typed value. println(either(divisionResultFailure)) val list: Cons[Int] | Empty = Cons(1, Cons(2, Cons(3, Empty()))) From 41f40a30ec099c6ad8ceea188de663550edb449a Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 17:32:34 -0800 Subject: [PATCH 08/59] - --- src/main/scala/ContextQueries.scala | 11 +++++------ src/main/scala/Conversion.scala | 14 +++++++------- src/main/scala/EnumTypes.scala | 4 +--- src/main/scala/ImpliedInstances.scala | 17 ++++++++--------- src/main/scala/Main.scala | 1 - src/main/scala/NamedTypeArguments.scala | 14 ++++++++------ src/main/scala/PatternMatching.scala | 6 +----- 7 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/main/scala/ContextQueries.scala b/src/main/scala/ContextQueries.scala index 68d2e61..a8c810e 100644 --- a/src/main/scala/ContextQueries.scala +++ b/src/main/scala/ContextQueries.scala @@ -2,12 +2,10 @@ import scala.concurrent.{ExecutionContext, Future} import scala.util.Try -/** - * Context Queries: +/** Context Queries (Formerly known as Implicit Function Types): * - http://dotty.epfl.ch/docs/reference/contextual/query-types.html, - * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html - */ -object ContextQueries extends App /* Formerly known as Implicit Function Types */ { + * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ +object ContextQueries extends App { object context { // type alias Contextual type Contextual[T] = (given ExecutionContext) => T @@ -15,7 +13,8 @@ object ContextQueries extends App /* Formerly known as Implicit Function Types * // sum is expanded to sum(x, y)(ctx) def asyncSum(x: Int, y: Int): Contextual[Future[Int]] = Future(x + y) - def asyncMult(x: Int, y: Int)(given ctx: ExecutionContext) = Future(x * y) + def asyncMult(x: Int, y: Int) + (given ctx: ExecutionContext) = Future(x * y) } object parse { diff --git a/src/main/scala/Conversion.scala b/src/main/scala/Conversion.scala index ae6b3ee..a60de3c 100644 --- a/src/main/scala/Conversion.scala +++ b/src/main/scala/Conversion.scala @@ -1,17 +1,17 @@ import scala.language.implicitConversions -/** - * Conversions: http://dotty.epfl.ch/docs/reference/contextual/conversions.html - */ +/** Conversions: http://dotty.epfl.ch/docs/reference/contextual/conversions.html */ object Conversion extends App { case class IntWrapper(a: Int) extends AnyVal case class DoubleWrapper(b: Double) extends AnyVal - def convert[T, U](x: T)(given converter: Conversion[T, U]): U = converter(x) + def convert[T, U](t: T) + (given converter: Conversion[T, U]): U = converter(t) - given IntWrapperToDoubleWrapper: Conversion[IntWrapper, DoubleWrapper] = new Conversion[IntWrapper, DoubleWrapper] { - override def apply(i: IntWrapper): DoubleWrapper = new DoubleWrapper(i.a.toDouble) - } + given IntWrapperToDoubleWrapper: Conversion[IntWrapper, DoubleWrapper] = + new Conversion[IntWrapper, DoubleWrapper] { + override def apply(i: IntWrapper): DoubleWrapper = new DoubleWrapper(i.a.toDouble) + } def useConversion(given f: Conversion[IntWrapper, DoubleWrapper]) = { val y: IntWrapper = new IntWrapper(4) diff --git a/src/main/scala/EnumTypes.scala b/src/main/scala/EnumTypes.scala index d3a4eef..f6c567f 100644 --- a/src/main/scala/EnumTypes.scala +++ b/src/main/scala/EnumTypes.scala @@ -1,6 +1,4 @@ -/** - * Enum Types: http://dotty.epfl.ch/docs/reference/enums/adts.html - */ +/** Enum Types: http://dotty.epfl.ch/docs/reference/enums/adts.html */ object EnumTypes extends App { enum ListEnum[+A] { case Cons(h: A, t: ListEnum[A]) diff --git a/src/main/scala/ImpliedInstances.scala b/src/main/scala/ImpliedInstances.scala index 5087892..700682a 100644 --- a/src/main/scala/ImpliedInstances.scala +++ b/src/main/scala/ImpliedInstances.scala @@ -1,9 +1,7 @@ import scala.util.{Success, Try} -/** - * Implied Instances: - * - https://dotty.epfl.ch/docs/reference/contextual/instance-defs.html - */ +/** Implied Instances: + * - https://dotty.epfl.ch/docs/reference/contextual/instance-defs.html */ object ImpliedInstances extends App { sealed trait StringParser[A] { def parse(s: String): Try[A] @@ -24,15 +22,16 @@ object ImpliedInstances extends App { new StringParser[Option[A]] { override def parse(s: String): Try[Option[A]] = s match { case "" ⇒ Success(None) // implicit parser not used. - case str ⇒ parser.parse(str).map(x ⇒ Some(x)) // implicit parser is evaluated at here + case str ⇒ parser.parse(str).map(Some(_)) // implicit parser is evaluated here } } } def test: Unit = { - println(implicitly[StringParser[Option[Int]]].parse("21")) - println(implicitly[StringParser[Option[Int]]].parse("")) - println(implicitly[StringParser[Option[Int]]].parse("21a")) - println(implicitly[StringParser[Option[Int]]](StringParser.optionParser[Int]).parse("42")) + val spoi = implicitly[StringParser[Option[Int]]] + println(spoi.parse("21")) + println(spoi.parse("")) + println(spoi.parse("21a")) + println(StringParser.optionParser[Int].parse("42")) } } diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index f3ba2a3..01107c0 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,4 +1,3 @@ - object Main { def main(args: Array[String]): Unit = { runExample("Trait Params")(TraitParams.test) diff --git a/src/main/scala/NamedTypeArguments.scala b/src/main/scala/NamedTypeArguments.scala index 12a41f6..a2ecb5d 100644 --- a/src/main/scala/NamedTypeArguments.scala +++ b/src/main/scala/NamedTypeArguments.scala @@ -1,17 +1,19 @@ -/** - * Named Type Arguments: https://dotty.epfl.ch/docs/reference/other-new-features/named-typeargs.html - */ +/** Named Type Arguments: https://dotty.epfl.ch/docs/reference/other-new-features/named-typeargs.html */ object NamedTypeArguments extends App { trait Functor[F[_]] { - def map[A, B](fa: F[A])(f: A => B): F[B] + def map[A, B](fa: F[A]) + (f: A => B): F[B] } implicit object listFunctor extends Functor[List] { - override def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f) + override def map[A, B](fa: List[A]) + (f: A => B): List[B] = fa.map(f) } def test: Unit = { - def fmap[F[_], A, B](fa: F[A])(f: A => B)(implicit F: Functor[F]): F[B] = F.map(fa)(f) + def fmap[F[_], A, B](fa: F[A]) + (f: A => B) + (implicit F: Functor[F]): F[B] = F.map(fa)(f) val result: List[Int] = fmap[F = List, A = Int, B = Int](List(1,2,3))(i => i + 1) diff --git a/src/main/scala/PatternMatching.scala b/src/main/scala/PatternMatching.scala index 3193772..14b77c8 100644 --- a/src/main/scala/PatternMatching.scala +++ b/src/main/scala/PatternMatching.scala @@ -1,7 +1,4 @@ - -/** - * Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html - */ +/** Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html */ object PatternMatching extends App { object booleanPattern { object Even { @@ -48,7 +45,6 @@ object PatternMatching extends App { object Name { def unapply(s: String): Name = new Name(s) } - } def test: Unit = { From 0bb2a9cc315fee71b20cba2206c054c5de4442f8 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 17 Nov 2019 17:35:41 -0800 Subject: [PATCH 09/59] - --- src/main/scala/StructuralTypes.scala | 5 +---- src/main/scala/TraitParams.scala | 9 ++++----- src/main/scala/TypeLambdas.scala | 4 +--- src/main/scala/UnionTypes.scala | 4 +--- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/scala/StructuralTypes.scala b/src/main/scala/StructuralTypes.scala index 2994d81..06223d9 100644 --- a/src/main/scala/StructuralTypes.scala +++ b/src/main/scala/StructuralTypes.scala @@ -1,7 +1,4 @@ - -/** - * Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html - */ +/** Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html */ object StructuralTypes extends App { case class Record(elems: (String, Any)*) extends Selectable { def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2 diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index a171226..0e81fa8 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -1,8 +1,5 @@ -/** - * Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html - */ +/** Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html */ object TraitParams extends App { - trait Base(val msg: String) class A extends Base("Hello") class B extends Base("Dotty!") @@ -14,7 +11,9 @@ object TraitParams extends App { printMessages(new A, new B) // Sanity check the classpath: this won't run if the dotty jar is not present. - val x: Int => Int = z => z + val x: Int => Int = + z => z + x(1) } } diff --git a/src/main/scala/TypeLambdas.scala b/src/main/scala/TypeLambdas.scala index 555977e..be1caa9 100644 --- a/src/main/scala/TypeLambdas.scala +++ b/src/main/scala/TypeLambdas.scala @@ -1,6 +1,4 @@ -/** - * Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html - */ +/** Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html */ object TypeLambdas extends App { type T[+X, Y] = Map[Y, X] diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index 5472fb7..91146c2 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -1,6 +1,4 @@ -/** - * Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html - */ +/** Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ object UnionTypes extends App { sealed trait Division final case class DivisionByZero(msg: String) extends Division From 64fb2d428f201796566f76a72fa55c0a7c07003c Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 19 Nov 2019 10:28:59 -0800 Subject: [PATCH 10/59] - --- src/main/scala/Main.scala | 1 + src/main/scala/Typeclasses.scala | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/main/scala/Typeclasses.scala diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 01107c0..0398dd7 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,5 +1,6 @@ object Main { def main(args: Array[String]): Unit = { + runExample("Typeclasses")(Typeclasses.test) runExample("Trait Params")(TraitParams.test) runExample("Enum Types")(EnumTypes.test) runExample("Context Queries")(ContextQueries.test) diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala new file mode 100644 index 0000000..38bc917 --- /dev/null +++ b/src/main/scala/Typeclasses.scala @@ -0,0 +1,21 @@ +/** + * Automatic Tupling of Function Params: https://dotty.epfl.ch/docs/reference/other-new-features/auto-parameter-tupling.html + */ +object Typeclasses extends App { + trait SemiGroup[T] { + def (x: T) combine (y: T): T + } + + trait Monoid [T] extends SemiGroup[T] { + def unit: T + } + + given Monoid[String] { + def (x: String) combine (y: String) = x.concat(y) + def unit = "" + + def sum[T: Monoid](xs: List[T]): T = + xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) + + def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c")) +} From 8514a350a6544ae2a9710c346c2f261f3e6bd219 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 19 Nov 2019 10:29:15 -0800 Subject: [PATCH 11/59] - --- src/main/scala/Typeclasses.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 38bc917..17bb3f5 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -1,6 +1,3 @@ -/** - * Automatic Tupling of Function Params: https://dotty.epfl.ch/docs/reference/other-new-features/auto-parameter-tupling.html - */ object Typeclasses extends App { trait SemiGroup[T] { def (x: T) combine (y: T): T From d6df577d6d3d014b0c05934895c2a9e75a0c1279 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 19 Nov 2019 10:31:35 -0800 Subject: [PATCH 12/59] - --- src/main/scala/Typeclasses.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 17bb3f5..d4f9143 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -10,9 +10,10 @@ object Typeclasses extends App { given Monoid[String] { def (x: String) combine (y: String) = x.concat(y) def unit = "" + } def sum[T: Monoid](xs: List[T]): T = xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) - def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c")) + def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) } From b91bb4f552c28d8042418d7f6adeab5564f7b4af Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 19 Nov 2019 10:39:36 -0800 Subject: [PATCH 13/59] - --- build.sbt | 16 +++++++--------- src/main/scala/Typeclasses.scala | 5 ++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index 88e1cb0..9140e8e 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,7 @@ -lazy val root = project - .in(file(".")) - .settings( - name := "dotty-example-project", - description := "Example sbt project that compiles using Dotty", - version := "0.1.0", - - scalaVersion := "0.20.0-RC1" - ) +description := "Example sbt project that compiles using Dotty" +logBuffered in Test := false +logLevel := Level.Warn +logLevel in test := Level.Info +name := "dotty-example-project" +scalaVersion := "0.20.0-RC1" +version := "0.1.0" diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index d4f9143..936063a 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -15,5 +15,8 @@ object Typeclasses extends App { def sum[T: Monoid](xs: List[T]): T = xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) - def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) + def test: Unit = { + println("\n\nasdf\nasdf\n\n") + println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) + } } From b8666eeab2f188b9bdccc5e3a0b32380aba688a2 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 19 Nov 2019 12:10:09 -0800 Subject: [PATCH 14/59] - --- src/main/scala/Typeclasses.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 936063a..4a50403 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -16,7 +16,6 @@ object Typeclasses extends App { xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) def test: Unit = { - println("\n\nasdf\nasdf\n\n") println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) } } From 281733d56a842cf78377b98b4316fe016b3b09e6 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 19 Nov 2019 13:40:05 -0800 Subject: [PATCH 15/59] - --- README.md | 8 ++++++++ src/main/scala/Main.scala | 3 ++- src/main/scala/Typeclasses.scala | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 95261e6..db407cb 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,14 @@ This is a normal sbt project, you can compile code with `sbt compile` and run it with `sbt run`, `sbt console` will start a Dotty REPL. +You can run just one example from the `sbt console`, for example we can run `Typeclasses.test`: + +``` +$ sbt console +scala> Typeclasses.test +sum("a", "b", "c"): abc +``` + If compiling this example project fails, you probably have a global sbt plugin that does not work with dotty, try to disable all plugins in `~/.sbt/1.0/plugins` and `~/.sbt/1.0`. diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 0398dd7..30632e6 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -16,7 +16,8 @@ object Main { runExample("Pattern Matching")(PatternMatching.test) } - private def runExample(name: String)(f: => Unit) = { + private def runExample(name: String) + (f: => Unit) = { println(Console.MAGENTA + s"$name example:" + Console.RESET) f println() diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 4a50403..0d6f1b8 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -1,4 +1,4 @@ -object Typeclasses extends App { +object Typeclasses { trait SemiGroup[T] { def (x: T) combine (y: T): T } From 6aeb463ee6702b06f936d77358387c5a0105dff6 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Sun, 24 Nov 2019 07:13:02 -0800 Subject: [PATCH 16/59] Update build.properties --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 6adcdc7..5a9ed92 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.3 +sbt.version=1.3.4 From 36457bad27e6e4a1cddd0f65ae5a059fd8d3ea99 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Mon, 25 Nov 2019 11:25:10 -0500 Subject: [PATCH 17/59] - --- README.md | 4 ++-- src/main/scala/Typeclasses.scala | 13 ++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index db407cb..a336d89 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,10 @@ addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.3.4") ### project/build.properties ```scala -sbt.version=1.3.3 +sbt.version=1.3.4 ``` -Older versions of sbt are not supported. +Versions of sbt older than 1.3.3 are not supported. ### build.sbt diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 0d6f1b8..40751b5 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -1,21 +1,16 @@ object Typeclasses { - trait SemiGroup[T] { + trait SemiGroup[T] with def (x: T) combine (y: T): T - } - trait Monoid [T] extends SemiGroup[T] { + trait Monoid [T] extends SemiGroup[T] with def unit: T - } - given Monoid[String] { + given Monoid[String] with def (x: String) combine (y: String) = x.concat(y) def unit = "" - } def sum[T: Monoid](xs: List[T]): T = xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) - def test: Unit = { - println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) - } + def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) } From 142d08b710893aa5a62abc134e843af0660d8cd1 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Mon, 25 Nov 2019 11:37:03 -0500 Subject: [PATCH 18/59] - --- src/main/scala/IntersectionTypes.scala | 2 +- src/main/scala/TraitParams.scala | 2 +- src/main/scala/Typeclasses.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/IntersectionTypes.scala b/src/main/scala/IntersectionTypes.scala index cb4e200..ea80de3 100644 --- a/src/main/scala/IntersectionTypes.scala +++ b/src/main/scala/IntersectionTypes.scala @@ -1,7 +1,7 @@ /** * Intersection Types: https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html */ -object IntersectionTypes { +object IntersectionTypes extends App { sealed trait X { def x: Double def tpe: X diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index 0e81fa8..c750bd7 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -5,7 +5,7 @@ object TraitParams extends App { class B extends Base("Dotty!") // Union types only exist in Dotty, so there's no chance that this will accidentally be compiled with Scala 2 - private def printMessages(msgs: (A | B)*) = println(msgs.map(_.msg).mkString(" ")) + private def printMessages(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ")) def test: Unit = { printMessages(new A, new B) diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 40751b5..92d6035 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -1,4 +1,4 @@ -object Typeclasses { +object Typeclasses extends App { trait SemiGroup[T] with def (x: T) combine (y: T): T From 163776adb1eac05493e3be40bb7efb40af17b540 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Mon, 25 Nov 2019 11:48:28 -0500 Subject: [PATCH 19/59] - --- src/main/scala/ExtensionClasses.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/scala/ExtensionClasses.scala diff --git a/src/main/scala/ExtensionClasses.scala b/src/main/scala/ExtensionClasses.scala new file mode 100644 index 0000000..3ec3e75 --- /dev/null +++ b/src/main/scala/ExtensionClasses.scala @@ -0,0 +1,14 @@ +object ExtensionClasses extends App { + case class Circle(x: Double, y: Double, radius: Double) + + // New Scala 3 way: + def (c: Circle) circumference: Double = c.radius * math.Pi * 2 + + val value = Circle(0, 0, 0.5).circumference + println(s"circumference = $value") + + // Scala 2 way + //implicit class CircleOps(circle: Circle) extends AnyVal { + // def circumference = circle.radius * Pi * 2 + //} +} From a75eb03a288320014ec8ff59c66ac1c050987d79 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Mon, 25 Nov 2019 16:25:35 -0500 Subject: [PATCH 20/59] - --- project/build.properties | 2 +- src/main/scala/ExtensionClasses.scala | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/project/build.properties b/project/build.properties index 5a9ed92..c0bab04 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.4 +sbt.version=1.2.8 diff --git a/src/main/scala/ExtensionClasses.scala b/src/main/scala/ExtensionClasses.scala index 3ec3e75..50767e9 100644 --- a/src/main/scala/ExtensionClasses.scala +++ b/src/main/scala/ExtensionClasses.scala @@ -1,14 +1,30 @@ -object ExtensionClasses extends App { +/** See https://dotty.epfl.ch/docs/reference/contextual/extension-methods-new.html */ +object ExtensionClasses1 extends App { case class Circle(x: Double, y: Double, radius: Double) // New Scala 3 way: def (c: Circle) circumference: Double = c.radius * math.Pi * 2 - val value = Circle(0, 0, 0.5).circumference - println(s"circumference = $value") + val circle = Circle(0, 0, 0.5) + println(s"circumference = ${ circle.circumference }") + + assert(circle.circumference == circumference(circle)) // Scala 2 way //implicit class CircleOps(circle: Circle) extends AnyVal { // def circumference = circle.radius * Pi * 2 //} } + +object ExtensionClasses2 extends App { + trait StringSeqOps { + def (xs: Seq[String]) longestStrings = { + val maxLength = xs.map(_.length).max + xs.filter(_.length == maxLength) + } + } + + given ops1: StringSeqOps + + println(s"""List("here", "is", "a", "list").longestStrings: """ + List("here", "is", "a", "list").longestStrings) +} From e9e3d669e283e7b08de1ba510f1cd4e3889716b1 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Mon, 25 Nov 2019 16:38:07 -0500 Subject: [PATCH 21/59] - --- src/main/scala/AutoParamTupling.scala | 1 + src/main/scala/ContextQueries.scala | 1 + src/main/scala/Conversion.scala | 2 ++ src/main/scala/EnumTypes.scala | 2 ++ src/main/scala/ImpliedInstances.scala | 2 ++ src/main/scala/IntersectionTypes.scala | 2 ++ src/main/scala/MultiversalEquality.scala | 2 ++ src/main/scala/NamedTypeArguments.scala | 2 ++ src/main/scala/PatternMatching.scala | 2 ++ src/main/scala/StructuralTypes.scala | 2 ++ src/main/scala/TraitParams.scala | 2 ++ src/main/scala/TypeLambdas.scala | 2 ++ src/main/scala/Typeclasses.scala | 2 ++ src/main/scala/UnionTypes.scala | 2 ++ 14 files changed, 26 insertions(+) diff --git a/src/main/scala/AutoParamTupling.scala b/src/main/scala/AutoParamTupling.scala index c7a1e76..478d486 100644 --- a/src/main/scala/AutoParamTupling.scala +++ b/src/main/scala/AutoParamTupling.scala @@ -13,4 +13,5 @@ object AutoParamTupling extends App { * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` */ xs.zipWithIndex.map((s, i) => println(s"$i: $s")) } + test } diff --git a/src/main/scala/ContextQueries.scala b/src/main/scala/ContextQueries.scala index a8c810e..60baa1d 100644 --- a/src/main/scala/ContextQueries.scala +++ b/src/main/scala/ContextQueries.scala @@ -41,4 +41,5 @@ object ContextQueries extends App { println(parse.sumStrings("3", "4")) println(parse.sumStrings("3", "a")) } + test } diff --git a/src/main/scala/Conversion.scala b/src/main/scala/Conversion.scala index a60de3c..ec65bca 100644 --- a/src/main/scala/Conversion.scala +++ b/src/main/scala/Conversion.scala @@ -30,4 +30,6 @@ object Conversion extends App { println(useConversion) println(convert(new IntWrapper(42))) } + + test } diff --git a/src/main/scala/EnumTypes.scala b/src/main/scala/EnumTypes.scala index f6c567f..da084b0 100644 --- a/src/main/scala/EnumTypes.scala +++ b/src/main/scala/EnumTypes.scala @@ -37,4 +37,6 @@ object EnumTypes extends App { calculateEarthWeightOnPlanets(80) } + + test } diff --git a/src/main/scala/ImpliedInstances.scala b/src/main/scala/ImpliedInstances.scala index 700682a..9cdcd8f 100644 --- a/src/main/scala/ImpliedInstances.scala +++ b/src/main/scala/ImpliedInstances.scala @@ -34,4 +34,6 @@ object ImpliedInstances extends App { println(spoi.parse("21a")) println(StringParser.optionParser[Int].parse("42")) } + + test } diff --git a/src/main/scala/IntersectionTypes.scala b/src/main/scala/IntersectionTypes.scala index ea80de3..ceae350 100644 --- a/src/main/scala/IntersectionTypes.scala +++ b/src/main/scala/IntersectionTypes.scala @@ -29,4 +29,6 @@ object IntersectionTypes extends App { val p2: PP = Point(6, 8) println(euclideanDistance(p1, p2)) } + + test } diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index 879838b..df317d4 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -38,4 +38,6 @@ import scala.language.strictEquality println("a != b: " + (a != b)) println("b == a: " + (b == a)) } + + test } diff --git a/src/main/scala/NamedTypeArguments.scala b/src/main/scala/NamedTypeArguments.scala index a2ecb5d..bb7402f 100644 --- a/src/main/scala/NamedTypeArguments.scala +++ b/src/main/scala/NamedTypeArguments.scala @@ -25,4 +25,6 @@ object NamedTypeArguments extends App { println(compile) } + + test } diff --git a/src/main/scala/PatternMatching.scala b/src/main/scala/PatternMatching.scala index 14b77c8..f126eb2 100644 --- a/src/main/scala/PatternMatching.scala +++ b/src/main/scala/PatternMatching.scala @@ -87,4 +87,6 @@ object PatternMatching extends App { case _ => println("empty name") } } + + test } diff --git a/src/main/scala/StructuralTypes.scala b/src/main/scala/StructuralTypes.scala index 06223d9..2f46280 100644 --- a/src/main/scala/StructuralTypes.scala +++ b/src/main/scala/StructuralTypes.scala @@ -20,4 +20,6 @@ object StructuralTypes extends App { // age field is java.util.NoSuchElementException: None.get //println(invalidPerson.age) } + + test } diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index c750bd7..32db613 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -16,4 +16,6 @@ object TraitParams extends App { x(1) } + + test } diff --git a/src/main/scala/TypeLambdas.scala b/src/main/scala/TypeLambdas.scala index be1caa9..32dd5c8 100644 --- a/src/main/scala/TypeLambdas.scala +++ b/src/main/scala/TypeLambdas.scala @@ -11,4 +11,6 @@ object TypeLambdas extends App { val tuple: Tuple[String] = ("a", "b") println(tuple) } + + test } diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 92d6035..42e5f99 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -13,4 +13,6 @@ object Typeclasses extends App { xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) + + test } diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index 91146c2..43a0045 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -37,4 +37,6 @@ object UnionTypes extends App { println(list) println(emptyList) } + + test } From be497ca38d9f56970a4cd0207c23db8de18ce2fc Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 12:29:20 -0500 Subject: [PATCH 22/59] - --- src/main/scala/AutoParamTupling.scala | 5 ++--- src/main/scala/ContextQueries.scala | 3 ++- src/main/scala/ContextQueries2.scala | 25 +++++++++++++++++++++++++ src/main/scala/ExtensionClasses.scala | 4 ++-- 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 src/main/scala/ContextQueries2.scala diff --git a/src/main/scala/AutoParamTupling.scala b/src/main/scala/AutoParamTupling.scala index 478d486..18825f6 100644 --- a/src/main/scala/AutoParamTupling.scala +++ b/src/main/scala/AutoParamTupling.scala @@ -1,6 +1,4 @@ -/** - * Automatic Tupling of Function Params: https://dotty.epfl.ch/docs/reference/other-new-features/auto-parameter-tupling.html - */ +/** Automatic Tupling of Function Params: https://dotty.epfl.ch/docs/reference/other-new-features/auto-parameter-tupling.html */ object AutoParamTupling extends App { def test: Unit = { /** In order to get thread safety, you need to put @volatile before lazy vals. @@ -13,5 +11,6 @@ object AutoParamTupling extends App { * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` */ xs.zipWithIndex.map((s, i) => println(s"$i: $s")) } + test } diff --git a/src/main/scala/ContextQueries.scala b/src/main/scala/ContextQueries.scala index 60baa1d..8ea8f8b 100644 --- a/src/main/scala/ContextQueries.scala +++ b/src/main/scala/ContextQueries.scala @@ -3,7 +3,7 @@ import scala.concurrent.{ExecutionContext, Future} import scala.util.Try /** Context Queries (Formerly known as Implicit Function Types): - * - http://dotty.epfl.ch/docs/reference/contextual/query-types.html, + * - http://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html, * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ object ContextQueries extends App { object context { @@ -41,5 +41,6 @@ object ContextQueries extends App { println(parse.sumStrings("3", "4")) println(parse.sumStrings("3", "a")) } + test } diff --git a/src/main/scala/ContextQueries2.scala b/src/main/scala/ContextQueries2.scala new file mode 100644 index 0000000..84b2e20 --- /dev/null +++ b/src/main/scala/ContextQueries2.scala @@ -0,0 +1,25 @@ +/** This example combines opaque aliases, implicit function types, and extension methods to provide + * a zero-overhead abstraction at runtime. + * See http://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html#example-postconditions */ +object PostConditions { + opaque type WrappedResult[T] = T + + def result[T](given r: WrappedResult[T]): T = r + + /** This extension method accepts an implicit function type called `condition`, + * which receives the given instance of type `WrappedResult[T]``. + * The given `WrappedResult` instance is passed to the result method. + * `WrappedResult` is an opaque type alias, so its values need not be boxed or unboxed. + * Because `ensuring` is added as an extension method, its argument also does not need boxing. */ + def [T](x: T) ensuring(condition: (given WrappedResult[T]) => Boolean): T = { + assert(condition(given x)) + x + } +} + +object ContextQueries2 extends App { + import PostConditions.{ensuring, result} + + val s = List(1, 2, 3).sum.ensuring(result == 6) + println("Yes, the list sums to 6.") +} diff --git a/src/main/scala/ExtensionClasses.scala b/src/main/scala/ExtensionClasses.scala index 50767e9..bdb26e5 100644 --- a/src/main/scala/ExtensionClasses.scala +++ b/src/main/scala/ExtensionClasses.scala @@ -2,7 +2,7 @@ object ExtensionClasses1 extends App { case class Circle(x: Double, y: Double, radius: Double) - // New Scala 3 way: + // New Scala 3 way, using an extension method: def (c: Circle) circumference: Double = c.radius * math.Pi * 2 val circle = Circle(0, 0, 0.5) @@ -10,7 +10,7 @@ object ExtensionClasses1 extends App { assert(circle.circumference == circumference(circle)) - // Scala 2 way + // Old Scala 2 way, using an implicit class: //implicit class CircleOps(circle: Circle) extends AnyVal { // def circumference = circle.radius * Pi * 2 //} From 62e31757e5184e92fca7c3b7085c358b0a8054a7 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 13:14:14 -0500 Subject: [PATCH 23/59] - --- src/main/scala/Main.scala | 2 + src/main/scala/OpaqueTypes.scala | 64 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/main/scala/OpaqueTypes.scala diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 30632e6..848ae9e 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -6,6 +6,8 @@ object Main { runExample("Context Queries")(ContextQueries.test) runExample("Implied Instances")(ImpliedInstances.test) runExample("Conversion")(Conversion.test) + runExample("OpaqueTypes 1")(OpaqueTypes1.test) + runExample("OpaqueTypes 2")(OpaqueTypes2.test) runExample("Union Types")(UnionTypes.test) runExample("Intersection Types")(IntersectionTypes.test) runExample("Type Lambda")(TypeLambdas.test) diff --git a/src/main/scala/OpaqueTypes.scala b/src/main/scala/OpaqueTypes.scala new file mode 100644 index 0000000..2a3e9b7 --- /dev/null +++ b/src/main/scala/OpaqueTypes.scala @@ -0,0 +1,64 @@ +/** Opaque types aliases provide type abstraction without *any* runtime overhead. +See https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html */ +object OpaqueTypes1 extends App { + object Logarithms { + opaque type Logarithm = Double + + object Logarithm { + // These are the ways to lift to the logarithm type + def apply(d: Double): Logarithm = math.log(d) + + def safe(d: Double): Option[Logarithm] = + if (d > 0.0) Some(math.log(d)) else None + } + + // Extension methods define opaque types' public APIs + given logarithmOps: { + def (x: Logarithm) toDouble: Double = math.exp(x) + def (x: Logarithm) + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) + def (x: Logarithm) * (y: Logarithm): Logarithm = Logarithm(x + y) + } + } + + def test: Unit = { + import Logarithms._ + + println("Logarithm(1.0) * Logarithm(2.0): " + (Logarithm(1.0) * Logarithm(2.0))) + println("Logarithm(1.0) + Logarithm(2.0): " + (Logarithm(1.0) + Logarithm(2.0))) + } + + test +} + +object OpaqueTypes2 extends App { + object Access { + opaque type Permissions = Int + opaque type PermissionChoice = Int + /** `Permission`'s upper bound is `Permissions & PermissionChoice`. + * Thus `Permission` is universally known to be a subtype of `Permissions` and `PermissionChoice`. */ + opaque type Permission <: Permissions & PermissionChoice = Int + + def (x: Permissions) & (y: Permissions): Permissions = x & y + def (x: PermissionChoice) | (y: PermissionChoice): PermissionChoice = x | y + def (x: Permissions) is (y: Permissions) = (x & y) == y + def (x: Permissions) isOneOf (y: PermissionChoice) = (x & y) != 0 + + val NoPermission: Permission = 0 + val ReadOnly: Permission = 1 + val WriteOnly: Permission = 2 + val ReadWrite: Permissions = ReadOnly & WriteOnly + val ReadOrWrite: PermissionChoice = ReadOnly | WriteOnly + } + + def test: Unit = { + import Access._ + + case class Item(rights: Permissions) + + val x = Item(ReadOnly) + assert( x.rights.is(ReadWrite) ) + assert( x.rights.isOneOf(ReadOrWrite) == true ) + } + + test +} From 004f1134ef28c9aa2285b1e869afeb7894bc0dd6 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:04:26 -0500 Subject: [PATCH 24/59] - --- src/main/scala/OpaqueTypes.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/OpaqueTypes.scala b/src/main/scala/OpaqueTypes.scala index 2a3e9b7..5ba3de7 100644 --- a/src/main/scala/OpaqueTypes.scala +++ b/src/main/scala/OpaqueTypes.scala @@ -46,7 +46,7 @@ object OpaqueTypes2 extends App { val NoPermission: Permission = 0 val ReadOnly: Permission = 1 val WriteOnly: Permission = 2 - val ReadWrite: Permissions = ReadOnly & WriteOnly + val ReadWrite: Permissions = ReadOnly | WriteOnly val ReadOrWrite: PermissionChoice = ReadOnly | WriteOnly } @@ -56,8 +56,8 @@ object OpaqueTypes2 extends App { case class Item(rights: Permissions) val x = Item(ReadOnly) - assert( x.rights.is(ReadWrite) ) - assert( x.rights.isOneOf(ReadOrWrite) == true ) + assert( ! x.rights.is(ReadWrite) ) + assert( x.rights.isOneOf(ReadOrWrite) ) } test From 80975485645ca6028a2bf36303670d8400f4a6f3 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:16:57 -0500 Subject: [PATCH 25/59] - --- src/main/scala/OpaqueTypes.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/OpaqueTypes.scala b/src/main/scala/OpaqueTypes.scala index 5ba3de7..199cf8d 100644 --- a/src/main/scala/OpaqueTypes.scala +++ b/src/main/scala/OpaqueTypes.scala @@ -34,6 +34,7 @@ object OpaqueTypes2 extends App { object Access { opaque type Permissions = Int opaque type PermissionChoice = Int + /** `Permission`'s upper bound is `Permissions & PermissionChoice`. * Thus `Permission` is universally known to be a subtype of `Permissions` and `PermissionChoice`. */ opaque type Permission <: Permissions & PermissionChoice = Int From 6f5dd69519782cc3c0390baaf14c9eafb4fa9965 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:25:01 -0500 Subject: [PATCH 26/59] - --- .travis.yml | 8 -------- README.md | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 99c1040..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: scala - -jdk: - - openjdk8 - -script: - - sbt run - - sbt 'set scalaVersion := dottyLatestNightlyBuild.get' run diff --git a/README.md b/README.md index a336d89..b60d8c1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Example sbt project that compiles using Dotty -[![Build Status](https://travis-ci.org/lampepfl/dotty-example-project.svg?branch=master)](https://travis-ci.org/lampepfl/dotty-example-project) +I (Mike Slinn) fixed many significant bugs in the [upstream project](https://github.com/lampepfl/dotty-example-project) and added code examples for new major features that were missing. ## Usage @@ -21,13 +21,20 @@ that does not work with dotty, try to disable all plugins in ### IDE support -Dotty comes built-in with IDE support, to try it out see +> Dotty comes built-in with IDE support, to try it out see http://dotty.epfl.ch/docs/usage/ide-support.html +Meh, not so much. +I found Atom with sbt running in a shell under platformio terminal worked best. + ## Making a new Dotty project -The fastest way to start a new Dotty project is to use one of the following templates: -* [Simple Dotty project](https://github.com/lampepfl/dotty.g8) -* [Dotty project that cross-compiles with Scala 2](https://github.com/lampepfl/dotty-cross.g8) +> The fastest way to start a new Dotty project is to use one of the following templates: +> * [Simple Dotty project](https://github.com/lampepfl/dotty.g8) +> * [Dotty project that cross-compiles with Scala 2](https://github.com/lampepfl/dotty-cross.g8) + +I am not a fan of `giter8`. +There is no reason to introduce yet another obscure language. +[Try dottyTemplate](https://github.com/mslinn/dottyTemplate) instead. ## Using Dotty in an existing project @@ -40,11 +47,11 @@ addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.3.4") ### project/build.properties ```scala -sbt.version=1.3.4 +sbt.version=1.2.8 ``` -Versions of sbt older than 1.3.3 are not supported. - +Versions of sbt older than 1.2.8 are not supported. +Versions 1.3.2 and 1.3.3 do not work properly with Dotty. ### build.sbt Any version number that starts with `0.` is automatically recognized as Dotty by @@ -74,9 +81,11 @@ scalacOptions ++= { if (isDotty.value) Seq("-language:Scala2") else Nil } Using the `isDotty` setting ensures that this option will only be set when compiling with Dotty. -A tool to port code from Scala 2.x to Dotty is currently in development at +> A tool to port code from Scala 2.x to Dotty is currently in development at https://github.com/scalacenter/scalafix +Actually, the truth is `scalafix` has not had any work done on it in a long time, and there is no indication when this important project will get the attention it deserves. I'm concerned that history will repeat itself and we'll get a last-minute hack job. + If your build contains dependencies that have only been published for Scala 2.x, you may be able to get them to work on Dotty by replacing: From d746979e759942e17d5a0d2424d4c8b436a8e8e2 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:25:58 -0500 Subject: [PATCH 27/59] - --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b60d8c1..386428d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Example sbt project that compiles using Dotty +# Example sbt Project that Compiles Using Dotty I (Mike Slinn) fixed many significant bugs in the [upstream project](https://github.com/lampepfl/dotty-example-project) and added code examples for new major features that were missing. @@ -51,7 +51,7 @@ sbt.version=1.2.8 ``` Versions of sbt older than 1.2.8 are not supported. -Versions 1.3.2 and 1.3.3 do not work properly with Dotty. +Versions 1.3.3 and 1.3.4 do not work properly with Dotty. ### build.sbt Any version number that starts with `0.` is automatically recognized as Dotty by From c0fb06940d6e84c2d17c6e5e684c7f33c3bab4ef Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:26:33 -0500 Subject: [PATCH 28/59] - --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 386428d..79e6a7e 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,7 @@ https://repo1.maven.org/maven2/ch/epfl/lamp/dotty_0.18/ to find the version number for the latest nightly build. Alternatively, you can set `scalaVersion := dottyLatestNightlyBuild.get` to always use the latest nightly build of dotty. -## Getting your project to compile with Dotty - +## Compiling Your Project with Dotty When porting an existing project, it's a good idea to start out with the Scala 2 compatibility mode (note that this mode affects typechecking and thus may prevent some valid Dotty code from compiling) by adding to your `build.sbt`: From 366a242812e03823d3d9332c4f7cc7ee117c28e9 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:26:52 -0500 Subject: [PATCH 29/59] - --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79e6a7e..1f715f9 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ https://repo1.maven.org/maven2/ch/epfl/lamp/dotty_0.18/ to find the version number for the latest nightly build. Alternatively, you can set `scalaVersion := dottyLatestNightlyBuild.get` to always use the latest nightly build of dotty. -## Compiling Your Project with Dotty +## Compiling Scala 2 Projects with Dotty When porting an existing project, it's a good idea to start out with the Scala 2 compatibility mode (note that this mode affects typechecking and thus may prevent some valid Dotty code from compiling) by adding to your `build.sbt`: From a7a6568bc053a50fceb0d861797284d868d9752e Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:27:36 -0500 Subject: [PATCH 30/59] - --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1f715f9..212c11a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If compiling this example project fails, you probably have a global sbt plugin that does not work with dotty, try to disable all plugins in `~/.sbt/1.0/plugins` and `~/.sbt/1.0`. -### IDE support +### IDE Support > Dotty comes built-in with IDE support, to try it out see http://dotty.epfl.ch/docs/usage/ide-support.html @@ -27,7 +27,7 @@ http://dotty.epfl.ch/docs/usage/ide-support.html Meh, not so much. I found Atom with sbt running in a shell under platformio terminal worked best. -## Making a new Dotty project +## Making a New Dotty Project > The fastest way to start a new Dotty project is to use one of the following templates: > * [Simple Dotty project](https://github.com/lampepfl/dotty.g8) > * [Dotty project that cross-compiles with Scala 2](https://github.com/lampepfl/dotty-cross.g8) @@ -36,7 +36,7 @@ I am not a fan of `giter8`. There is no reason to introduce yet another obscure language. [Try dottyTemplate](https://github.com/mslinn/dottyTemplate) instead. -## Using Dotty in an existing project +## Using Dotty in An Existing Project You will need to make the following adjustments to your build: @@ -45,7 +45,7 @@ You will need to make the following adjustments to your build: addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.3.4") ``` -### project/build.properties +### `project/build.properties` ```scala sbt.version=1.2.8 ``` @@ -53,7 +53,7 @@ sbt.version=1.2.8 Versions of sbt older than 1.2.8 are not supported. Versions 1.3.3 and 1.3.4 do not work properly with Dotty. -### build.sbt +### `build.sbt` Any version number that starts with `0.` is automatically recognized as Dotty by the `sbt-dotty` plugin, you don't need to set up anything: @@ -61,7 +61,7 @@ the `sbt-dotty` plugin, you don't need to set up anything: scalaVersion := "0.20.0-RC1" ``` -#### Nightly builds +#### Nightly Builds If the latest release of Dotty is missing a bugfix or feature you need, you may wish to use a nightly build. Look at the bottom of https://repo1.maven.org/maven2/ch/epfl/lamp/dotty_0.18/ to find the version From abd66bf5662d4197a1a915cd10fca51e4f074aa5 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:29:26 -0500 Subject: [PATCH 31/59] - --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 212c11a..f7056cc 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,12 @@ I (Mike Slinn) fixed many significant bugs in the [upstream project](https://git ## Usage -This is a normal sbt project, you can compile code with `sbt compile` and run it -with `sbt run`, `sbt console` will start a Dotty REPL. +This is a normal sbt project. +You can compile code with `sbt compile` and run it +with `sbt run` or `sbt runMain `. +`sbt console` will start a Dotty REPL. -You can run just one example from the `sbt console`, for example we can run `Typeclasses.test`: +You can also execute just one example from the `sbt console` by evaluating the `test` method, for example we can run `Typeclasses.test`: ``` $ sbt console @@ -16,8 +18,8 @@ sum("a", "b", "c"): abc ``` If compiling this example project fails, you probably have a global sbt plugin -that does not work with dotty, try to disable all plugins in -`~/.sbt/1.0/plugins` and `~/.sbt/1.0`. +that does not work with dotty; disable all plugins in +`~/.sbt/1.0/plugins` and `~/.sbt/1.0` by renaming those directories to something else. ### IDE Support From 2b733abdb7da0504a389707631a960f6ba986fe7 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:30:20 -0500 Subject: [PATCH 32/59] - --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f7056cc..a905524 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ If compiling this example project fails, you probably have a global sbt plugin that does not work with dotty; disable all plugins in `~/.sbt/1.0/plugins` and `~/.sbt/1.0` by renaming those directories to something else. -### IDE Support +## IDE Support > Dotty comes built-in with IDE support, to try it out see http://dotty.epfl.ch/docs/usage/ide-support.html @@ -63,7 +63,7 @@ the `sbt-dotty` plugin, you don't need to set up anything: scalaVersion := "0.20.0-RC1" ``` -#### Nightly Builds +### Nightly Builds If the latest release of Dotty is missing a bugfix or feature you need, you may wish to use a nightly build. Look at the bottom of https://repo1.maven.org/maven2/ch/epfl/lamp/dotty_0.18/ to find the version @@ -111,6 +111,5 @@ Alternatively, to set this setting on all your dependencies, you can use: ``` ## Discuss - -Feel free to come chat with us on the +Feel free to come chat on the [Dotty gitter](http://gitter.im/lampepfl/dotty)! From 477c53b99d88050193e21453d2504ed3fc3ff937 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:30:35 -0500 Subject: [PATCH 33/59] - --- src/main/scala/ContextQueries.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/ContextQueries.scala b/src/main/scala/ContextQueries.scala index 8ea8f8b..2f124d6 100644 --- a/src/main/scala/ContextQueries.scala +++ b/src/main/scala/ContextQueries.scala @@ -5,7 +5,7 @@ import scala.util.Try /** Context Queries (Formerly known as Implicit Function Types): * - http://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html, * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ -object ContextQueries extends App { +object ContextQueries1 extends App { object context { // type alias Contextual type Contextual[T] = (given ExecutionContext) => T From 9f894dce624d96fb081f7290b347bed232329632 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:32:23 -0500 Subject: [PATCH 34/59] - --- src/main/scala/ContextQueries2.scala | 6 ++++-- src/main/scala/Main.scala | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/scala/ContextQueries2.scala b/src/main/scala/ContextQueries2.scala index 84b2e20..d39e671 100644 --- a/src/main/scala/ContextQueries2.scala +++ b/src/main/scala/ContextQueries2.scala @@ -20,6 +20,8 @@ object PostConditions { object ContextQueries2 extends App { import PostConditions.{ensuring, result} - val s = List(1, 2, 3).sum.ensuring(result == 6) - println("Yes, the list sums to 6.") + def test: Unit = { + val s = List(1, 2, 3).sum.ensuring(result == 6) + println("Yes, the list sums to 6.") + } } diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 848ae9e..76dfffe 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -3,7 +3,8 @@ object Main { runExample("Typeclasses")(Typeclasses.test) runExample("Trait Params")(TraitParams.test) runExample("Enum Types")(EnumTypes.test) - runExample("Context Queries")(ContextQueries.test) + runExample("Context Queries 1")(ContextQueries1.test) + runExample("Context Queries 2")(ContextQueries2.test) runExample("Implied Instances")(ImpliedInstances.test) runExample("Conversion")(Conversion.test) runExample("OpaqueTypes 1")(OpaqueTypes1.test) From 9990ba0d778e91cc7169fda8237c164f357e3b60 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:32:42 -0500 Subject: [PATCH 35/59] - --- src/main/scala/{ContextQueries.scala => ContextQueries1.scala} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/scala/{ContextQueries.scala => ContextQueries1.scala} (100%) diff --git a/src/main/scala/ContextQueries.scala b/src/main/scala/ContextQueries1.scala similarity index 100% rename from src/main/scala/ContextQueries.scala rename to src/main/scala/ContextQueries1.scala From 139dd8e5786f1c3b7bddeb8bcecec57e32f55638 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 14:59:52 -0500 Subject: [PATCH 36/59] - --- src/main/scala/Main.scala | 14 +++++++------- src/main/scala/TraitParams.scala | 20 ++++++++++---------- src/main/scala/UnionTypes.scala | 3 +-- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 76dfffe..951df2d 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,22 +1,22 @@ object Main { def main(args: Array[String]): Unit = { - runExample("Typeclasses")(Typeclasses.test) runExample("Trait Params")(TraitParams.test) - runExample("Enum Types")(EnumTypes.test) + runExample("Typeclasses")(Typeclasses.test) + runExample("OpaqueTypes 1")(OpaqueTypes1.test) runExample("Context Queries 1")(ContextQueries1.test) + runExample("Intersection Types")(IntersectionTypes.test) runExample("Context Queries 2")(ContextQueries2.test) - runExample("Implied Instances")(ImpliedInstances.test) - runExample("Conversion")(Conversion.test) - runExample("OpaqueTypes 1")(OpaqueTypes1.test) runExample("OpaqueTypes 2")(OpaqueTypes2.test) - runExample("Union Types")(UnionTypes.test) - runExample("Intersection Types")(IntersectionTypes.test) runExample("Type Lambda")(TypeLambdas.test) + runExample("Enum Types")(EnumTypes.test) + runExample("Implied Instances")(ImpliedInstances.test) + runExample("Conversion")(Conversion.test) runExample("Multiversal Equality")(MultiversalEquality.test) runExample("Named Type Arguments")(NamedTypeArguments.test) runExample("Auto Param Tupling")(AutoParamTupling.test) runExample("Structural Types")(StructuralTypes.test) runExample("Pattern Matching")(PatternMatching.test) + runExample("Union Types")(UnionTypes.test) } private def runExample(name: String) diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index 32db613..ef4f2ee 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -1,20 +1,20 @@ /** Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html */ object TraitParams extends App { trait Base(val msg: String) + class A extends Base("Hello") - class B extends Base("Dotty!") + class B extends Base("Dotty") - // Union types only exist in Dotty, so there's no chance that this will accidentally be compiled with Scala 2 - private def printMessages(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ")) + case class C(override val msg: String) extends Base(msg) + case class D(override val msg: String) extends Base(msg) - def test: Unit = { - printMessages(new A, new B) - - // Sanity check the classpath: this won't run if the dotty jar is not present. - val x: Int => Int = - z => z + /** @param msgs varargs union type (sequence of A or B) */ + private def printMessages1(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") + private def printMessages2(msgs: (C | D)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") - x(1) + def test: Unit = { + printMessages1(new A, new B) + printMessages2(C("Goodbye"), D("cruel world")) } test diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index 43a0045..c909a4b 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -11,9 +11,8 @@ object UnionTypes extends App { final class Empty extends List[Nothing] final case class Cons[+A](h: A, t: List[A]) extends List[A] - private def safeDivide(a: Double, b: Double): DivisionResult = { + private def safeDivide(a: Double, b: Double): DivisionResult = if (b == 0) DivisionByZero("DivisionByZeroException") else Success(a / b) - } private def either(division: Division) = division match { case DivisionByZero(m) => Left(m) From c65727b6d47980763a60671ba1974c571105c2d5 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 15:09:34 -0500 Subject: [PATCH 37/59] - --- src/main/scala/TraitParams.scala | 8 +++++--- src/main/scala/UnionTypes.scala | 17 ++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index ef4f2ee..6d17c9e 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -1,15 +1,17 @@ /** Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html */ object TraitParams extends App { trait Base(val msg: String) - + class A extends Base("Hello") class B extends Base("Dotty") + /** @param msgs varargs union type (sequence of A or B) */ + private def printMessages1(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") + + case class C(override val msg: String) extends Base(msg) case class D(override val msg: String) extends Base(msg) - /** @param msgs varargs union type (sequence of A or B) */ - private def printMessages1(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") private def printMessages2(msgs: (C | D)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") def test: Unit = { diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index c909a4b..2669d59 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -1,15 +1,17 @@ -/** Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ +/** Union types (aka sum types): https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ object UnionTypes extends App { sealed trait Division final case class DivisionByZero(msg: String) extends Division final case class Success(double: Double) extends Division - // You can create type aliases for your union types (sum types). + // Type aliases can use union types type DivisionResult = DivisionByZero | Success sealed trait List[+A] - final class Empty extends List[Nothing] final case class Cons[+A](h: A, t: List[A]) extends List[A] + final class Empty extends List[Nothing] { + override def toString: String = "Empty" + } private def safeDivide(a: Double, b: Double): DivisionResult = if (b == 0) DivisionByZero("DivisionByZeroException") else Success(a / b) @@ -26,15 +28,16 @@ object UnionTypes extends App { val divisionResultFailure: Success | DivisionByZero = safeDivide(4, 0) // Calling `either` function with union typed value. - println(either(divisionResultSuccess)) + println("either(divisionResultSuccess): " + either(divisionResultSuccess)) // Calling `either` function with union typed value. - println(either(divisionResultFailure)) + println("either(divisionResultFailure): " + either(divisionResultFailure)) val list: Cons[Int] | Empty = Cons(1, Cons(2, Cons(3, Empty()))) + println("list: " + list) + val emptyList: Empty | Cons[Any] = Empty() - println(list) - println(emptyList) + println("emptyList: " + emptyList) } test From 706296dd179cb6ff07842a905d4b0de5e4b90555 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 15:23:16 -0500 Subject: [PATCH 38/59] - --- src/main/scala/EnumTypes.scala | 7 +++++-- src/main/scala/ExtensionClasses.scala | 3 ++- src/main/scala/OpaqueTypes.scala | 5 +++-- src/main/scala/Typeclasses.scala | 6 ++++++ src/main/scala/UnionTypes.scala | 7 ++++++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/scala/EnumTypes.scala b/src/main/scala/EnumTypes.scala index da084b0..042d8f4 100644 --- a/src/main/scala/EnumTypes.scala +++ b/src/main/scala/EnumTypes.scala @@ -1,4 +1,7 @@ -/** Enum Types: http://dotty.epfl.ch/docs/reference/enums/adts.html */ +/** Proper Scala enums (Scala 2 Enumerations are horrible). + * * Interoperate with Java enums + * * Support Algebraic Data Types (ADTs) because they accept type parameters, and can be Generalized ADTs (GADTs). + * See http://dotty.epfl.ch/docs/reference/enums/adts.html */ object EnumTypes extends App { enum ListEnum[+A] { case Cons(h: A, t: ListEnum[A]) @@ -37,6 +40,6 @@ object EnumTypes extends App { calculateEarthWeightOnPlanets(80) } - + test } diff --git a/src/main/scala/ExtensionClasses.scala b/src/main/scala/ExtensionClasses.scala index bdb26e5..d70b872 100644 --- a/src/main/scala/ExtensionClasses.scala +++ b/src/main/scala/ExtensionClasses.scala @@ -1,4 +1,5 @@ -/** See https://dotty.epfl.ch/docs/reference/contextual/extension-methods-new.html */ +/** Easy way to add methods to existing classes + * See https://dotty.epfl.ch/docs/reference/contextual/extension-methods-new.html */ object ExtensionClasses1 extends App { case class Circle(x: Double, y: Double, radius: Double) diff --git a/src/main/scala/OpaqueTypes.scala b/src/main/scala/OpaqueTypes.scala index 199cf8d..c099183 100644 --- a/src/main/scala/OpaqueTypes.scala +++ b/src/main/scala/OpaqueTypes.scala @@ -1,5 +1,6 @@ /** Opaque types aliases provide type abstraction without *any* runtime overhead. -See https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html */ + * Replace Scala 2 value types + * See https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html */ object OpaqueTypes1 extends App { object Logarithms { opaque type Logarithm = Double @@ -34,7 +35,7 @@ object OpaqueTypes2 extends App { object Access { opaque type Permissions = Int opaque type PermissionChoice = Int - + /** `Permission`'s upper bound is `Permissions & PermissionChoice`. * Thus `Permission` is universally known to be a subtype of `Permissions` and `PermissionChoice`. */ opaque type Permission <: Permissions & PermissionChoice = Int diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 42e5f99..10dd307 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -1,3 +1,9 @@ +/** Extension methods provide a nice syntax for typeclasses + * * Removes need for dangerous implicit conversions + * * Emphasize intent over mechanism + * * Better error messages than generated from implicits + * * Implicit conversions will go away + * See https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates */ object Typeclasses extends App { trait SemiGroup[T] with def (x: T) combine (y: T): T diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index 2669d59..52beebf 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -1,4 +1,9 @@ -/** Union types (aka sum types): https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ +/** Union types (aka sum types): + * * Like C structs + * * No boxing/unboxing overhead + * * Works with singleton types + * * Good for Scala/JavaScript interoperability + * https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ object UnionTypes extends App { sealed trait Division final case class DivisionByZero(msg: String) extends Division From 67649f81b820d73c28fd49e913ab928c58a76b39 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 15:28:26 -0500 Subject: [PATCH 39/59] - --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a905524..b7acf56 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ that does not work with dotty; disable all plugins in http://dotty.epfl.ch/docs/usage/ide-support.html Meh, not so much. -I found Atom with sbt running in a shell under platformio terminal worked best. +I found Atom with sbt running in a shell under `platformio-ide-terminal` worked best. ## Making a New Dotty Project > The fastest way to start a new Dotty project is to use one of the following templates: @@ -111,5 +111,4 @@ Alternatively, to set this setting on all your dependencies, you can use: ``` ## Discuss -Feel free to come chat on the -[Dotty gitter](http://gitter.im/lampepfl/dotty)! +Chat on the [Dotty gitter](http://gitter.im/lampepfl/dotty) channel. From 4019e5caa24e4ec082c77b82a3cc1745fdd60583 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 15:43:28 -0500 Subject: [PATCH 40/59] - --- src/main/scala/ContextQueries1.scala | 14 +++--- src/main/scala/EnumTypes.scala | 1 + src/main/scala/OpaqueTypes.scala | 66 ---------------------------- src/main/scala/OpaqueTypes1.scala | 32 ++++++++++++++ src/main/scala/OpaqueTypes2.scala | 33 ++++++++++++++ 5 files changed, 74 insertions(+), 72 deletions(-) delete mode 100644 src/main/scala/OpaqueTypes.scala create mode 100644 src/main/scala/OpaqueTypes1.scala create mode 100644 src/main/scala/OpaqueTypes2.scala diff --git a/src/main/scala/ContextQueries1.scala b/src/main/scala/ContextQueries1.scala index 2f124d6..7242732 100644 --- a/src/main/scala/ContextQueries1.scala +++ b/src/main/scala/ContextQueries1.scala @@ -3,8 +3,10 @@ import scala.concurrent.{ExecutionContext, Future} import scala.util.Try /** Context Queries (Formerly known as Implicit Function Types): + * - Implicit functions are functions that only have implicit parameters. + * - Their types are implicit function types. * - http://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html, - * - https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ + * - Old syntax: https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ object ContextQueries1 extends App { object context { // type alias Contextual @@ -14,7 +16,7 @@ object ContextQueries1 extends App { def asyncSum(x: Int, y: Int): Contextual[Future[Int]] = Future(x + y) def asyncMult(x: Int, y: Int) - (given ctx: ExecutionContext) = Future(x * y) + (given ctx: ExecutionContext): Contextual[Future[Int]] = Future(x * y) } object parse { @@ -35,11 +37,11 @@ object ContextQueries1 extends App { def test: Unit = { import ExecutionContext.Implicits.global - context.asyncSum(3, 4).foreach(println) - context.asyncMult(3, 4).foreach(println) + context.asyncSum(3, 4).foreach(x => println("asyncSum: " + x)) + context.asyncMult(3, 4).foreach(x => println("asyncMult: " + x)) - println(parse.sumStrings("3", "4")) - println(parse.sumStrings("3", "a")) + println("""parse.sumStrings("3", "4"): """ + parse.sumStrings("3", "4")) + println("""parse.sumStrings("3", "a"): """ + parse.sumStrings("3", "a")) } test diff --git a/src/main/scala/EnumTypes.scala b/src/main/scala/EnumTypes.scala index 042d8f4..139e8e0 100644 --- a/src/main/scala/EnumTypes.scala +++ b/src/main/scala/EnumTypes.scala @@ -8,6 +8,7 @@ object EnumTypes extends App { case Empty } + /** This looks a lot like the [old Java enum example](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html) */ enum Planet(mass: Double, radius: Double) { private final val G = 6.67300E-11 diff --git a/src/main/scala/OpaqueTypes.scala b/src/main/scala/OpaqueTypes.scala deleted file mode 100644 index c099183..0000000 --- a/src/main/scala/OpaqueTypes.scala +++ /dev/null @@ -1,66 +0,0 @@ -/** Opaque types aliases provide type abstraction without *any* runtime overhead. - * Replace Scala 2 value types - * See https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html */ -object OpaqueTypes1 extends App { - object Logarithms { - opaque type Logarithm = Double - - object Logarithm { - // These are the ways to lift to the logarithm type - def apply(d: Double): Logarithm = math.log(d) - - def safe(d: Double): Option[Logarithm] = - if (d > 0.0) Some(math.log(d)) else None - } - - // Extension methods define opaque types' public APIs - given logarithmOps: { - def (x: Logarithm) toDouble: Double = math.exp(x) - def (x: Logarithm) + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) - def (x: Logarithm) * (y: Logarithm): Logarithm = Logarithm(x + y) - } - } - - def test: Unit = { - import Logarithms._ - - println("Logarithm(1.0) * Logarithm(2.0): " + (Logarithm(1.0) * Logarithm(2.0))) - println("Logarithm(1.0) + Logarithm(2.0): " + (Logarithm(1.0) + Logarithm(2.0))) - } - - test -} - -object OpaqueTypes2 extends App { - object Access { - opaque type Permissions = Int - opaque type PermissionChoice = Int - - /** `Permission`'s upper bound is `Permissions & PermissionChoice`. - * Thus `Permission` is universally known to be a subtype of `Permissions` and `PermissionChoice`. */ - opaque type Permission <: Permissions & PermissionChoice = Int - - def (x: Permissions) & (y: Permissions): Permissions = x & y - def (x: PermissionChoice) | (y: PermissionChoice): PermissionChoice = x | y - def (x: Permissions) is (y: Permissions) = (x & y) == y - def (x: Permissions) isOneOf (y: PermissionChoice) = (x & y) != 0 - - val NoPermission: Permission = 0 - val ReadOnly: Permission = 1 - val WriteOnly: Permission = 2 - val ReadWrite: Permissions = ReadOnly | WriteOnly - val ReadOrWrite: PermissionChoice = ReadOnly | WriteOnly - } - - def test: Unit = { - import Access._ - - case class Item(rights: Permissions) - - val x = Item(ReadOnly) - assert( ! x.rights.is(ReadWrite) ) - assert( x.rights.isOneOf(ReadOrWrite) ) - } - - test -} diff --git a/src/main/scala/OpaqueTypes1.scala b/src/main/scala/OpaqueTypes1.scala new file mode 100644 index 0000000..6ec2bcc --- /dev/null +++ b/src/main/scala/OpaqueTypes1.scala @@ -0,0 +1,32 @@ +/** Opaque types aliases provide type abstraction without *any* runtime overhead. + * They replace Scala 2 value types. + * See https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html */ +object OpaqueTypes1 extends App { + object Logarithms { + opaque type Logarithm = Double + + object Logarithm { + // These are the ways to lift to the logarithm type + def apply(d: Double): Logarithm = math.log(d) + + def safe(d: Double): Option[Logarithm] = + if (d > 0.0) Some(math.log(d)) else None + } + + // Extension methods define opaque types' public APIs + given logarithmOps: { + def (x: Logarithm) toDouble: Double = math.exp(x) + def (x: Logarithm) + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) + def (x: Logarithm) * (y: Logarithm): Logarithm = Logarithm(x + y) + } + } + + def test: Unit = { + import Logarithms._ + + println("Logarithm(1.0) * Logarithm(2.0): " + (Logarithm(1.0) * Logarithm(2.0))) + println("Logarithm(1.0) + Logarithm(2.0): " + (Logarithm(1.0) + Logarithm(2.0))) + } + + test +} diff --git a/src/main/scala/OpaqueTypes2.scala b/src/main/scala/OpaqueTypes2.scala new file mode 100644 index 0000000..1e81fcf --- /dev/null +++ b/src/main/scala/OpaqueTypes2.scala @@ -0,0 +1,33 @@ +object OpaqueTypes2 extends App { + object Access { + opaque type Permissions = Int + opaque type PermissionChoice = Int + + /** `Permission`'s upper bound is `Permissions & PermissionChoice`. + * Thus `Permission` is universally known to be a subtype of `Permissions` and `PermissionChoice`. */ + opaque type Permission <: Permissions & PermissionChoice = Int + + def (x: Permissions) & (y: Permissions): Permissions = x & y + def (x: PermissionChoice) | (y: PermissionChoice): PermissionChoice = x | y + def (x: Permissions) is (y: Permissions) = (x & y) == y + def (x: Permissions) isOneOf (y: PermissionChoice) = (x & y) != 0 + + val NoPermission: Permission = 0 + val ReadOnly: Permission = 1 + val WriteOnly: Permission = 2 + val ReadWrite: Permissions = ReadOnly | WriteOnly + val ReadOrWrite: PermissionChoice = ReadOnly | WriteOnly + } + + def test: Unit = { + import Access._ + + case class Item(rights: Permissions) + + val x = Item(ReadOnly) + assert( ! x.rights.is(ReadWrite) ) + assert( x.rights.isOneOf(ReadOrWrite) ) + } + + test +} From 60aac65e2397b536f1e563f06dc6ac639a71a0ef Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 15:47:52 -0500 Subject: [PATCH 41/59] - --- src/main/scala/ContextQueries1.scala | 4 ++-- src/main/scala/{ImpliedInstances.scala => Delegates.scala} | 6 +++--- src/main/scala/Main.scala | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/main/scala/{ImpliedInstances.scala => Delegates.scala} (89%) diff --git a/src/main/scala/ContextQueries1.scala b/src/main/scala/ContextQueries1.scala index 7242732..7eba54d 100644 --- a/src/main/scala/ContextQueries1.scala +++ b/src/main/scala/ContextQueries1.scala @@ -20,10 +20,10 @@ object ContextQueries1 extends App { } object parse { - type Parseable[T] = (given ImpliedInstances.StringParser[T]) => Try[T] + type Parseable[T] = (given Delegates.StringParser[T]) => Try[T] def sumStrings(x: String, y: String): Parseable[Int] = { - val parser = implicitly[ImpliedInstances.StringParser[Int]] + val parser = implicitly[Delegates.StringParser[Int]] val tryA = parser.parse(x) val tryB = parser.parse(y) diff --git a/src/main/scala/ImpliedInstances.scala b/src/main/scala/Delegates.scala similarity index 89% rename from src/main/scala/ImpliedInstances.scala rename to src/main/scala/Delegates.scala index 9cdcd8f..89bc7f9 100644 --- a/src/main/scala/ImpliedInstances.scala +++ b/src/main/scala/Delegates.scala @@ -1,8 +1,8 @@ import scala.util.{Success, Try} -/** Implied Instances: - * - https://dotty.epfl.ch/docs/reference/contextual/instance-defs.html */ -object ImpliedInstances extends App { +/** Delegates (Implied Instances): + * - https://dotty.epfl.ch/docs/reference/contextual/delegates.html*/ +object Delegates extends App { sealed trait StringParser[A] { def parse(s: String): Try[A] } diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 951df2d..c63ee66 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -3,13 +3,13 @@ object Main { runExample("Trait Params")(TraitParams.test) runExample("Typeclasses")(Typeclasses.test) runExample("OpaqueTypes 1")(OpaqueTypes1.test) + runExample("Delegates")(Delegates.test) runExample("Context Queries 1")(ContextQueries1.test) runExample("Intersection Types")(IntersectionTypes.test) runExample("Context Queries 2")(ContextQueries2.test) runExample("OpaqueTypes 2")(OpaqueTypes2.test) runExample("Type Lambda")(TypeLambdas.test) runExample("Enum Types")(EnumTypes.test) - runExample("Implied Instances")(ImpliedInstances.test) runExample("Conversion")(Conversion.test) runExample("Multiversal Equality")(MultiversalEquality.test) runExample("Named Type Arguments")(NamedTypeArguments.test) From 849bc0382daf33f3be42b70670ecb31388e421ac Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Tue, 26 Nov 2019 15:52:08 -0500 Subject: [PATCH 42/59] - --- src/main/scala/Delegates.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/Delegates.scala b/src/main/scala/Delegates.scala index 89bc7f9..ae5ee84 100644 --- a/src/main/scala/Delegates.scala +++ b/src/main/scala/Delegates.scala @@ -1,6 +1,6 @@ import scala.util.{Success, Try} -/** Delegates (Implied Instances): +/** Delegates (formerly known as Implied Instances): * - https://dotty.epfl.ch/docs/reference/contextual/delegates.html*/ object Delegates extends App { sealed trait StringParser[A] { From 0ecd5a2c2cd5b95b91fb0e64e3f652d3f0eb40f5 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 11:47:40 -0500 Subject: [PATCH 43/59] - --- src/main/scala/Main.scala | 1 + src/main/scala/SyntaxNew.scala | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/main/scala/SyntaxNew.scala diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index c63ee66..c77be2c 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,5 +1,6 @@ object Main { def main(args: Array[String]): Unit = { + runExample("New Syntax")(SyntaxNew) runExample("Trait Params")(TraitParams.test) runExample("Typeclasses")(Typeclasses.test) runExample("OpaqueTypes 1")(OpaqueTypes1.test) diff --git a/src/main/scala/SyntaxNew.scala b/src/main/scala/SyntaxNew.scala new file mode 100644 index 0000000..f70d55e --- /dev/null +++ b/src/main/scala/SyntaxNew.scala @@ -0,0 +1,28 @@ +@main def SyntaxNew = + println("Hello from SyntaxNew") + + def test: Unit = + val xs = 0 to 3 + val xsFiltered = for x <- xs if x > 1 yield x + for + x <- xsFiltered + y <- xsFiltered + do println(s"$x * $y = ${x * y}") + + test + +/** To run, type `runMain testIf Monday` */ +@main def testIf(day: String) = + if day == "Sunday" || day == "Saturday" + then println("Today is a weekend, hooray!") + else println(s"Today is a workday.") + + /** To run, type `runMain testWhile 3` */ +@main def testWhile(bound: Int) = + var x = 0 + + def incrementX() = + x += 1 + println(x) + + while x <= bound do incrementX() From 90332ac9bd9af28866d58e2cb2756adfc9ae03f8 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 11:48:59 -0500 Subject: [PATCH 44/59] - --- src/main/scala/SyntaxNew.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/SyntaxNew.scala b/src/main/scala/SyntaxNew.scala index f70d55e..48dcc7a 100644 --- a/src/main/scala/SyntaxNew.scala +++ b/src/main/scala/SyntaxNew.scala @@ -1,3 +1,5 @@ +/** See https://dotty.epfl.ch/blog/2019/08/30/18th-dotty-milestone-release.html */ + @main def SyntaxNew = println("Hello from SyntaxNew") From e80c0e47a7dac3d93d6161ca2f1fae853695f508 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:27:06 -0500 Subject: [PATCH 45/59] - --- README.md | 2 +- project/build.properties | 2 ++ src/main/scala/Delegates.scala | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b7acf56..a02223b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Example sbt Project that Compiles Using Dotty -I (Mike Slinn) fixed many significant bugs in the [upstream project](https://github.com/lampepfl/dotty-example-project) and added code examples for new major features that were missing. +I (Mike Slinn, founder of [ScalaCourses.com](https://www.ScalaCourses.com)) fixed many significant bugs in the [upstream project](https://github.com/lampepfl/dotty-example-project) and added code examples for new major features that were missing. ## Usage diff --git a/project/build.properties b/project/build.properties index c0bab04..4da2902 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1,3 @@ +# Sbt versions older than 1.1.4 are not supported with Dotty. +# Sbt versions 1.3.3 and 1.3.4 do not work properly with Dotty. sbt.version=1.2.8 diff --git a/src/main/scala/Delegates.scala b/src/main/scala/Delegates.scala index ae5ee84..7b280fa 100644 --- a/src/main/scala/Delegates.scala +++ b/src/main/scala/Delegates.scala @@ -1,7 +1,8 @@ import scala.util.{Success, Try} /** Delegates (formerly known as Implied Instances): - * - https://dotty.epfl.ch/docs/reference/contextual/delegates.html*/ + * - https://dotty.epfl.ch/docs/reference/contextual/delegates.html + * - https://dotty.epfl.ch/docs/reference/contextual/derivation.html*/ object Delegates extends App { sealed trait StringParser[A] { def parse(s: String): Try[A] From 0691fee897622954c6fe41bd89be78af9393e72a Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:31:15 -0500 Subject: [PATCH 46/59] - --- src/main/scala/SyntaxNew.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/SyntaxNew.scala b/src/main/scala/SyntaxNew.scala index 48dcc7a..8e4ced0 100644 --- a/src/main/scala/SyntaxNew.scala +++ b/src/main/scala/SyntaxNew.scala @@ -1,4 +1,5 @@ -/** See https://dotty.epfl.ch/blog/2019/08/30/18th-dotty-milestone-release.html */ +/** The new and old syntaxes can be mixed freely in one file. + * See https://dotty.epfl.ch/blog/2019/08/30/18th-dotty-milestone-release.html */ @main def SyntaxNew = println("Hello from SyntaxNew") From 7e20fff609df423b25a98cb51785b3c991363b26 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:34:27 -0500 Subject: [PATCH 47/59] - --- src/main/scala/Main.scala | 52 ++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index c77be2c..c1882a2 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,29 +1,25 @@ -object Main { - def main(args: Array[String]): Unit = { - runExample("New Syntax")(SyntaxNew) - runExample("Trait Params")(TraitParams.test) - runExample("Typeclasses")(Typeclasses.test) - runExample("OpaqueTypes 1")(OpaqueTypes1.test) - runExample("Delegates")(Delegates.test) - runExample("Context Queries 1")(ContextQueries1.test) - runExample("Intersection Types")(IntersectionTypes.test) - runExample("Context Queries 2")(ContextQueries2.test) - runExample("OpaqueTypes 2")(OpaqueTypes2.test) - runExample("Type Lambda")(TypeLambdas.test) - runExample("Enum Types")(EnumTypes.test) - runExample("Conversion")(Conversion.test) - runExample("Multiversal Equality")(MultiversalEquality.test) - runExample("Named Type Arguments")(NamedTypeArguments.test) - runExample("Auto Param Tupling")(AutoParamTupling.test) - runExample("Structural Types")(StructuralTypes.test) - runExample("Pattern Matching")(PatternMatching.test) - runExample("Union Types")(UnionTypes.test) - } +@main def Main = + runExample("New Syntax")(SyntaxNew) + runExample("Trait Params")(TraitParams.test) + runExample("Typeclasses")(Typeclasses.test) + runExample("OpaqueTypes 1")(OpaqueTypes1.test) + runExample("Delegates")(Delegates.test) + runExample("Context Queries 1")(ContextQueries1.test) + runExample("Intersection Types")(IntersectionTypes.test) + runExample("Context Queries 2")(ContextQueries2.test) + runExample("OpaqueTypes 2")(OpaqueTypes2.test) + runExample("Type Lambda")(TypeLambdas.test) + runExample("Enum Types")(EnumTypes.test) + runExample("Conversion")(Conversion.test) + runExample("Multiversal Equality")(MultiversalEquality.test) + runExample("Named Type Arguments")(NamedTypeArguments.test) + runExample("Auto Param Tupling")(AutoParamTupling.test) + runExample("Structural Types")(StructuralTypes.test) + runExample("Pattern Matching")(PatternMatching.test) + runExample("Union Types")(UnionTypes.test) - private def runExample(name: String) - (f: => Unit) = { - println(Console.MAGENTA + s"$name example:" + Console.RESET) - f - println() - } -} +private def runExample(name: String) + (f: => Unit) = + println(Console.MAGENTA + s"$name example:" + Console.RESET) + f + println() From a306cccb7b718994ec30f9852308da0b28d5ee61 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:37:46 -0500 Subject: [PATCH 48/59] - --- src/main/scala/AutoParamTupling.scala | 8 +++----- src/main/scala/ContextQueries1.scala | 12 ++++-------- src/main/scala/Main.scala | 4 ++-- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/main/scala/AutoParamTupling.scala b/src/main/scala/AutoParamTupling.scala index 18825f6..30ec2a3 100644 --- a/src/main/scala/AutoParamTupling.scala +++ b/src/main/scala/AutoParamTupling.scala @@ -1,16 +1,14 @@ /** Automatic Tupling of Function Params: https://dotty.epfl.ch/docs/reference/other-new-features/auto-parameter-tupling.html */ -object AutoParamTupling extends App { - def test: Unit = { +@main def AutoParamTupling = + def test: Unit = /** In order to get thread safety, you need to put @volatile before lazy vals. * https://dotty.epfl.ch/docs/reference/changed-features/lazy-vals.html */ @volatile lazy val xs: List[String] = List("d", "o", "t", "t", "y") - /** Current behaviour in Scala 2.12.2 : + /** Current behaviour in Scala 2.12 : * error: missing parameter type * Note: The expected type requires a one-argument function accepting a 2-Tuple. * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` */ xs.zipWithIndex.map((s, i) => println(s"$i: $s")) - } test -} diff --git a/src/main/scala/ContextQueries1.scala b/src/main/scala/ContextQueries1.scala index 7eba54d..b60674e 100644 --- a/src/main/scala/ContextQueries1.scala +++ b/src/main/scala/ContextQueries1.scala @@ -7,8 +7,8 @@ import scala.util.Try * - Their types are implicit function types. * - http://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html, * - Old syntax: https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html */ -object ContextQueries1 extends App { - object context { +@main def ContextQueries1 = + object context with // type alias Contextual type Contextual[T] = (given ExecutionContext) => T @@ -17,9 +17,8 @@ object ContextQueries1 extends App { def asyncMult(x: Int, y: Int) (given ctx: ExecutionContext): Contextual[Future[Int]] = Future(x * y) - } - object parse { + object parse with type Parseable[T] = (given Delegates.StringParser[T]) => Try[T] def sumStrings(x: String, y: String): Parseable[Int] = { @@ -32,9 +31,8 @@ object ContextQueries1 extends App { b <- tryB } yield a + b } - } - def test: Unit = { + def test: Unit = import ExecutionContext.Implicits.global context.asyncSum(3, 4).foreach(x => println("asyncSum: " + x)) @@ -42,7 +40,5 @@ object ContextQueries1 extends App { println("""parse.sumStrings("3", "4"): """ + parse.sumStrings("3", "4")) println("""parse.sumStrings("3", "a"): """ + parse.sumStrings("3", "a")) - } test -} diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index c1882a2..be3c7fa 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -4,7 +4,7 @@ runExample("Typeclasses")(Typeclasses.test) runExample("OpaqueTypes 1")(OpaqueTypes1.test) runExample("Delegates")(Delegates.test) - runExample("Context Queries 1")(ContextQueries1.test) + runExample("Context Queries 1")(ContextQueries1) runExample("Intersection Types")(IntersectionTypes.test) runExample("Context Queries 2")(ContextQueries2.test) runExample("OpaqueTypes 2")(OpaqueTypes2.test) @@ -13,7 +13,7 @@ runExample("Conversion")(Conversion.test) runExample("Multiversal Equality")(MultiversalEquality.test) runExample("Named Type Arguments")(NamedTypeArguments.test) - runExample("Auto Param Tupling")(AutoParamTupling.test) + runExample("Automatic Functional Parameter Tupling")(AutoParamTupling) runExample("Structural Types")(StructuralTypes.test) runExample("Pattern Matching")(PatternMatching.test) runExample("Union Types")(UnionTypes.test) From ad71ce3fca24e8ef879c4e9451e4859dd185b2c3 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:48:06 -0500 Subject: [PATCH 49/59] - --- src/main/scala/ContextQueries2.scala | 14 ++++++-------- src/main/scala/Main.scala | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/scala/ContextQueries2.scala b/src/main/scala/ContextQueries2.scala index d39e671..fd3fe8e 100644 --- a/src/main/scala/ContextQueries2.scala +++ b/src/main/scala/ContextQueries2.scala @@ -1,7 +1,7 @@ /** This example combines opaque aliases, implicit function types, and extension methods to provide * a zero-overhead abstraction at runtime. * See http://dotty.epfl.ch/docs/reference/contextual/implicit-function-types.html#example-postconditions */ -object PostConditions { +object PostConditions opaque type WrappedResult[T] = T def result[T](given r: WrappedResult[T]): T = r @@ -11,17 +11,15 @@ object PostConditions { * The given `WrappedResult` instance is passed to the result method. * `WrappedResult` is an opaque type alias, so its values need not be boxed or unboxed. * Because `ensuring` is added as an extension method, its argument also does not need boxing. */ - def [T](x: T) ensuring(condition: (given WrappedResult[T]) => Boolean): T = { + def [T](x: T) ensuring(condition: (given WrappedResult[T]) => Boolean): T = assert(condition(given x)) x - } -} -object ContextQueries2 extends App { +@main def ContextQueries2 = import PostConditions.{ensuring, result} - def test: Unit = { + def test: Unit = val s = List(1, 2, 3).sum.ensuring(result == 6) println("Yes, the list sums to 6.") - } -} + + test diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index be3c7fa..64af6f5 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -6,7 +6,7 @@ runExample("Delegates")(Delegates.test) runExample("Context Queries 1")(ContextQueries1) runExample("Intersection Types")(IntersectionTypes.test) - runExample("Context Queries 2")(ContextQueries2.test) + runExample("Context Queries 2")(ContextQueries2) runExample("OpaqueTypes 2")(OpaqueTypes2.test) runExample("Type Lambda")(TypeLambdas.test) runExample("Enum Types")(EnumTypes.test) From 0c21c60568d42091794637f00a34815c9227469c Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:50:31 -0500 Subject: [PATCH 50/59] - --- src/main/scala/Delegates.scala | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/scala/Delegates.scala b/src/main/scala/Delegates.scala index 7b280fa..4403f97 100644 --- a/src/main/scala/Delegates.scala +++ b/src/main/scala/Delegates.scala @@ -3,12 +3,11 @@ import scala.util.{Success, Try} /** Delegates (formerly known as Implied Instances): * - https://dotty.epfl.ch/docs/reference/contextual/delegates.html * - https://dotty.epfl.ch/docs/reference/contextual/derivation.html*/ -object Delegates extends App { - sealed trait StringParser[A] { +object Delegates with + sealed trait StringParser[A] def parse(s: String): Try[A] - } - object StringParser { + object StringParser with def apply[A](given parser: StringParser[A]): StringParser[A] = parser private def baseParser[A](f: String ⇒ Try[A]): StringParser[A] = @@ -21,20 +20,16 @@ object Delegates extends App { given optionParser[A](given parser: => StringParser[A]): StringParser[Option[A]] = new StringParser[Option[A]] { - override def parse(s: String): Try[Option[A]] = s match { + override def parse(s: String): Try[Option[A]] = s match case "" ⇒ Success(None) // implicit parser not used. case str ⇒ parser.parse(str).map(Some(_)) // implicit parser is evaluated here - } } - } - def test: Unit = { + def test: Unit = val spoi = implicitly[StringParser[Option[Int]]] println(spoi.parse("21")) println(spoi.parse("")) println(spoi.parse("21a")) println(StringParser.optionParser[Int].parse("42")) - } test -} From 406166a6c7b9ed7fe8f4146262e1b19ba9f75569 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:54:08 -0500 Subject: [PATCH 51/59] - --- src/main/scala/EnumTypes.scala | 15 +++++---------- src/main/scala/Main.scala | 6 +++--- src/main/scala/MultiversalEquality.scala | 7 ++----- src/main/scala/NamedTypeArguments.scala | 12 ++++-------- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/main/scala/EnumTypes.scala b/src/main/scala/EnumTypes.scala index 139e8e0..9b5ceae 100644 --- a/src/main/scala/EnumTypes.scala +++ b/src/main/scala/EnumTypes.scala @@ -2,14 +2,13 @@ * * Interoperate with Java enums * * Support Algebraic Data Types (ADTs) because they accept type parameters, and can be Generalized ADTs (GADTs). * See http://dotty.epfl.ch/docs/reference/enums/adts.html */ -object EnumTypes extends App { - enum ListEnum[+A] { +@main def EnumTypes = + enum ListEnum[+A] case Cons(h: A, t: ListEnum[A]) case Empty - } /** This looks a lot like the [old Java enum example](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html) */ - enum Planet(mass: Double, radius: Double) { + enum Planet(mass: Double, radius: Double) with private final val G = 6.67300E-11 def surfaceGravity = G * mass / (radius * radius) @@ -24,23 +23,19 @@ object EnumTypes extends App { 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) - } - def test: Unit = { + def test: Unit = val emptyList = ListEnum.Empty val list = ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) println(emptyList) println(s"$list\n") - def calculateEarthWeightOnPlanets(earthWeight: Double): Unit = { + def calculateEarthWeightOnPlanets(earthWeight: Double): Unit = val mass = earthWeight/Planet.Earth.surfaceGravity for (p <- Planet.values) println(s"Your weight on $p is ${p.surfaceWeight(mass)}") () - } calculateEarthWeightOnPlanets(80) - } test -} diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 64af6f5..8b53e51 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -9,10 +9,10 @@ runExample("Context Queries 2")(ContextQueries2) runExample("OpaqueTypes 2")(OpaqueTypes2.test) runExample("Type Lambda")(TypeLambdas.test) - runExample("Enum Types")(EnumTypes.test) + runExample("Enum Types")(EnumTypes) runExample("Conversion")(Conversion.test) - runExample("Multiversal Equality")(MultiversalEquality.test) - runExample("Named Type Arguments")(NamedTypeArguments.test) + runExample("Multiversal Equality")(MultiversalEquality) + runExample("Named Type Arguments")(NamedTypeArguments) runExample("Automatic Functional Parameter Tupling")(AutoParamTupling) runExample("Structural Types")(StructuralTypes.test) runExample("Pattern Matching")(PatternMatching.test) diff --git a/src/main/scala/MultiversalEquality.scala b/src/main/scala/MultiversalEquality.scala index df317d4..056e50e 100644 --- a/src/main/scala/MultiversalEquality.scala +++ b/src/main/scala/MultiversalEquality.scala @@ -4,9 +4,8 @@ import scala.language.strictEquality * Multiversal Equality: https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html * scala.Eq definition: https://github.com/lampepfl/dotty/blob/master/library/src/scala/Eql.scala */ - object MultiversalEquality extends App { - - def test: Unit = { +@main def MultiversalEquality = + def test: Unit = // Values of types Int and String cannot be compared with == or !=, // unless we add the derived delegate instance like: given Eql[Int, String] = Eql.derived @@ -37,7 +36,5 @@ import scala.language.strictEquality println("a != b: " + (a != b)) println("b == a: " + (b == a)) - } test -} diff --git a/src/main/scala/NamedTypeArguments.scala b/src/main/scala/NamedTypeArguments.scala index bb7402f..4aa20e1 100644 --- a/src/main/scala/NamedTypeArguments.scala +++ b/src/main/scala/NamedTypeArguments.scala @@ -1,16 +1,14 @@ /** Named Type Arguments: https://dotty.epfl.ch/docs/reference/other-new-features/named-typeargs.html */ -object NamedTypeArguments extends App { - trait Functor[F[_]] { +@main def NamedTypeArguments = + trait Functor[F[_]] def map[A, B](fa: F[A]) (f: A => B): F[B] - } - implicit object listFunctor extends Functor[List] { + implicit object listFunctor extends Functor[List] with override def map[A, B](fa: List[A]) (f: A => B): List[B] = fa.map(f) - } - def test: Unit = { + def test: Unit = def fmap[F[_], A, B](fa: F[A]) (f: A => B) (implicit F: Functor[F]): F[B] = F.map(fa)(f) @@ -24,7 +22,5 @@ object NamedTypeArguments extends App { val compile: List[String] = fmap[F = List, B = String](List(1,2,3))(i => (i + 1).toString) println(compile) - } test -} From c183838546ed6908a2d1d418d96aa5a94a633366 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:56:26 -0500 Subject: [PATCH 52/59] - --- src/main/scala/Main.scala | 2 +- src/main/scala/OpaqueTypes1.scala | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 8b53e51..29c4840 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -2,7 +2,7 @@ runExample("New Syntax")(SyntaxNew) runExample("Trait Params")(TraitParams.test) runExample("Typeclasses")(Typeclasses.test) - runExample("OpaqueTypes 1")(OpaqueTypes1.test) + runExample("OpaqueTypes 1")(OpaqueTypes1) runExample("Delegates")(Delegates.test) runExample("Context Queries 1")(ContextQueries1) runExample("Intersection Types")(IntersectionTypes.test) diff --git a/src/main/scala/OpaqueTypes1.scala b/src/main/scala/OpaqueTypes1.scala index 6ec2bcc..dd65488 100644 --- a/src/main/scala/OpaqueTypes1.scala +++ b/src/main/scala/OpaqueTypes1.scala @@ -1,32 +1,27 @@ /** Opaque types aliases provide type abstraction without *any* runtime overhead. * They replace Scala 2 value types. * See https://dotty.epfl.ch/docs/reference/other-new-features/opaques.html */ -object OpaqueTypes1 extends App { - object Logarithms { +@main def OpaqueTypes1 = + object Logarithms with opaque type Logarithm = Double - object Logarithm { + object Logarithm with // These are the ways to lift to the logarithm type def apply(d: Double): Logarithm = math.log(d) def safe(d: Double): Option[Logarithm] = if (d > 0.0) Some(math.log(d)) else None - } // Extension methods define opaque types' public APIs - given logarithmOps: { + given logarithmOps: with def (x: Logarithm) toDouble: Double = math.exp(x) def (x: Logarithm) + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) def (x: Logarithm) * (y: Logarithm): Logarithm = Logarithm(x + y) - } - } - def test: Unit = { + def test: Unit = import Logarithms._ println("Logarithm(1.0) * Logarithm(2.0): " + (Logarithm(1.0) * Logarithm(2.0))) println("Logarithm(1.0) + Logarithm(2.0): " + (Logarithm(1.0) + Logarithm(2.0))) - } test -} From cb20d0d54aa316aee89f3ed31849d9791fc2e93c Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 13:59:33 -0500 Subject: [PATCH 53/59] - --- src/main/scala/Main.scala | 4 +-- src/main/scala/OpaqueTypes2.scala | 9 ++---- src/main/scala/PatternMatching.scala | 46 +++++++++------------------- 3 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 29c4840..28f24d8 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -7,7 +7,7 @@ runExample("Context Queries 1")(ContextQueries1) runExample("Intersection Types")(IntersectionTypes.test) runExample("Context Queries 2")(ContextQueries2) - runExample("OpaqueTypes 2")(OpaqueTypes2.test) + runExample("OpaqueTypes 2")(OpaqueTypes2) runExample("Type Lambda")(TypeLambdas.test) runExample("Enum Types")(EnumTypes) runExample("Conversion")(Conversion.test) @@ -15,7 +15,7 @@ runExample("Named Type Arguments")(NamedTypeArguments) runExample("Automatic Functional Parameter Tupling")(AutoParamTupling) runExample("Structural Types")(StructuralTypes.test) - runExample("Pattern Matching")(PatternMatching.test) + runExample("Pattern Matching")(PatternMatching) runExample("Union Types")(UnionTypes.test) private def runExample(name: String) diff --git a/src/main/scala/OpaqueTypes2.scala b/src/main/scala/OpaqueTypes2.scala index 1e81fcf..fc120b5 100644 --- a/src/main/scala/OpaqueTypes2.scala +++ b/src/main/scala/OpaqueTypes2.scala @@ -1,5 +1,5 @@ -object OpaqueTypes2 extends App { - object Access { +@main def OpaqueTypes2 = + object Access with opaque type Permissions = Int opaque type PermissionChoice = Int @@ -17,9 +17,8 @@ object OpaqueTypes2 extends App { val WriteOnly: Permission = 2 val ReadWrite: Permissions = ReadOnly | WriteOnly val ReadOrWrite: PermissionChoice = ReadOnly | WriteOnly - } - def test: Unit = { + def test: Unit = import Access._ case class Item(rights: Permissions) @@ -27,7 +26,5 @@ object OpaqueTypes2 extends App { val x = Item(ReadOnly) assert( ! x.rights.is(ReadWrite) ) assert( x.rights.isOneOf(ReadOrWrite) ) - } test -} diff --git a/src/main/scala/PatternMatching.scala b/src/main/scala/PatternMatching.scala index f126eb2..df8fd2c 100644 --- a/src/main/scala/PatternMatching.scala +++ b/src/main/scala/PatternMatching.scala @@ -1,13 +1,11 @@ /** Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html */ -object PatternMatching extends App { - object booleanPattern { - object Even { +@main def PatternMatching = + object booleanPattern with + object Even with def unapply(s: String): Boolean = s.length % 2 == 0 - } - } - object productPattern { - class Person(name: String, age: Int) extends Product { + object productPattern with + class Person(name: String, age: Int) extends Product // if we not define that, it will give compile error. // we change the order def _1 = age @@ -17,35 +15,25 @@ object PatternMatching extends App { def canEqual(that: Any): Boolean = ??? def productArity: Int = ??? def productElement(n: Int): Any = ??? - } - object Person { + object Person with def unapply(a: (String, Int)): Person = new Person(a._1, a._2) - } - } - object seqPattern { + object seqPattern with // adapted from http://danielwestheide.com/blog/2012/11/28/the-neophytes-guide-to-scala-part-2-extracting-sequences.html - object Names { - def unapplySeq(name: String): Option[Seq[String]] = { + object Names with + def unapplySeq(name: String): Option[Seq[String]] = val names = name.trim.split(" ") if (names.size < 2) None else Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) - } - } - - } - object namePattern { - class Name(val name: String) { + object namePattern with + class Name(val name: String) def get: String = name def isEmpty = name.isEmpty - } - object Name { + object Name with def unapply(s: String): Name = new Name(s) - } - } def test: Unit = { import booleanPattern._ @@ -66,27 +54,23 @@ object PatternMatching extends App { println(containsConsecutive(List(1, 2, 3, 3, 5))) import productPattern._ - ("john", 42) match { + ("john", 42) match case Person(n, a) => println(s"name: $n, age: $a") - } import seqPattern._ - def greet(fullName: String) = fullName match { + def greet(fullName: String) = fullName match case Names(lastName, firstName, _: _*) => "Good morning, " + firstName + " " + lastName + "!" case _ => "Welcome! Please make sure to fill in your name!" - } println(greet("Alan Turing")) println(greet("john")) println(greet("Wolfgang Amadeus Mozart")) import namePattern._ - "alice" match { + "alice" match case Name(n) => println(s"name is $n") case _ => println("empty name") - } } test -} From 5e33baf909e3f4ff38e26d0bbc31ab3496836a52 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 14:01:58 -0500 Subject: [PATCH 54/59] - --- src/main/scala/Main.scala | 4 ++-- src/main/scala/StructuralTypes.scala | 12 ++++-------- src/main/scala/TraitParams.scala | 10 ++++------ 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 28f24d8..75c136b 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,6 +1,6 @@ @main def Main = runExample("New Syntax")(SyntaxNew) - runExample("Trait Params")(TraitParams.test) + runExample("Trait Params")(TraitParams) runExample("Typeclasses")(Typeclasses.test) runExample("OpaqueTypes 1")(OpaqueTypes1) runExample("Delegates")(Delegates.test) @@ -14,7 +14,7 @@ runExample("Multiversal Equality")(MultiversalEquality) runExample("Named Type Arguments")(NamedTypeArguments) runExample("Automatic Functional Parameter Tupling")(AutoParamTupling) - runExample("Structural Types")(StructuralTypes.test) + runExample("Structural Types")(StructuralTypes) runExample("Pattern Matching")(PatternMatching) runExample("Union Types")(UnionTypes.test) diff --git a/src/main/scala/StructuralTypes.scala b/src/main/scala/StructuralTypes.scala index 2f46280..8f6c8bd 100644 --- a/src/main/scala/StructuralTypes.scala +++ b/src/main/scala/StructuralTypes.scala @@ -1,25 +1,21 @@ /** Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html */ -object StructuralTypes extends App { - case class Record(elems: (String, Any)*) extends Selectable { +@main def StructuralTypes = + case class Record(elems: (String, Any)*) extends Selectable def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2 - } - type Person = Record { + type Person = Record with val name: String val age: Int - } val person = Record("name" -> "Emma", "age" -> 42, "salary" -> 320L).asInstanceOf[Person] val invalidPerson = Record("name" -> "John", "salary" -> 42).asInstanceOf[Person] - def test: Unit = { + def test: Unit = println(person.name) println(person.age) println(invalidPerson.name) // age field is java.util.NoSuchElementException: None.get //println(invalidPerson.age) - } test -} diff --git a/src/main/scala/TraitParams.scala b/src/main/scala/TraitParams.scala index 6d17c9e..06c36e3 100644 --- a/src/main/scala/TraitParams.scala +++ b/src/main/scala/TraitParams.scala @@ -1,23 +1,21 @@ /** Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html */ -object TraitParams extends App { +@main def TraitParams = trait Base(val msg: String) class A extends Base("Hello") class B extends Base("Dotty") /** @param msgs varargs union type (sequence of A or B) */ - private def printMessages1(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") + def printMessages1(msgs: (A | B)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") case class C(override val msg: String) extends Base(msg) case class D(override val msg: String) extends Base(msg) - private def printMessages2(msgs: (C | D)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") + def printMessages2(msgs: (C | D)*): Unit = println(msgs.map(_.msg).mkString(" ") + "!") - def test: Unit = { + def test: Unit = printMessages1(new A, new B) printMessages2(C("Goodbye"), D("cruel world")) - } test -} From de3ab8a1da41c0bed5db979146dddd87bb5fc128 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 14:08:07 -0500 Subject: [PATCH 55/59] - --- src/main/scala/Conversion.scala | 27 ++++++++------------------- src/main/scala/Main.scala | 10 +++++----- src/main/scala/TypeLambdas.scala | 6 ++---- src/main/scala/Typeclasses.scala | 3 +-- src/main/scala/UnionTypes.scala | 14 +++++--------- 5 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/main/scala/Conversion.scala b/src/main/scala/Conversion.scala index ec65bca..686ec0e 100644 --- a/src/main/scala/Conversion.scala +++ b/src/main/scala/Conversion.scala @@ -1,35 +1,24 @@ import scala.language.implicitConversions -/** Conversions: http://dotty.epfl.ch/docs/reference/contextual/conversions.html */ -object Conversion extends App { - case class IntWrapper(a: Int) extends AnyVal - case class DoubleWrapper(b: Double) extends AnyVal +case class IntWrapper(a: Int) extends AnyVal +case class DoubleWrapper(b: Double) extends AnyVal +/** Conversions: http://dotty.epfl.ch/docs/reference/contextual/conversions.html */ +@main def Conversion = def convert[T, U](t: T) (given converter: Conversion[T, U]): U = converter(t) given IntWrapperToDoubleWrapper: Conversion[IntWrapper, DoubleWrapper] = - new Conversion[IntWrapper, DoubleWrapper] { + new Conversion[IntWrapper, DoubleWrapper] with override def apply(i: IntWrapper): DoubleWrapper = new DoubleWrapper(i.a.toDouble) - } - - def useConversion(given f: Conversion[IntWrapper, DoubleWrapper]) = { + + def useConversion(given f: Conversion[IntWrapper, DoubleWrapper]) = val y: IntWrapper = new IntWrapper(4) val x: DoubleWrapper = y x - } - - /* Not working anymore. - def useConversion(implicit f: A => B) = { - val y: A = ... - val x: B = a // error under Dotty - } - */ - def test: Unit = { + def test: Unit = println(useConversion) println(convert(new IntWrapper(42))) - } test -} diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 75c136b..7715c6c 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -1,22 +1,22 @@ @main def Main = runExample("New Syntax")(SyntaxNew) runExample("Trait Params")(TraitParams) - runExample("Typeclasses")(Typeclasses.test) + runExample("Typeclasses")(Typeclasses) runExample("OpaqueTypes 1")(OpaqueTypes1) runExample("Delegates")(Delegates.test) runExample("Context Queries 1")(ContextQueries1) - runExample("Intersection Types")(IntersectionTypes.test) + runExample("Intersection Types")(IntersectionTypes) runExample("Context Queries 2")(ContextQueries2) runExample("OpaqueTypes 2")(OpaqueTypes2) - runExample("Type Lambda")(TypeLambdas.test) + runExample("Type Lambda")(TypeLambdas) runExample("Enum Types")(EnumTypes) - runExample("Conversion")(Conversion.test) + runExample("Conversion")(Conversion) runExample("Multiversal Equality")(MultiversalEquality) runExample("Named Type Arguments")(NamedTypeArguments) runExample("Automatic Functional Parameter Tupling")(AutoParamTupling) runExample("Structural Types")(StructuralTypes) runExample("Pattern Matching")(PatternMatching) - runExample("Union Types")(UnionTypes.test) + runExample("Union Types")(UnionTypes) private def runExample(name: String) (f: => Unit) = diff --git a/src/main/scala/TypeLambdas.scala b/src/main/scala/TypeLambdas.scala index 32dd5c8..3de219f 100644 --- a/src/main/scala/TypeLambdas.scala +++ b/src/main/scala/TypeLambdas.scala @@ -1,16 +1,14 @@ /** Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html */ -object TypeLambdas extends App { +@main def TypeLambdas = type T[+X, Y] = Map[Y, X] type Tuple = [X] =>> (X, X) - def test: Unit = { + def test: Unit = val m: T[String, Int] = Map(1 -> "1") println(m) val tuple: Tuple[String] = ("a", "b") println(tuple) - } test -} diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 10dd307..307da9c 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -4,7 +4,7 @@ * * Better error messages than generated from implicits * * Implicit conversions will go away * See https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates */ -object Typeclasses extends App { +@main def Typeclasses = trait SemiGroup[T] with def (x: T) combine (y: T): T @@ -21,4 +21,3 @@ object Typeclasses extends App { def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) test -} diff --git a/src/main/scala/UnionTypes.scala b/src/main/scala/UnionTypes.scala index 52beebf..1e8c458 100644 --- a/src/main/scala/UnionTypes.scala +++ b/src/main/scala/UnionTypes.scala @@ -4,7 +4,7 @@ * * Works with singleton types * * Good for Scala/JavaScript interoperability * https://dotty.epfl.ch/docs/reference/new-types/union-types.html */ -object UnionTypes extends App { +@main def UnionTypes = sealed trait Division final case class DivisionByZero(msg: String) extends Division final case class Success(double: Double) extends Division @@ -14,19 +14,17 @@ object UnionTypes extends App { sealed trait List[+A] final case class Cons[+A](h: A, t: List[A]) extends List[A] - final class Empty extends List[Nothing] { + final class Empty extends List[Nothing] override def toString: String = "Empty" - } - private def safeDivide(a: Double, b: Double): DivisionResult = + def safeDivide(a: Double, b: Double): DivisionResult = if (b == 0) DivisionByZero("DivisionByZeroException") else Success(a / b) - private def either(division: Division) = division match { + def either(division: Division) = division match case DivisionByZero(m) => Left(m) case Success(d) => Right(d) - } - def test: Unit = { + def test: Unit = val divisionResultSuccess: DivisionResult = safeDivide(4, 2) // Commutative @@ -43,7 +41,5 @@ object UnionTypes extends App { val emptyList: Empty | Cons[Any] = Empty() println("emptyList: " + emptyList) - } test -} From 5cb4e2f1c4ab4ce7800ab5ed2f6b9a149cc59a99 Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 14:09:05 -0500 Subject: [PATCH 56/59] - --- src/main/scala/Main.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index 7715c6c..baa3839 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -3,7 +3,7 @@ runExample("Trait Params")(TraitParams) runExample("Typeclasses")(Typeclasses) runExample("OpaqueTypes 1")(OpaqueTypes1) - runExample("Delegates")(Delegates.test) + runExample("Delegates")(Delegates) runExample("Context Queries 1")(ContextQueries1) runExample("Intersection Types")(IntersectionTypes) runExample("Context Queries 2")(ContextQueries2) From d14cc128b29c16d1ecad6658e2ed399cd495488d Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Wed, 27 Nov 2019 14:28:46 -0500 Subject: [PATCH 57/59] - --- src/main/scala/Main.scala | 2 +- src/main/scala/Typeclasses.scala | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/Main.scala b/src/main/scala/Main.scala index baa3839..34a17c4 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/Main.scala @@ -8,7 +8,7 @@ runExample("Intersection Types")(IntersectionTypes) runExample("Context Queries 2")(ContextQueries2) runExample("OpaqueTypes 2")(OpaqueTypes2) - runExample("Type Lambda")(TypeLambdas) + runExample("Type Lambdas")(TypeLambdas) runExample("Enum Types")(EnumTypes) runExample("Conversion")(Conversion) runExample("Multiversal Equality")(MultiversalEquality) diff --git a/src/main/scala/Typeclasses.scala b/src/main/scala/Typeclasses.scala index 307da9c..fd0c876 100644 --- a/src/main/scala/Typeclasses.scala +++ b/src/main/scala/Typeclasses.scala @@ -18,6 +18,7 @@ def sum[T: Monoid](xs: List[T]): T = xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_)) - def test: Unit = println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) + def test: Unit = + println("""sum("a", "b", "c"): """ + sum(List("a", "b", "c"))) test From 641bfa6f2315f70d5ba22b775f0d496ca913d27e Mon Sep 17 00:00:00 2001 From: Mike Slinn Date: Thu, 28 Nov 2019 10:20:01 -0500 Subject: [PATCH 58/59] - --- src/main/scala/ContextQueries1.scala | 3 ++- src/main/scala/IntersectionTypes.scala | 20 +++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/main/scala/ContextQueries1.scala b/src/main/scala/ContextQueries1.scala index b60674e..049f33a 100644 --- a/src/main/scala/ContextQueries1.scala +++ b/src/main/scala/ContextQueries1.scala @@ -16,7 +16,8 @@ import scala.util.Try def asyncSum(x: Int, y: Int): Contextual[Future[Int]] = Future(x + y) def asyncMult(x: Int, y: Int) - (given ctx: ExecutionContext): Contextual[Future[Int]] = Future(x * y) + (given ctx: ExecutionContext): Contextual[Future[Int]] = + Future(x * y) object parse with type Parseable[T] = (given Delegates.StringParser[T]) => Try[T] diff --git a/src/main/scala/IntersectionTypes.scala b/src/main/scala/IntersectionTypes.scala index ceae350..6fd10d2 100644 --- a/src/main/scala/IntersectionTypes.scala +++ b/src/main/scala/IntersectionTypes.scala @@ -1,34 +1,28 @@ /** * Intersection Types: https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html */ -object IntersectionTypes extends App { - sealed trait X { +@main def IntersectionTypes = + sealed trait X def x: Double def tpe: X - } - sealed trait Y { + sealed trait Y def y: Double def tpe: Y - } // The compiler treats P and PP as equivalent and interchangeable types type P = Y & X type PP = X & Y - final case class Point(x: Double, y: Double) extends X with Y { - override def tpe: X & Y = ??? - } + final case class Point(x: Double, y: Double) extends X with Y + override def tpe: P = ??? - def test: Unit = { - def euclideanDistance(p1: P, p2: P) = { + def test: Unit = + def euclideanDistance(p1: P, p2: P) = Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) - } val p1: P = Point(3, 4) val p2: PP = Point(6, 8) println(euclideanDistance(p1, p2)) - } test -} From 5b27ab71ace8bf83b999630d3cf2d3c1dc27ae63 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Wed, 2 Dec 2020 12:57:45 +0100 Subject: [PATCH 59/59] Update sbt to 1.4.4 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 4da2902..cb23649 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1,3 +1,3 @@ # Sbt versions older than 1.1.4 are not supported with Dotty. # Sbt versions 1.3.3 and 1.3.4 do not work properly with Dotty. -sbt.version=1.2.8 +sbt.version=1.4.4