Reputation: 391
I'm new to Scala, trying to master DSL creation tricks. Can't figure out why compiler behaves differently in the following 2 scenarios when a) I instantiate class B directly and b) when I do the same by wrapper method or value.
object Example {
def createB: B = new B
class B
def createA: A = new A
class A {
def aMethod(b: B)(p: String => Unit): Unit = {}
}
def main(args: Array[String]) {
// this compiles fine
createA aMethod new B { s: String =>
}
// this does not compile, as compiler tries to apply function (String => Unit) to class B
createA aMethod createB { s: String =>
}
// this does not compile either
val bb = new B
createA aMethod bb { s: String =>
}
}
}
Upvotes: 1
Views: 69
Reputation: 1230
Your first example:
createA aMethod new B { s: String => }
may compile, but it isn't doing what you expect. You are actually constructing an instance of B that has the self type of String (refer to this and this for more information). The return type of that statement then is a Function that takes a Function of String to Unit and returns Unit. More simply, you have not provided a value for parameter p to your function, aMethod.
Your issue in all three examples is just a syntactic one. The compiler is really confused and doesn't know where you are giving it a function and where you are extending classes. When that is the case I like to explicitly add the periods and parens for function calls. All three of these should now compile and do what you want:
createA.aMethod(new B) { s: String =>
}
createA.aMethod(createB){ s: String =>
}
val bb = new B
createA.aMethod(bb){ s: String =>
}
Edit: An alternative by directly calling apply on the curried function, this may be your best bet:
class A {
def aMethod(b: B)(p: String => Unit): Unit = {}
}
def main(args: Array[String]) {
createA aMethod new B apply { s: String =>
}
createA aMethod createB apply { s: String =>
}
val bb = new B
createA aMethod bb apply { s: String =>
}
}
If you hate using 'apply' you could also construct an object with whatever name you want:
class A {
def aMethod(b: B) = new {
def myCoolName(p: String => Unit): Unit = {}
}
}
def main(args: Array[String]) {
createA aMethod new B myCoolName { s: String =>
}
createA aMethod createB myCoolName { s: String =>
}
val bb = new B
createA aMethod bb myCoolName { s: String =>
}
}
Another alternative with aMethod not curried:
class A {
def aMethodNotCurried(b: B, p: String => Unit): Unit = {}
}
def mainNotCurried(args: Array[String]) {
createA aMethodNotCurried (new B, { s: String =>
})
createA aMethodNotCurried (createB, { s: String =>
})
val bb = new B
createA aMethodNotCurried (bb, { s: String =>
})
}
Upvotes: 1