Reputation: 923
I'm trying to define a class whose instances have a String
and a function. In the function the String
parameter is used.
class Tenant(val name: String, exclusion: Map[String, Int] => Boolean)
val rule1 = new Tenant(name = "Baker3",
(suggestedFloor: Map[String, Int]) => suggestedFloor(name) != topFloor)
val rule1 = new Tenant(name = "Cooper2",
(suggestedFloor: Map[String, Int]) => suggestedFloor(name) != groundFloor)
Which gives an error on the last use of name: not found: value name
.
How can I do that?
Upvotes: 0
Views: 87
Reputation: 38217
Problem:
You are trying to reference the name name
in a lexical context where it's simply not available:
val rule1 = new Tenant(name = "Cooper2",
(suggestedFloor: Map[String, Int]) => suggestedFloor(name) != groundFloor)
— name
in this context does not refer to the name
defined within Tenant
, but instead a to the name name
in the scope of the rule1
definition, where of course it obviously does not exist. With this code, the error would disappear but of course this is not what you want:
val name = ??? // this is the `name` that gets referenced by the lambda
val rule1 = new Tenant(name = "Cooper2",
(suggestedFloor: Map[String, Int]) => suggestedFloor(name) != groundFloor)
Solution:
To work around that, instead of passing in a function at the time of instantiation, use a method override instead:
abstract class Tenant(val name: String) {
def exclusion(suggestedFloor: Map[String, Int]): Boolean
}
val rule1 = new Tenant(name = "Baker3") {
def exclusion(suggestedFloor: Map[String, Int]) =
suggestedFloor(name) != topFloor
}
This creates an anonymous subclass of Tenant
with a "custom" definition for exclusion
; this, I would say, is also considered idiomatic style in Scala.
Alternatively, you can resort to slightly different semantics and override not a method but an attribute that contains a function instead; this will yield shorter syntax when combined with the more compact form of lambda definition using _
:
abstract class Tenant(val name: String) {
val exclusion: Map[String, Int] => Boolean
}
val rule1 = new Tenant(name = "Baker3") {
val exclusion = (_: Map[String, Int])(name) != topFloor
}
Unfortunately, the need for the Map[String, Int]
re-declaration, is not eliminated by the type inferencer, for reasons only people smarter than me can elaborate on.
Upvotes: 2
Reputation: 21557
You need to curry you function or class declaration:
class Tenant(name: String)(exclusion: Map[String, Int] => Boolean = _(name) != topFloor)
Now make an instance:
scala> new Tenant("hello")()
res8: Tenant = Tenant@13c3c24f
Upvotes: 0