Is there a one-line way to provide a named reference to a value which is to be implicitly available (i.e. available with using
syntax) without the soon-to-be-deprecated implicit
keyword? According to the docs, I'd expect the following to work (under SBT, scalaVersion := "3.0.0-M2"
:
trait Greeter {
def sayHello(username: String): Unit
def shutdown(): Unit
}
def greet(username: String)(using g: Greeter): Unit = {
g.sayHello(username)
}
object Foo extends App {
given greeter: Greeter = new Greeter {
override def sayHello(username: String): Unit = println(s"Hello, ${username}!")
override def shutdown(): Unit = println("Shutting down")
}
try {
greet("world")
} finally {
greeter.shutdown()
}
}
but this fails with
[error] -- Error: /path/to/project/src/main/scala/Foo.scala:12:15
[error] 12 | given greeter: Greeter = new Greeter {
[error] | ^
[error] | end of statement expected but ':' found
[error] -- [E040] Syntax Error: /path/to/project/src/main/scala/Foo.scala:12:17
[error] 12 | given greeter: Greeter = new Greeter {
[error] | ^^^^^^^
[error] | ';' expected, but identifier found
Now: I can work around this in many ways, but either the docs are confusing (or wrong) or I'm misunderstanding something rather fundamental.
Workaround 1 (as suggested here):
lazy val greeter: Greeter = new Greeter {
override def sayHello(username: String): Unit = println(s"Hello, ${username}!")
override def shutdown(): Unit = println("Shutting down")
}
given Greeter = greeter
...
but I'd like to be able to do this in a single expression rather than two. The same comment applies to defining the given first and then binding it to a name:
given Greeter with {
override def sayHello(username: String): Unit = println(s"Hello, ${username}!")
override def shutdown(): Unit = println("Shutting down")
}
val greeter: Greeter = implicitly
especially since I think implicitly
will be deprecated in 3.1 and gone in 3.2.
We could also wrap our invocations of the given object in functions to get around this:
def greet(username: String)(using g: Greeter): Unit = {
g.sayHello(username)
}
def shutdown(using greeter: Greeter): Unit = {
greeter.shutdown()
}
given Greeter with {
override def sayHello(username: String): Unit = println(s"Hello, ${username}!")
override def shutdown(): Unit = println("Shutting down")
}
try {
greet("world")
} finally {
shutdown
}
but that seems boilerplateful to me.
Turns out that the
given x: T = ...
syntax was added between revision M2 and revision RC1. The following works with scalaVersion := "3.0.0-RC1"
:
trait Greeter {
def sayHello(username: String): Unit
def shutdown(): Unit
}
def greet(username: String)(using g: Greeter): Unit = {
g.sayHello(username)
}
object Foo extends App {
given greeter: Greeter with {
override def sayHello(username: String): Unit = println(s"Hello, ${username}!")
override def shutdown(): Unit = println("Shutting down")
}
try {
greet("world")
} finally {
greeter.shutdown()
}
}