Skip to content

Commit 74b5e44

Browse files
authored
Merge branch 'master' into update/logback-classic-1.2.11
2 parents a61cc80 + 4fd496a commit 74b5e44

File tree

11 files changed

+374
-13
lines changed

11 files changed

+374
-13
lines changed

build.sbt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
val scala3 = "3.1.0"
1+
val scala3 = "3.1.2"
22
lazy val root = project
33
.in(file("."))
44
.settings(
@@ -16,17 +16,17 @@ lazy val root = project
1616
// Notice how the Scala 2.13-built libraries are used. For more information:
1717
// https://www.scala-lang.org/blog/2021/04/08/scala-3-in-sbt.html
1818
libraryDependencies ++= Seq(
19-
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.14",
20-
"com.typesafe.akka" %% "akka-slf4j" % "2.6.14",
19+
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.19",
20+
"com.typesafe.akka" %% "akka-slf4j" % "2.6.19",
2121
).map(dep => dep.cross(CrossVersion.for3Use2_13)) ++ Seq(
2222
// Libraries that already fully support Scala 3:
23-
"org.typelevel" %% "cats-core" % "2.6.1",
23+
"org.typelevel" %% "cats-core" % "2.7.0",
2424
"org.scala-lang" %% "scala3-staging" % scalaVersion.value,
25-
"org.scala-lang.modules" %% "scala-parser-combinators" % "2.0.0",
25+
"org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1",
2626
"ch.qos.logback" % "logback-classic" % "1.2.11",
2727
"org.scalacheck" %% "scalacheck" % "1.15.4" % Test,
28-
"org.scalameta" %% "munit" % "0.7.26" % Test,
29-
"org.scalameta" %% "munit-scalacheck" % "0.7.26" % Test,
28+
"org.scalameta" %% "munit" % "0.7.29" % Test,
29+
"org.scalameta" %% "munit-scalacheck" % "0.7.29" % Test,
3030
"com.eed3si9n.expecty" %% "expecty" % "0.15.4" % Test,
3131
),
3232

inline-perf.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env zsh
2+
# A script to run progscala3.meta.performance.InlinePerf program that looks at runtime performance when inline is used.
3+
# See src/main/scala/progscala3/meta/performance/README.md for more details.
4+
for warmup in true #false
5+
do
6+
let n=1
7+
for i in {1..8} # Used to generate n = 10 to 100,000,000
8+
do
9+
let "n = 10*$n"
10+
echo "## N = $n, warm up = $warmup"
11+
# TIP: Invoke this script with "NOOP=echo ./inline-perf.sh" and it will just echo the following line, rather than run it.
12+
$NOOP sbt "runMain progscala3.meta.performance.InlinePerf $warmup $n"
13+
done
14+
done

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.5.5
1+
sbt.version=1.6.2

src/main/java/progscala3/objectsystem/JavaArrays.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
public class JavaArrays {
55
public static void main(String[] args) {
6+
System.out.println("*** A java.lang.ArrayStoreException will be thrown: ***");
67
Integer[] array1 = new Integer[] {
78
Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3) };
89
Number[] array2 = array1; // Compiles fine, but shouldn't!!

src/main/scala/progscala3/appdesign/parthenon/PayrollCalculator.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ object PayrollCalculator: // <1>
2121
(name, salary, ruleString) <- data
2222
yield Pay(name, salary, toDeductions(ruleString))
2323

24-
case class BadInput(message: String, input: String)
25-
extends RuntimeException(s"Bad input data, $message: $input")
24+
case class BadInput(message: String, input: String, array: Array[String])
25+
extends RuntimeException(s"""Bad input data, $message: "$input" (array = ${array.mkString("[", ",", "]")}) """)
2626

2727
private type Record = (String, Dollars, String) // <4>
2828

@@ -33,13 +33,13 @@ object PayrollCalculator: // <1>
3333
yield toRule(line)
3434

3535
private def toRule(line: String): Record = // <5>
36-
line.split("""\s*,\s.*""") match
36+
line.split("""\s*,\s*""") match
3737
case Array(name, salary, fedTax, stateTax, insurance, retirement) =>
3838
val ruleString = dsl.format(
3939
fedTax.toDouble, stateTax.toDouble,
4040
insurance.toDouble, retirement.toDouble)
4141
(name, Dollars(salary.toDouble), ruleString)
42-
case array => throw BadInput("expected six fields", line)
42+
case array => throw BadInput("expected six fields", line, array)
4343

4444
private val parser = PayrollParser() // <6>
4545
private def toDeductions(rule: String): Deductions =

src/main/scala/progscala3/basicoop/Abstract.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ open class HelloService(override val name: String) // <3>
4646

4747
// tag::main[]
4848
@main def HelloServiceMain(name: String, users: String*): Unit =
49-
val hs = HelloService("hello")
49+
val hs = HelloService(name)
5050
for
5151
user <- users
5252
request = Map("user" -> user)
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// src/main/scala/progscala3/meta/performance/InlinePerf.scala
2+
// This code does not appear in the book.
3+
package progscala3.meta.performance
4+
import scala.quoted.*
5+
import scala.math.random
6+
7+
@main def InlinePerf(warmup: Boolean, numberOfTrials: Int*) =
8+
9+
class Thing(var state: Double, var count: Long = 0L, var label: String):
10+
def update(): Unit =
11+
state = random()
12+
count += 1
13+
14+
def trialBaseline(n: Int): Long =
15+
val startBaseline = System.nanoTime()
16+
val thing = new Thing(0.0, 0L, "baseline")
17+
for i <- 1 to n do thing.update()
18+
val endBaseline = System.nanoTime()
19+
assert(thing.count == n) // Sanity check: thing.update was called and not optimized away.
20+
endBaseline - startBaseline
21+
22+
def trialEnabled(n: Int): Long =
23+
val startEnabled = System.nanoTime()
24+
val thing = new Thing(0.0, 0L, "enabled")
25+
for i <- 1 to n
26+
do
27+
invariantEnabled(thing.label == "enabled") {
28+
thing.update()
29+
}
30+
val endEnabled = System.nanoTime()
31+
assert(thing.count == n) // Sanity check: thing.update was called and not optimized away.
32+
endEnabled - startEnabled
33+
34+
def trialDisabled(n: Int): Long =
35+
val startDisabled = System.nanoTime()
36+
val thing = new Thing(0.0, 0L, "disabled")
37+
for i <- 1 to n
38+
do
39+
invariantDisabled(thing.label == "disabled") {
40+
thing.update()
41+
}
42+
val endDisabled = System.nanoTime()
43+
assert(thing.count == n) // Sanity check: thing.update was called and not optimized away.
44+
endDisabled - startDisabled
45+
46+
def trialMinInline(n: Int): Long =
47+
val startMinInline = System.nanoTime()
48+
val thing = new Thing(0.0, 0L, "min-inline")
49+
for i <- 1 to n
50+
do
51+
invariantMinInline(thing.label == "min-inline") {
52+
thing.update()
53+
}
54+
val endMinInline = System.nanoTime()
55+
assert(thing.count == n) // Sanity check: thing.update was called and not optimized away.
56+
endMinInline - startMinInline
57+
58+
def separator() =
59+
println( "|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|")
60+
61+
def header() =
62+
separator()
63+
println(f"| N | Elapsed Times (nanoseconds), JVM Warmup? $warmup%5s |")
64+
println( "| | Baseline | Enabled | Disabled | E/B% | D/B% | E/D% | MinInline | M/B% | M/E% |")
65+
separator()
66+
67+
header()
68+
val ns = if numberOfTrials.size == 0 then Seq(1000000) else numberOfTrials
69+
// Warm up the JVM with 1000000 runs.
70+
// The warmup causes DRAMATICALLY different results!
71+
if warmup then
72+
trialBaseline(1000000)
73+
trialMinInline(1000000)
74+
trialEnabled(1000000)
75+
trialDisabled(1000000)
76+
77+
for n <- numberOfTrials
78+
do
79+
val timeBaseline = trialBaseline(n)
80+
val timeMinInline = trialMinInline(n)
81+
val timeEnabled = trialEnabled(n)
82+
val timeDisabled = trialDisabled(n)
83+
val percentEB = (100.0 * timeEnabled)/timeBaseline
84+
val percentDB = (100.0 * timeDisabled)/timeBaseline
85+
val percentED = (100.0 * timeEnabled)/timeDisabled
86+
val percentMB = (100.0 * timeMinInline)/timeBaseline
87+
val percentME = (100.0 * timeMinInline)/timeEnabled
88+
println(f"| $n%9d | $timeBaseline%10d | $timeEnabled%10d | $timeDisabled%10d " +
89+
f"| $percentEB%7.2f%% | $percentDB%7.2f%% | $percentED%7.2f%% " +
90+
f"| $timeMinInline%10d | $percentMB%7.2f%% | $percentME%7.2f%% |")
91+
separator()
92+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// src/main/scala/progscala3/meta/performance/InvariantDisabled.scala
2+
// This code does not appear in the book.
3+
package progscala3.meta.performance
4+
import scala.quoted.*
5+
6+
object invariantDisabled:
7+
inline val ignore = true
8+
9+
inline def apply[T](
10+
inline predicate: => Boolean, message: => String = "")(
11+
inline block: => T): T =
12+
inline if !ignore then
13+
if !predicate then fail(predicate, message, block, "before")
14+
val result = block
15+
if !predicate then fail(predicate, message, block, "after")
16+
result
17+
else
18+
block
19+
20+
inline private def fail[T](
21+
inline predicate: => Boolean,
22+
inline message: => String,
23+
inline block: => T,
24+
inline beforeAfter: String): Unit =
25+
${ failImpl('predicate, 'message, 'block, 'beforeAfter) }
26+
27+
case class InvariantFailure(msg: String) extends RuntimeException(msg)
28+
29+
private def failImpl[T](
30+
predicate: Expr[Boolean], message: Expr[String],
31+
block: Expr[T], beforeAfter: Expr[String])(
32+
using Quotes): Expr[String] =
33+
'{ throw InvariantFailure(
34+
s"""FAILURE! predicate "${${showExpr(predicate)}}" """
35+
+ s"""failed ${$beforeAfter} evaluation of block:"""
36+
+ s""" "${${showExpr(block)}}". Message = "${$message}". """)
37+
}
38+
39+
private def showExpr[T](expr: Expr[T])(using Quotes): Expr[String] =
40+
val code: String = expr.show
41+
Expr(code)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// src/main/scala/progscala3/meta/performance/InvariantEnabled.scala
2+
// This code does not appear in the book.
3+
package progscala3.meta.performance
4+
import scala.quoted.*
5+
6+
object invariantEnabled:
7+
inline val ignore = false
8+
9+
inline def apply[T](
10+
inline predicate: => Boolean, message: => String = "")(
11+
inline block: => T): T =
12+
inline if !ignore then
13+
if !predicate then fail(predicate, message, block, "before")
14+
val result = block
15+
if !predicate then fail(predicate, message, block, "after")
16+
result
17+
else
18+
block
19+
20+
inline private def fail[T](
21+
inline predicate: => Boolean,
22+
inline message: => String,
23+
inline block: => T,
24+
inline beforeAfter: String): Unit =
25+
${ failImpl('predicate, 'message, 'block, 'beforeAfter) }
26+
27+
case class InvariantFailure(msg: String) extends RuntimeException(msg)
28+
29+
private def failImpl[T](
30+
predicate: Expr[Boolean], message: Expr[String],
31+
block: Expr[T], beforeAfter: Expr[String])(
32+
using Quotes): Expr[String] =
33+
'{ throw InvariantFailure(
34+
s"""FAILURE! predicate "${${showExpr(predicate)}}" """
35+
+ s"""failed ${$beforeAfter} evaluation of block:"""
36+
+ s""" "${${showExpr(block)}}". Message = "${$message}". """)
37+
}
38+
39+
private def showExpr[T](expr: Expr[T])(using Quotes): Expr[String] =
40+
val code: String = expr.show
41+
Expr(code)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// src/main/scala/progscala3/meta/performance/InvariantMinInline.scala
2+
// This code does not appear in the book.
3+
package progscala3.meta.performance
4+
import scala.quoted.*
5+
6+
object invariantMinInline:
7+
val ignore = false
8+
9+
inline def apply[T](
10+
predicate: => Boolean, message: => String = "")(
11+
block: => T): T =
12+
if !ignore then
13+
if !predicate then fail(predicate, message, block, "before")
14+
val result = block
15+
if !predicate then fail(predicate, message, block, "after")
16+
result
17+
else
18+
block
19+
20+
inline private def fail[T](
21+
predicate: => Boolean,
22+
message: => String,
23+
block: => T,
24+
beforeAfter: String): Unit =
25+
${ failImpl('predicate, 'message, 'block, 'beforeAfter) }
26+
27+
case class InvariantFailure(msg: String) extends RuntimeException(msg)
28+
29+
private def failImpl[T](
30+
predicate: Expr[Boolean], message: Expr[String],
31+
block: Expr[T], beforeAfter: Expr[String])(
32+
using Quotes): Expr[String] =
33+
'{ throw InvariantFailure(
34+
s"""FAILURE! predicate "${${showExpr(predicate)}}" """
35+
+ s"""failed ${$beforeAfter} evaluation of block:"""
36+
+ s""" "${${showExpr(block)}}". Message = "${$message}". """)
37+
}
38+
39+
private def showExpr[T](expr: Expr[T])(using Quotes): Expr[String] =
40+
val code: String = expr.show
41+
Expr(code)

0 commit comments

Comments
 (0)