diff --git a/README.md b/README.md index cb032bba..9e4ded0b 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,8 @@ [![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org) * [Dean Wampler](mailto:programming.scala@gmail.com) -* [@deanwampler](https://twitter.com/deanwampler) -* [LinkedIn](https://www.linkedin.com/in/deanwampler/) -* [Book Page](http://programming-scala.org) +* Dean Wampler's [Bluesky](https://bsky.app/profile/deanwampler.bsky.social), [Mastodon](https://discuss.systems/@deanwampler), or [LinkedIn](https://www.linkedin.com/in/deanwampler/) accounts. +* [My Book Page](http://programming-scala.org) * [Blog about Scala 3](https://medium.com/scala-3) This repo contains all the code examples in O'Reilly's [Programming Scala, Third Edition](http://programming-scala.org). (The second edition is [available here](http://shop.oreilly.com/product/0636920033073.do).) There are also many code files in this distribution that aren't included in the book. @@ -178,28 +177,29 @@ $ I welcome feedback on the Book and these examples. Please post comments, corrections, etc. to one of the following places: -* This GitHub repo's [Gitter channel](https://gitter.im/deanwampler/programming-scala-book-code-examples), [Discussion forum](https://github.com/deanwampler/programming-scala-book-code-examples/discussions), or [Issues](https://github.com/deanwampler/programming-scala-book-code-examples/issues). -* The book's Twitter account, [@ProgScala](https://twitter.com/ProgScala). -* The O'Reilly book and errata sites (coming soon). +* This GitHub repo's [Discussion forum](https://github.com/deanwampler/programming-scala-book-code-examples/discussions), or [Issues](https://github.com/deanwampler/programming-scala-book-code-examples/issues). +* The [O'Reilly book page](https://oreil.ly/programming-scala-3) and the [errata page](https://www.oreilly.com/catalog/errata.csp?isbn=9781492077893). +* Dean Wampler's [Bluesky](https://bsky.app/profile/deanwampler.bsky.social), [Mastodon](https://discuss.systems/@deanwampler), or [LinkedIn](https://www.linkedin.com/in/deanwampler/) accounts. There is also my dedicated site for the book where occasional updates, clarifications, corrections, and lame excuses will be posted: [programming-scala.org](http://programming-scala.org). ## A Little History -| Key Dates | Description | -| :---------------- | :---------- | -| August 11, 2014 | 2nd edition examples | -| May 27, 2019 | Updated for Scala 2.12 and 2.13 | -| June 18, 2019 | New support for Maven builds, courtesy of [oldbig](https://github.com/oldbig) | -| October 12, 2019 | Updated for Scala 2.13.1, sbt 1.3.2, and other dependencies. Also now compiles with JDK 11 | -| October 13, 2019 | Renamed the repo from `prog-scala-2nd-ed-code-examples` to `programming-scala-book-code-examples` | -| December 31, 2019 | Renamed the `progscala2` package to `progscala3` and reworked most of the `*.sc` scripts for better testability and other improvements | -| March 1, 2020 | Completed conversion to Scala 3 | -| March 20, 2020 | Started incorporating new Scala 3 syntax, idioms | -| May 15, 2021 | Scala `3.0.0` final updates. Almost done! | -| May 22, 2021 | _Final_ updates for _Programming Scala, Third Edition_! | -| July 24, 2021 | Scala 3.0.1. Notes on using IntelliJ. | -| November 6, 2021 | Scala 3.1.0 and a fix for locale settings ([PR 42](https://github.com/deanwampler/programming-scala-book-code-examples/pull/42)). | -| September 15, 2024 | Scala 3.5.0 changes, e.g. the [new Scala CLI](https://docs.scala-lang.org/sips/scala-cli.html). | +| Key Dates | Description | +| :----------------- | :---------- | +| August 11, 2014 | 2nd edition examples | +| May 27, 2019 | Updated for Scala 2.12 and 2.13 | +| June 18, 2019 | New support for Maven builds, courtesy of [oldbig](https://github.com/oldbig) | +| October 12, 2019 | Updated for Scala 2.13.1, sbt 1.3.2, and other dependencies. Also now compiles with JDK 11 | +| October 13, 2019 | Renamed the repo from `prog-scala-2nd-ed-code-examples` to `programming-scala-book-code-examples` | +| December 31, 2019 | Renamed the `progscala2` package to `progscala3` and reworked most of the `*.sc` scripts for better testability and other improvements | +| March 1, 2020 | Completed conversion to Scala 3 | +| March 20, 2020 | Started incorporating new Scala 3 syntax, idioms | +| May 15, 2021 | Scala `3.0.0` final updates. Almost done! | +| May 22, 2021 | _Final_ updates for _Programming Scala, Third Edition_! | +| July 24, 2021 | Scala 3.0.1. Notes on using IntelliJ. | +| November 6, 2021 | Scala 3.1.0 and a fix for locale settings ([PR 42](https://github.com/deanwampler/programming-scala-book-code-examples/pull/42)). | +| September 15, 2024 | Scala 3.5.0 changes, e.g. the [new Scala CLI](https://docs.scala-lang.org/sips/scala-cli.html). | +| December 21, 2024 | Scala 3.6.2 changes, supporting new syntax options. | diff --git a/build.sbt b/build.sbt index 11f8c156..12447cf6 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val scala3 = "3.5.2" +val scala3 = "3.6.3" lazy val root = project .in(file(".")) .settings( @@ -20,14 +20,14 @@ lazy val root = project "com.typesafe.akka" %% "akka-slf4j" % "2.6.20", ).map(dep => dep.cross(CrossVersion.for3Use2_13)) ++ Seq( // Libraries that already fully support Scala 3: - "org.typelevel" %% "cats-core" % "2.12.0", + "org.typelevel" %% "cats-core" % "2.13.0", "org.scala-lang" %% "scala3-staging" % scalaVersion.value, "org.scala-lang.modules" %% "scala-parser-combinators" % "2.4.0", - "ch.qos.logback" % "logback-classic" % "1.5.12", + "ch.qos.logback" % "logback-classic" % "1.5.17", "org.scalacheck" %% "scalacheck" % "1.18.1" % Test, - "org.scalameta" %% "munit" % "1.0.2" % Test, - "org.scalameta" %% "munit-scalacheck" % "1.0.0" % Test, - "com.eed3si9n.expecty" %% "expecty" % "0.16.0" % Test, + "org.scalameta" %% "munit" % "1.1.1" % Test, + "org.scalameta" %% "munit-scalacheck" % "1.1.0" % Test, + "com.eed3si9n.expecty" %% "expecty" % "0.17.0" % Test, ), // For Scala 3 diff --git a/check-scripts.sh b/check-scripts.sh index af6066dc..4a66d612 100755 --- a/check-scripts.sh +++ b/check-scripts.sh @@ -3,6 +3,31 @@ default_dirs=( "src/script/scala" ) out_root="target/script-tests" out_ext="out" +expected_errors_in=( + src/script/scala/progscala3/appdesign/Deprecated.scala + src/script/scala/progscala3/patternmatching/MatchExhaustive.scala + src/script/scala/progscala3/patternmatching/MatchSurprise.scala + src/script/scala/progscala3/IndentationSyntax.scala + src/script/scala/progscala3/contexts/typeclass/TypeClassSubtypingProblems.scala + src/script/scala/progscala3/contexts/SeqUnzip.scala + src/script/scala/progscala3/meta/inline/Recursive.scala + src/script/scala/progscala3/meta/inline/Overrides.scala + src/script/scala/progscala3/meta/compiletime/RequireConst.scala + src/script/scala/progscala3/meta/compiletime/SummonAll.scala + src/script/scala/progscala3/rounding/TypeErasureProblem.scala + src/script/scala/progscala3/rounding/InfixMethod.scala + src/script/scala/progscala3/typelessdomore/Human.scala + src/script/scala/progscala3/typelessdomore/RepeatedParameters.scala + src/script/scala/progscala3/typelessdomore/MethodBroadInference.scala + src/script/scala/progscala3/typelessdomore/MethodRecursiveReturn.scala + src/script/scala/progscala3/typelessdomore/MethodNestedReturn.scala + src/script/scala/progscala3/basicoop/MatchableOpaque.scala + src/script/scala/progscala3/typesystem/typepaths/TypePath.scala + src/script/scala/progscala3/typesystem/valuetypes/SingletonTypes.scala + src/script/scala/progscala3/patternmatching/MatchTypesErasure.scala + src/script/scala/progscala3/patternmatching/MatchForFiltering.scala + src/script/scala/progscala3/collections/MultiMap.scala +) error() { echo "ERROR: $@" @@ -24,23 +49,44 @@ So, this bash script starts the REPL (using "sbt console") for each file and the uses :load to load the file. The output is written to $out_root/path/to/file.$out_ext. -Some files DO throw errors. In some cases, you'll see a comment on the same line -like "// ERROR". In other cases, you have to look at the book discussion to see -if the error is expected. Unfortunately, all the output has to be inspected manually. -If you see lots of errors for any one file, make sure you are using a Scala 3 REPL! +The following files are known to throw errors intentionally: +$(for f in ${expected_errors_in[@]}; do echo " $f"; done) + +Failures for these known files are ignored. In some of them, you'll see a comment +on the same line, like "// ERROR" or "// COMPILATION ERROR", which are easier to +spot when looking at error messages. In other cases, you have to look at the book +discussion to see if the error is expected. Unfortunately, this means that any +unexpected errors in these files will be missed, unless you inspect the output +when running them! + +For finding unexpected errors, the console output is searched for errors by looking +for any of the following lines near the end (where N=2+): + +1 warning found +N warnings found +1 error found +N errors found + +HOWEVER, to be really safe, all the outputs should still be inspected manually. Usage: $0 [-h|--help] [-v|--verbose] [-c|--clean] [-n|--no-exec] [dir ...] Where: -h | --help Print this message and exit. --v | --verbose Print each file name to the console as it is processed. +-v | --verbose Print each file name to the console as it is processed and dump + to stdout the test output (in the script's corresponding + "target/script-tests/..."). -c | --clean Delete all previous output. -n | --no-exec Don't execute the commands, just echo what would be done. +--check | --check-only + Don't run the scripts; just check for reported errors only + on any existing output files under $out_root. dir ... Start in these directories. (default "${default_dirs[@]}") EOF } : ${VERBOSE:=false} : ${CLEAN:=false} +: ${CHECK_ONLY=false} : ${NOOP:=} dirs=() @@ -54,7 +100,10 @@ do -v|--v*) VERBOSE=true ;; - -c|--c*) + --check*) + CHECK_ONLY=true + ;; + -c|--cl*) CLEAN=true ;; -n|--n*) @@ -79,27 +128,96 @@ then [[ -n "$out_root" ]] && rm -rf "$out_root" # safety check! fi +count_problem() { + problem=$1 + script=$2 + out=$3 + let count=$(grep -cE "^.+ $problem? found$" "$out" | sed -e "s/ $problem.*//") + case $count in + 0) + # do nothing + ;; + 1) + echo "ERROR: 1 ${problem} found in $script ($out)" + ;; + *) + echo "ERROR: $count ${problem}s found in $script ($out)" + ;; + esac + return $count +} + +report() { + let status=$1 + script=$2 + out=$3 + let error_count=0 + if [[ $status -ne 0 ]] + then + echo "ERROR: $script failed! ($out)" + let error_count+=1 + fi + for skip in ${expected_errors_in[@]} + do + [[ "$skip" = "$script" ]] && return $error_count + done + count_problem 'warning' "$script" "$out" + let error_count+=$? + count_problem 'error' "$script" "$out" + let error_count+=$? + $VERBOSE && cat "$out" + return $error_count +} + +export total_problem_count +let total_problem_count=0 + check() { script="$1" out="$out_root/$script.$out_ext" - $NOOP rm -f $out $VERBOSE && echo "$f --> $out" - if [[ -z "$NOOP" ]] + if ! $CHECK_ONLY then - mkdir -p $(dirname $out) - TERM=dumb sbt console < $out + $NOOP rm -f "$out" + if [[ -z "$NOOP" ]] + then + mkdir -p $(dirname "$out") + TERM=dumb sbt console < "$out" :load $script EOF - else - $NOOP mkdir -p $(dirname $out) - $NOOP "TERM=dumb sbt console ... :load $script ... > $out" + else + $NOOP mkdir -p $(dirname $out) + $NOOP "TERM=dumb sbt console ... :load $script ... > $out" + fi fi + $NOOP report $? "$script" "$out" + let total_problem_count+=$? + # return $? } +problem_count="$out_root/problem_count.txt" # see "hack" note below. +rm -f "$problem_count" for dir in "${dirs[@]}" do find "$dir" -name '*.scala' | while read f do check $f + # hack! The value of total_problem_count is lost to the outer shell, + # so write the values to a file for consumption "outside". + echo $total_problem_count >> "$problem_count" done done + +if [[ -f "$problem_count" ]] +then + let total_problem_count=$(tail -n 1 "$problem_count") + rm -f "$problem_count" + if [[ $total_problem_count -gt 0 ]] + then + echo "ERROR: $total_problem_count issues found." + exit 1 + fi +fi +echo "No obvious issues found, but consider checking all the output files in $out_root!" +exit 0 + diff --git a/project/build.properties b/project/build.properties index 09feeeed..cc68b53f 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.4 +sbt.version=1.10.11 diff --git a/project/plugins.sbt b/project/plugins.sbt index 28d7630d..170c1877 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -3,4 +3,4 @@ resolvers ++= Seq( "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" ) -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.2") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1") diff --git a/src/main/scala/progscala3/basicoop/NoSQLRecordsRevisited.scala b/src/main/scala/progscala3/basicoop/NoSQLRecordsRevisited.scala index 14d383e5..1c2e9d84 100644 --- a/src/main/scala/progscala3/basicoop/NoSQLRecordsRevisited.scala +++ b/src/main/scala/progscala3/basicoop/NoSQLRecordsRevisited.scala @@ -21,11 +21,11 @@ extension (rec: Record) object Record: def empty: Record = Map.empty -given FromTo[Int] with +given FromTo[Int]: def apply(any: Any): Int = any.asInstanceOf[Int] -given FromTo[Double] with +given FromTo[Double]: def apply(any: Any): Double = any.asInstanceOf[Double] -given FromTo[String] with +given FromTo[String]: def apply(any: Any): String = any.asInstanceOf[String] @main def TryScalaDBRevisited = diff --git a/src/main/scala/progscala3/contexts/NoSQLRecords.scala b/src/main/scala/progscala3/contexts/NoSQLRecords.scala index 261ed45f..e98c6327 100644 --- a/src/main/scala/progscala3/contexts/NoSQLRecords.scala +++ b/src/main/scala/progscala3/contexts/NoSQLRecords.scala @@ -28,7 +28,7 @@ case class Record private (contents: Map[String,Any]): // <2> given Conv[Int] = _.asInstanceOf[Int] // <5> given Conv[Double] = _.asInstanceOf[Double] given Conv[String] = _.asInstanceOf[String] - given ab[A : Conv, B : Conv]: Conv[(A, B)] = _.asInstanceOf[(A,B)] + given ab: [A : Conv, B : Conv] => Conv[(A, B)] = _.asInstanceOf[(A,B)] val rec = Record.make.add("one" -> 1).add("two" -> 2.2) .add("three" -> "THREE!").add("four" -> (4.4, "four")) diff --git a/src/main/scala/progscala3/contexts/accounting/NewImplicitConversions.scala b/src/main/scala/progscala3/contexts/accounting/NewImplicitConversions.scala index 9b8d31fb..20e03d89 100644 --- a/src/main/scala/progscala3/contexts/accounting/NewImplicitConversions.scala +++ b/src/main/scala/progscala3/contexts/accounting/NewImplicitConversions.scala @@ -42,7 +42,7 @@ case class Salary(gross: Dollars, taxes: Percentage): val salary = Salary(100_000.0, 20.0) println(s"salary: $salary. Net pay: ${salary.net}") - given Conversion[Int,Dollars] with // <3> + given Conversion[Int,Dollars]: // <3> def apply(i:Int): Dollars= Dollars(i.toDouble) val dollars: Dollars = 10 // <4> diff --git a/src/main/scala/progscala3/contexts/json/JSONBuilder.scala b/src/main/scala/progscala3/contexts/json/JSONBuilder.scala index 67ecff10..89f3722e 100644 --- a/src/main/scala/progscala3/contexts/json/JSONBuilder.scala +++ b/src/main/scala/progscala3/contexts/json/JSONBuilder.scala @@ -102,7 +102,7 @@ object JSONBuilder: * are _witnesses_, constraining the allowed types of JSON values. Note that * there is nothing to implement in the trait, but we have to use the `with {}` * clauses to make these definitions concrete. - * NOTE: Scala 3.0.0 requires "given ValidJSONValue[Int] with {}", while 3.0.1 + * NOTE: Scala 3.0.0 requires "given ValidJSONValue[Int]: {}", while 3.0.1 * removed the need for "with {}", but you have to add the "()". */ sealed trait ValidJSONValue[T <: Matchable] diff --git a/src/main/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala b/src/main/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala index 2abde30b..4e391c82 100644 --- a/src/main/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala +++ b/src/main/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala @@ -11,11 +11,11 @@ trait Semigroup[T]: trait Monoid[T] extends Semigroup[T]: def unit: T // <2> -given StringMonoid: Monoid[String] with // <3> +given StringMonoid: Monoid[String]: // <3> def unit: String = "" extension (s: String) infix def combine(other: String): String = s + other -given IntMonoid: Monoid[Int] with +given IntMonoid: Monoid[Int]: def unit: Int = 0 extension (i: Int) infix def combine(other: Int): Int = i + other // end::definitions[] diff --git a/src/main/scala/progscala3/contexts/typeclass/new1/ToJSONTypeClasses.scala b/src/main/scala/progscala3/contexts/typeclass/new1/ToJSONTypeClasses.scala index 5df5255d..a8486841 100644 --- a/src/main/scala/progscala3/contexts/typeclass/new1/ToJSONTypeClasses.scala +++ b/src/main/scala/progscala3/contexts/typeclass/new1/ToJSONTypeClasses.scala @@ -5,7 +5,7 @@ package progscala3.contexts.typeclass.new1 import progscala3.introscala.shapes.{Point, Shape, Circle, Rectangle, Triangle} import progscala3.contexts.json.ToJSON -given ToJSON[Point] with // <1> +given ToJSON[Point]: // <1> extension (point: Point) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -14,7 +14,7 @@ given ToJSON[Point] with // <1> |${indent}"y": "${point.y}" |$outdent}""".stripMargin -given ToJSON[Circle] with // <2> +given ToJSON[Circle]: // <2> extension (circle: Circle) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -25,7 +25,7 @@ given ToJSON[Circle] with // <2> // end::definitions1[] // tag::definitions2[] -given ToJSON[Rectangle] with +given ToJSON[Rectangle]: extension (rect: Rectangle) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -35,7 +35,7 @@ given ToJSON[Rectangle] with |${indent}"width": ${rect.width} |$outdent}""".stripMargin -given ToJSON[Triangle] with +given ToJSON[Triangle]: extension (tri: Triangle) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) diff --git a/src/main/scala/progscala3/contexts/typeclass/new2/ToJSONTypeClasses.scala b/src/main/scala/progscala3/contexts/typeclass/new2/ToJSONTypeClasses.scala index 1174cc33..969ecc4a 100644 --- a/src/main/scala/progscala3/contexts/typeclass/new2/ToJSONTypeClasses.scala +++ b/src/main/scala/progscala3/contexts/typeclass/new2/ToJSONTypeClasses.scala @@ -4,7 +4,7 @@ package progscala3.contexts.typeclass.new2 import progscala3.introscala.shapes.{Point, Shape, Circle, Rectangle, Triangle} import progscala3.contexts.json.ToJSON -given ToJSON[Point] with +given ToJSON[Point]: extension (point: Point) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -13,7 +13,7 @@ given ToJSON[Point] with |${indent}"y": "${point.y}" |$outdent}""".stripMargin -given ToJSON[Circle] with +given ToJSON[Circle]: extension (circle: Circle) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -22,7 +22,7 @@ given ToJSON[Circle] with |${indent}"radius": ${circle.radius} |$outdent}""".stripMargin -given ToJSON[Rectangle] with +given ToJSON[Rectangle]: extension (rect: Rectangle) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -32,7 +32,7 @@ given ToJSON[Rectangle] with |${indent}"width": ${rect.width} |$outdent}""".stripMargin -given ToJSON[Triangle] with +given ToJSON[Triangle]: extension (tri: Triangle) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -45,7 +45,7 @@ given ToJSON[Triangle] with // tag::ToJSONShape[] // src/main/scala/progscala3/contexts/typeclass/new2/ToJSONTypeClasses.scala -given ToJSON[Shape] with +given ToJSON[Shape]: extension (shape: Shape) def toJSON(name: String = "", level: Int = 0): String = shape match diff --git a/src/main/scala/progscala3/contexts/typeclass/new3/ToJSONTypeClasses.scala b/src/main/scala/progscala3/contexts/typeclass/new3/ToJSONTypeClasses.scala index da07b129..d75f9451 100644 --- a/src/main/scala/progscala3/contexts/typeclass/new3/ToJSONTypeClasses.scala +++ b/src/main/scala/progscala3/contexts/typeclass/new3/ToJSONTypeClasses.scala @@ -4,7 +4,7 @@ package progscala3.contexts.typeclass.new3 import progscala3.introscala.shapes.{Point, Shape, Circle, Rectangle, Triangle} import progscala3.contexts.json.ToJSON -given ToJSON[Point] with +given ToJSON[Point]: extension (point: Point) def toJSON(name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) @@ -13,7 +13,7 @@ given ToJSON[Point] with |${indent}"y": "${point.y}" |$outdent}""".stripMargin -given circleToJSON: ToJSON[Circle] with +given circleToJSON: ToJSON[Circle]: def toJSON2(circle: Circle, name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) s"""${handleName(name)}{ @@ -24,7 +24,7 @@ given circleToJSON: ToJSON[Circle] with def toJSON(name: String = "", level: Int = 0): String = toJSON2(circle, name, level) -given rectangleToJSON: ToJSON[Rectangle] with +given rectangleToJSON: ToJSON[Rectangle]: def toJSON2(rect: Rectangle, name: String = "", level: Int = 0): String = val (outdent, indent) = indentation(level) s"""${handleName(name)}{ @@ -39,7 +39,7 @@ given rectangleToJSON: ToJSON[Rectangle] with // tag::ToJSONShape[] // src/main/scala/progscala3/contexts/typeclass/new3/ToJSONTypeClasses.scala -given triangleToJSON: ToJSON[Triangle] with // <1> +given triangleToJSON: ToJSON[Triangle]: // <1> def toJSON2( tri: Triangle, name: String = "", level: Int = 0): String = // <2> val (outdent, indent) = indentation(level) @@ -52,7 +52,7 @@ given triangleToJSON: ToJSON[Triangle] with // <1> def toJSON(name: String = "", level: Int = 0): String = toJSON2(tri, name, level) // <3> -given ToJSON[Shape] with +given ToJSON[Shape]: extension (shape: Shape) def toJSON(name: String = "", level: Int = 0): String = shape match diff --git a/src/main/scala/progscala3/contexts/typeclass/new4/ToJSONTypeClasses.scala b/src/main/scala/progscala3/contexts/typeclass/new4/ToJSONTypeClasses.scala index 7ac5265c..a62ccd5b 100644 --- a/src/main/scala/progscala3/contexts/typeclass/new4/ToJSONTypeClasses.scala +++ b/src/main/scala/progscala3/contexts/typeclass/new4/ToJSONTypeClasses.scala @@ -52,27 +52,27 @@ protected object ShapesToJSON: |$outdent}""".stripMargin end ShapesToJSON -given pointToJSON: ToJSON[Point] with +given pointToJSON: ToJSON[Point]: extension (point: Point) def toJSON(name: String = "", level: Int = 0): String = ShapesToJSON(point, name, level) -given circleToJSON: ToJSON[Circle] with +given circleToJSON: ToJSON[Circle]: extension (circle: Circle) def toJSON(name: String = "", level: Int = 0): String = ShapesToJSON(circle, name, level) -given rectangleToJSON: ToJSON[Rectangle] with +given rectangleToJSON: ToJSON[Rectangle]: extension (rect: Rectangle) def toJSON(name: String = "", level: Int = 0): String = ShapesToJSON(rect, name, level) -given triangleToJSON: ToJSON[Triangle] with +given triangleToJSON: ToJSON[Triangle]: extension (tri: Triangle) def toJSON(name: String = "", level: Int = 0): String = ShapesToJSON(tri, name, level) -given shapeToJSON: ToJSON[Shape] with +given shapeToJSON: ToJSON[Shape]: extension (shape: Shape) def toJSON(name: String = "", level: Int = 0): String = shape match case c: Circle => ShapesToJSON(c, name, level) diff --git a/src/main/scala/progscala3/dsls/payroll/Money.scala b/src/main/scala/progscala3/dsls/payroll/Money.scala index 3e2bdceb..fbc8ea70 100644 --- a/src/main/scala/progscala3/dsls/payroll/Money.scala +++ b/src/main/scala/progscala3/dsls/payroll/Money.scala @@ -3,10 +3,10 @@ package progscala3.dsls.payroll import progscala3.contexts.accounting.* // <1> import scala.util.FromDigits.Floating // <2> -given Floating[Dollars] with // <3> +given Floating[Dollars]: // <3> def fromDigits(digits: String): Dollars = Dollars(digits.toDouble) -given Floating[Percentage] with +given Floating[Percentage]: def fromDigits(digits: String): Percentage = Percentage(digits.toDouble) implicit class dsc(sc: StringContext): // <4> diff --git a/src/main/scala/progscala3/fp/categories/Functor2.scala b/src/main/scala/progscala3/fp/categories/Functor2.scala index 6d9a49bc..2c6ac90d 100644 --- a/src/main/scala/progscala3/fp/categories/Functor2.scala +++ b/src/main/scala/progscala3/fp/categories/Functor2.scala @@ -106,9 +106,9 @@ object FunctionF2B: (fa: F[A]) => flatMap(fa)(t compose f) @main def TryFunctionF2B() = - given [A]: FunctionF2B.FlatMap[A,Seq] with + given [A] => FunctionF2B.FlatMap[A,Seq]: def apply(seq: Seq[A])(f: A => Seq[A]): Seq[A] = seq.flatMap(f) - given [A]: FunctionF2B.FlatMap[A,Option] with + given [A] => FunctionF2B.FlatMap[A,Option]: def apply(seq: Option[A])(f: A => Option[A]): Option[A] = seq.flatMap(f) val f: Int => Int = 2 * _ @@ -145,8 +145,8 @@ object FunctionF2C: } @main def TryFunctionF2C() = - given [A]: FunctionF2C.Lift[A,Seq] = (a:A) => Seq(a) - given [A]: FunctionF2B.FlatMap[A,Set] with + given [A] => FunctionF2C.Lift[A,Seq] = (a:A) => Seq(a) + given [A] => FunctionF2B.FlatMap[A,Set]: def apply(set: Set[A])(f: A => Set[A]): Set[A] = set.flatMap(f) val fseqd: Seq[Double] => Seq[Double] = _.map(2.0 * _) @@ -183,8 +183,8 @@ object FunctionF2D: } @main def TryFunctionF2D() = - given [A]: FunctionF2C.Lift[A,Seq] = (a:A) => Seq(a) - given [A]: FunctionF2B.FlatMap[A,Set] with + given [A] => FunctionF2C.Lift[A,Seq] = (a:A) => Seq(a) + given [A] => FunctionF2B.FlatMap[A,Set]: def apply(set: Set[A])(f: A => Set[A]): Set[A] = set.flatMap(f) given Functor[Seq] = SeqF diff --git a/src/main/scala/progscala3/fp/categories/MapMerge.scala b/src/main/scala/progscala3/fp/categories/MapMerge.scala index ba3afa6c..37b0a678 100644 --- a/src/main/scala/progscala3/fp/categories/MapMerge.scala +++ b/src/main/scala/progscala3/fp/categories/MapMerge.scala @@ -2,7 +2,7 @@ package progscala3.fp.categories import progscala3.contexts.typeclass.Monoid -given MapMergeMonoid[K, V : Monoid]: Monoid[Map[K, V]] with // <1> +given MapMergeMonoid: [K, V : Monoid] => Monoid[Map[K, V]]: // <1> def unit: Map[K, V] = Map.empty extension (map1: Map[K, V]) def combine(map2: Map[K, V]): Map[K, V] = val kmon = summon[Monoid[V]] diff --git a/src/main/scala/progscala3/typesystem/typelambdas/Functor.scala b/src/main/scala/progscala3/typesystem/typelambdas/Functor.scala index 271d0f3a..e393e3ab 100644 --- a/src/main/scala/progscala3/typesystem/typelambdas/Functor.scala +++ b/src/main/scala/progscala3/typesystem/typelambdas/Functor.scala @@ -5,12 +5,12 @@ trait Functor[M[_]]: extension [A] (m: M[A]) def map2[B](f: A => B): M[B] object Functor: - given Functor[Seq] with + given Functor[Seq]: extension [A] (seq: Seq[A]) def map2[B](f: A => B): Seq[B] = seq map f type MapKV = [K] =>> [V] =>> Map[K,V] // <1> - given [K]: Functor[MapKV[K]] with // <2> + given [K] => Functor[MapKV[K]]: // <2> extension [V1] (map: MapKV[K][V1]) def map2[V2](f: V1 => V2): MapKV[K][V2] = map.view.mapValues(f).toMap diff --git a/src/script/scala/progscala3/BracesSyntax.scala b/src/script/scala/progscala3/BracesSyntax.scala index 1963d6ac..05ea3099 100644 --- a/src/script/scala/progscala3/BracesSyntax.scala +++ b/src/script/scala/progscala3/BracesSyntax.scala @@ -86,7 +86,7 @@ val mon = new Monoid[Int] { } // New type class given instantiation -given intMonoid: Monoid[Float] with { +given intMonoid: Monoid[Float]: { def add(f1: Float, f2: Float): Float = f1+f2 def zero: Float = 0.0F } diff --git a/src/script/scala/progscala3/IndentationSyntax.scala b/src/script/scala/progscala3/IndentationSyntax.scala index add2f655..ac275d3e 100644 --- a/src/script/scala/progscala3/IndentationSyntax.scala +++ b/src/script/scala/progscala3/IndentationSyntax.scala @@ -112,11 +112,11 @@ val longMon = end new // You can use "end new" here because "new Monoid..." starts at the same column! // New type class given instantiation -given floatMonoid: Monoid[Float] with +given floatMonoid: Monoid[Float]: def add(f1: Float, f2: Float): Float = f1+f2 def zero: Float = 0.0F end floatMonoid // Use identifier. -given Monoid[Double] with +given Monoid[Double]: def add(d1: Double, d2: Double): Double = d1+d2 def zero: Double = 0.0 end given // Anonymous, so no identifier. Hence, use "given". diff --git a/src/script/scala/progscala3/appdesign/Deprecated.scala b/src/script/scala/progscala3/appdesign/Deprecated.scala index bafd07af..1b0529a1 100644 --- a/src/script/scala/progscala3/appdesign/Deprecated.scala +++ b/src/script/scala/progscala3/appdesign/Deprecated.scala @@ -6,7 +6,7 @@ import scala.annotation.nowarn // This one has to be imported. @deprecated("this method will be removed", "V1.2.3") def obsolete(i: Int) = 2*i -def warning(i: Int) = obsolete(i) +def warning(i: Int) = obsolete(i) // ERROR // In Scala 2, @nowarn would suppress a warning for this method's use of obsolete. // This is not (yet?) implemented in Scala 3. @nowarn def nowarning(i: Int) = obsolete(i) diff --git a/src/script/scala/progscala3/basicoop/MatchableOpaque.scala b/src/script/scala/progscala3/basicoop/MatchableOpaque.scala index 10cbb818..db0c8e05 100644 --- a/src/script/scala/progscala3/basicoop/MatchableOpaque.scala +++ b/src/script/scala/progscala3/basicoop/MatchableOpaque.scala @@ -5,7 +5,7 @@ object Obj: opaque type OArr[T] = Array[T] summon[Obj.Arr[Int] <:< Matchable] // Okay -summon[Obj.OArr[Int] <:< Matchable] // Doesn't work +summon[Obj.OArr[Int] <:< Matchable] // ERROR! object Obj2: type Arr[T] = Array[T] diff --git a/src/script/scala/progscala3/collections/MultiMap.scala b/src/script/scala/progscala3/collections/MultiMap.scala index 164052bb..24023876 100644 --- a/src/script/scala/progscala3/collections/MultiMap.scala +++ b/src/script/scala/progscala3/collections/MultiMap.scala @@ -1,4 +1,5 @@ // src/script/scala/progscala3/collections/MultiMap.scala +// NOTE: This file uses deprecated features, like MultiMap. import collection.mutable.{HashMap, MultiMap, Set} // <1> val mm = new HashMap[Int, Set[String]] with MultiMap[Int, String] // <2> diff --git a/src/script/scala/progscala3/contexts/GivenImports.scala b/src/script/scala/progscala3/contexts/GivenImports.scala index e2e2a51e..f76a117a 100644 --- a/src/script/scala/progscala3/contexts/GivenImports.scala +++ b/src/script/scala/progscala3/contexts/GivenImports.scala @@ -23,7 +23,7 @@ trait Marker[T] object O2: class C1 given C1 = C1() - // In Scala 3.0.0, the following has to be written: given Marker[Int] with {} + // In Scala 3.0.0, the following has to be written: given Marker[Int]: {} given Marker[Int]() // <1> given Marker[List[?]]() // <2> diff --git a/src/script/scala/progscala3/contexts/ImplicitNotFound.scala b/src/script/scala/progscala3/contexts/ImplicitNotFound.scala index 73ba013e..cc36e6ef 100644 --- a/src/script/scala/progscala3/contexts/ImplicitNotFound.scala +++ b/src/script/scala/progscala3/contexts/ImplicitNotFound.scala @@ -19,9 +19,9 @@ object O: // end::definitions[] // tag::usage[] -given Tagify[Int] with +given Tagify[Int]: def toTag(i: Int): String = s"$i" -given Tagify[String] with +given Tagify[String]: def toTag(s: String): String = s"$s" Stringer("Hello World!") diff --git a/src/script/scala/progscala3/contexts/SeqUnzip.scala b/src/script/scala/progscala3/contexts/SeqUnzip.scala index f6d31e9f..1a1eda4c 100644 --- a/src/script/scala/progscala3/contexts/SeqUnzip.scala +++ b/src/script/scala/progscala3/contexts/SeqUnzip.scala @@ -4,7 +4,7 @@ val seq = (0 to 10).toList object noimplicit: - val unzipped = seq.unzip // Error. + val unzipped = seq.unzip // ERROR object topair: implicit val toPair: Int => (Int, String) = i => (i, (2*i).toString) diff --git a/src/script/scala/progscala3/contexts/UsingClauses.scala b/src/script/scala/progscala3/contexts/UsingClauses.scala index fb4d384e..30bbfcb4 100644 --- a/src/script/scala/progscala3/contexts/UsingClauses.scala +++ b/src/script/scala/progscala3/contexts/UsingClauses.scala @@ -45,7 +45,7 @@ oddEvenImplicitOrdering() // tag::oddEvenGivenOrdering[] def evenOddGivenOrdering() = - given evenOdd: Ordering[Int] with + given evenOdd: Ordering[Int]: def compare(i: Int, j: Int): Int = i%2 compare j%2 match case 0 => i compare j case c => -c diff --git a/src/script/scala/progscala3/contexts/UsingTypeErasureWorkaround.scala b/src/script/scala/progscala3/contexts/UsingTypeErasureWorkaround.scala index 7be90e44..30ab1d9f 100644 --- a/src/script/scala/progscala3/contexts/UsingTypeErasureWorkaround.scala +++ b/src/script/scala/progscala3/contexts/UsingTypeErasureWorkaround.scala @@ -4,7 +4,7 @@ object O2: trait Marker[T] // <1> // In Scala 3.0.0, the following has to be written: - // given IntMarker: Marker[Int] with {} + // given IntMarker: Marker[Int]: {} given IntMarker: Marker[Int]() given StringMarker: Marker[String]() diff --git a/src/script/scala/progscala3/contexts/typeclass/MonoidAliasGiven.scala b/src/script/scala/progscala3/contexts/typeclass/MonoidAliasGiven.scala index d7c78bc3..cbe1c1f3 100644 --- a/src/script/scala/progscala3/contexts/typeclass/MonoidAliasGiven.scala +++ b/src/script/scala/progscala3/contexts/typeclass/MonoidAliasGiven.scala @@ -2,7 +2,7 @@ // src/script/scala/progscala3/contexts/typeclass/MonoidAliasGiven.scala import progscala3.contexts.typeclass.Monoid -given NumericMonoid2[T : Numeric]: Monoid[T] = new Monoid[T]: +given NumericMonoid2: [T: Numeric] => Monoid[T] = new Monoid[T]: println("Initializing NumericMonoid2") def unit: T = summon[Numeric[T]].zero extension (t: T) infix def combine(other: T): T = diff --git a/src/script/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala b/src/script/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala index fe051cb8..582395b2 100644 --- a/src/script/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala +++ b/src/script/scala/progscala3/contexts/typeclass/MonoidTypeClass.scala @@ -16,7 +16,7 @@ IntMonoid.unit <+> 2 // 2 // end::usage[] // tag::numericdefinition[] -given NumericMonoid[T : Numeric]: Monoid[T] with +given NumericMonoid[T : Numeric]: Monoid[T]: def unit: T = summon[Numeric[T]].zero extension (t: T) infix def combine(other: T): T = summon[Numeric[T]].plus(t, other) @@ -31,19 +31,19 @@ NumericMonoid[BigDecimal].unit combine BigDecimal(3.14) // end::numericdefinition[] // tag::numericdefinition2[] -given NumericMonoid[T](using num: Numeric[T]): Monoid[T] with +given NumericMonoid[T](using num: Numeric[T]): Monoid[T]: def unit: T = num.zero extension (t: T) infix def combine(other: T): T = num.plus(t, other) // end::numericdefinition2[] // tag::numericdefinition3[] -given [T : Numeric]: Monoid[T] with +given [T : Numeric]: Monoid[T]: def unit: T = summon[Numeric[T]].zero extension (t: T) infix def combine(other: T): T = summon[Numeric[T]].plus(t, other) // or -given [T](using num: Numeric[T]): Monoid[T] with +given [T](using num: Numeric[T]): Monoid[T]: def unit: T = summon[Numeric[T]].zero extension (t: T) infix def combine(other: T): T = summon[Numeric[T]].plus(t, other) diff --git a/src/script/scala/progscala3/contexts/typeclass/TypeClassSubtypingProblems.scala b/src/script/scala/progscala3/contexts/typeclass/TypeClassSubtypingProblems.scala index dfa15996..4e18c2fa 100644 --- a/src/script/scala/progscala3/contexts/typeclass/TypeClassSubtypingProblems.scala +++ b/src/script/scala/progscala3/contexts/typeclass/TypeClassSubtypingProblems.scala @@ -15,7 +15,7 @@ import progscala3.contexts.{DomainConcept, Address, Person} // Helper methods are used, like in // src/main/scala/progscala3/contexts/typeclass/new3/ToJSONTypeClasses.scala // for reasons explained below. -given ToJSON[Address] with +given ToJSON[Address]: def toJSON2(address: Address, name: String, level: Int): String = val (outdent, indent) = indentation(level) s""""$name": { @@ -26,7 +26,7 @@ given ToJSON[Address] with def toJSON(name: String = "", level: Int = 0): String = toJSON2(address, name, level) -given ToJSON[Person] with +given ToJSON[Person]: def toJSON2(person: Person, name: String, level: Int): String = val (outdent, indent) = indentation(level) s""""$name": { @@ -64,7 +64,7 @@ list1.map(_.toJSON("object")) // switches on the actual type. This is ugly and you'll have to remember to update // this method if you change the subtypes of DomainConcept. Note that I declared // it to be a sealed trait above, which lets the compiler catch some problems. -given ToJSON[DomainConcept] with +given ToJSON[DomainConcept]: extension (dc: DomainConcept) def toJSON(name: String = "", level: Int = 0): String = dc match case person: Person => summon[ToJSON[Person]].toJSON2(person, name, level) @@ -83,7 +83,7 @@ list1.map(_.toJSON("object")) // person.toJSON() will now recursively call the DomainConcept.toJSON // extension method, instead of the original Person.toJSON. -given ToJSON[DomainConcept] with +given ToJSON[DomainConcept]: extension (dc: DomainConcept) def toJSON(name: String = "", level: Int = 0): String = dc match case person: Person => person.toJSON(name, level) diff --git a/src/script/scala/progscala3/meta/compiletime/SummonAll.scala b/src/script/scala/progscala3/meta/compiletime/SummonAll.scala index 6e908e64..4f6e1e8e 100644 --- a/src/script/scala/progscala3/meta/compiletime/SummonAll.scala +++ b/src/script/scala/progscala3/meta/compiletime/SummonAll.scala @@ -2,7 +2,7 @@ import scala.compiletime.summonAll trait C; trait D; trait E -// In Scala 3.0.0, the following has to be written: given c: C with {} +// In Scala 3.0.0, the following has to be written: given c: C: {} given c: C() given d: D() diff --git a/src/script/scala/progscala3/meta/compiletime/SummonFrom.scala b/src/script/scala/progscala3/meta/compiletime/SummonFrom.scala index ab675337..cc25dbcf 100644 --- a/src/script/scala/progscala3/meta/compiletime/SummonFrom.scala +++ b/src/script/scala/progscala3/meta/compiletime/SummonFrom.scala @@ -14,7 +14,7 @@ inline def trySummonFrom(label: String, expected: Int): Unit = // <1> def tryNone = trySummonFrom("tryNone:", 0) // <2> def tryA = // <3> - // In Scala 3.0.0, the following has to be written: given A with {} + // In Scala 3.0.0, the following has to be written: given A: {} given A() trySummonFrom("tryA:", 1) diff --git a/src/script/scala/progscala3/patternmatching/MatchExhaustive.scala b/src/script/scala/progscala3/patternmatching/MatchExhaustive.scala index 4f39af45..f3b7822a 100644 --- a/src/script/scala/progscala3/patternmatching/MatchExhaustive.scala +++ b/src/script/scala/progscala3/patternmatching/MatchExhaustive.scala @@ -2,5 +2,5 @@ val seq3 = Seq(Some(1), None, Some(2), None) val result3 = seq3.map { - case Some(i) => s"int $i" + case Some(i) => s"int $i" // ERROR } diff --git a/src/script/scala/progscala3/patternmatching/MatchForFiltering.scala b/src/script/scala/progscala3/patternmatching/MatchForFiltering.scala index 0a143f75..b8891744 100644 --- a/src/script/scala/progscala3/patternmatching/MatchForFiltering.scala +++ b/src/script/scala/progscala3/patternmatching/MatchForFiltering.scala @@ -5,7 +5,7 @@ val elems = Seq((1, 2), "hello", (3, 4), 1, 2.2, (5, 6)) val what1 = for (case (x, y) <- elems) yield (y, x) // <1> val what2 = for case (x, y) <- elems yield (y, x) -val nope = for (x, y) <- elems yield (y, x) +val nope = for (x, y) <- elems yield (y, x) // ERROR val seq = Seq(None, Some(1), None, Some(2.2), None, None, Some("three")) for case Some(x) <- seq yield x diff --git a/src/script/scala/progscala3/patternmatching/MatchRepeatedParamsList.scala b/src/script/scala/progscala3/patternmatching/MatchRepeatedParamsList.scala index 8f671d45..80220fa4 100644 --- a/src/script/scala/progscala3/patternmatching/MatchRepeatedParamsList.scala +++ b/src/script/scala/progscala3/patternmatching/MatchRepeatedParamsList.scala @@ -32,7 +32,6 @@ val results = wheres.map { val valStr = (val1 +: vals).mkString(", ") s"WHERE $col IN ($valStr)" case WhereOp(col, op, value) => s"WHERE $col ${op.symbol} $value" - case x => s"ERROR: Unknown expression: $x" } assert(results == Seq( "WHERE state IN (IL, CA, VA)", diff --git a/src/script/scala/progscala3/patternmatching/MatchSurprise.scala b/src/script/scala/progscala3/patternmatching/MatchSurprise.scala index 22306fd9..81291fc4 100644 --- a/src/script/scala/progscala3/patternmatching/MatchSurprise.scala +++ b/src/script/scala/progscala3/patternmatching/MatchSurprise.scala @@ -5,7 +5,7 @@ def checkYBad(y: Int): Seq[String] = for x <- Seq(99, 100, 101) yield x match case y => "found y!" - case i: Int => "int: "+i // Unreachable case! + case i: Int => "int: "+i // ERROR Unreachable case! // end::bad[] // tag::good1[] diff --git a/src/script/scala/progscala3/patternmatching/MatchTreeADTFull.scala b/src/script/scala/progscala3/patternmatching/MatchTreeADTFull.scala index 720220f1..add25177 100644 --- a/src/script/scala/progscala3/patternmatching/MatchTreeADTFull.scala +++ b/src/script/scala/progscala3/patternmatching/MatchTreeADTFull.scala @@ -31,3 +31,4 @@ yield tree match r @ Branch(rl @ Leaf(rli), rr @ Branch(_,_))) => s"3: l=$l, r=$r, rl=$rl, rli=$rli, rr=$rr" case _:Branch[?] => "4: Other Branch" + case Leaf(_) => "5: Leaf" diff --git a/src/script/scala/progscala3/rounding/InfixMethod.scala b/src/script/scala/progscala3/rounding/InfixMethod.scala index 6254188f..fafc7c65 100644 --- a/src/script/scala/progscala3/rounding/InfixMethod.scala +++ b/src/script/scala/progscala3/rounding/InfixMethod.scala @@ -4,9 +4,9 @@ case class Foo(str: String): def append(s: String): Foo = copy(str + s) infix def combine(s:String): Foo = append(s) -Foo("one").append("two") // <1> -Foo("one") append {"two"} // <2> +Foo("one").append("two") // <1> +Foo("one") append {"two"} // <2> Foo("one") `append` "two" -Foo("one") append "two" // <3> +Foo("one") append "two" // <3> -Foo("one") combine "two" // <4> +Foo("one") combine "two" // <4> diff --git a/src/script/scala/progscala3/rounding/TypeErasureProblem.scala b/src/script/scala/progscala3/rounding/TypeErasureProblem.scala index 3c352c4a..a79633d2 100644 --- a/src/script/scala/progscala3/rounding/TypeErasureProblem.scala +++ b/src/script/scala/progscala3/rounding/TypeErasureProblem.scala @@ -2,4 +2,4 @@ object O: def m(is: Seq[Int]): Int = is.sum - def m(ss: Seq[String]): Int = ss.length + def m(ss: Seq[String]): Int = ss.length // ERROR diff --git a/src/script/scala/progscala3/typelessdomore/RepeatedParameters.scala b/src/script/scala/progscala3/typelessdomore/RepeatedParameters.scala index 8e253268..fe9c244b 100644 --- a/src/script/scala/progscala3/typelessdomore/RepeatedParameters.scala +++ b/src/script/scala/progscala3/typelessdomore/RepeatedParameters.scala @@ -12,7 +12,7 @@ object Mean1: // tag::mean2[] object Mean2: def apply(ds: Double*): Double = apply(ds) - def apply(ds: Seq[Double]): Double = ds.sum/ds.size + def apply(ds: Seq[Double]): Double = ds.sum/ds.size // ERROR // end::mean2[] // tag::mean[] diff --git a/src/script/scala/progscala3/typesystem/higherkinded/HKFoldLeft.scala b/src/script/scala/progscala3/typesystem/higherkinded/HKFoldLeft.scala index cd96b72e..d24d0baf 100644 --- a/src/script/scala/progscala3/typesystem/higherkinded/HKFoldLeft.scala +++ b/src/script/scala/progscala3/typesystem/higherkinded/HKFoldLeft.scala @@ -6,14 +6,14 @@ object HKFoldLeft: // "HK" for "higher-kinded" trait Folder[-M[_]]: // <1> def apply[IN, OUT](m: M[IN], seed: OUT, f: (OUT, IN) => OUT): OUT - given Folder[Iterable] with // <2> + given Folder[Iterable]: // <2> def apply[IN, OUT](iter: Iterable[IN], seed: OUT, f: (OUT, IN) => OUT): OUT = var accumulator = seed iter.foreach(t => accumulator = f(accumulator, t)) accumulator - given Folder[Option] with // <3> + given Folder[Option]: // <3> def apply[IN, OUT](opt: Option[IN], seed: OUT, f: (OUT, IN) => OUT): OUT = opt match case Some(t) => f(seed, t) @@ -44,7 +44,7 @@ HKFoldLeft(Option.empty[Int])(0.0)(_+_) // end::usage1[] // tag::usage2[] -given Folder[[X] =>> Either[String, X]] with +given Folder[[X] =>> Either[String, X]]: def apply[IN, OUT](err: Either[String, IN], seed: OUT, f: (OUT, IN) => OUT): OUT = err match case Right(t) => f(seed, t)