What's the difference of the following definition?
1.def debug(msg: => AnyRef) = { println(String.valueOf(msg)) }
2.def debug(msg: () => AnyRef) = { println(String.valueOf(msg)) }
The first definition can accept any thing, string, or function etc. but the second one can only accept function. I'd like to know reazon.
scala> def debug(msg: => AnyRef) = { println(String.valueOf(msg)) }
debug: (msg: => AnyRef)Unit
scala> debug("hi")
hi
scala> debug(() => "xx")
<function0>
scala> def debug(msg: () => AnyRef) = { println(String.valueOf(msg)) }
debug: (msg: () => AnyRef)Unit
scala> debug("hi")
<console>:9: error: type mismatch;
found : java.lang.String("hi")
required: () => AnyRef
debug("hi")
^
The first is a call-by-name parameter, i.e. it evaluates the the argument each time it is used in the method, and only if it is used. As you have discovered, this can be anthing that evaluates to the required type.
The second takes specifically a Function0[AnyRef] object. You can think of the () as an empty parameter list (not to be confused with the Unit value, which is written the same).
Related
What I want to achieve is the 2 functions (one of them is no arg function) are composed into one.
Here is an example to give you idea what I am doing:
object Test extends App {
val zeroArgFunc = () => 10
val intArgFunc = (i: Int) => s"hello $i"
val stringArgFunc = (s: String) => println(s)
// This line works perfectly fine.
val intAndThenString: Int => Unit = stringArgFunc compose intArgFunc
// But this line fails with 'type mismatch' compilation error.
val zeroAndThenInt: () => String = intArgFunc compose zeroArgFunc
}
Compilation error:
[error] found : () => Int
[error] required: ? => Int
[error] val zeroAndThenInt: () => String = intArgFunc compose zeroArgFunc
[error] ^
[error] one error found
Any idea what's wrong?
[UPD] The Scala version is 2.13.1 (if it matters).
Desugaring () => 10 we have
new Function0[Int] { def apply() = 10 }
and Function0 does not have compose or andThen methods
trait Function0[... +R] extends ... { ...
def apply(): R
override def toString(): String = "<function0>"
}
so it seems Function0 cannot be composed.
On the other hand (i: Int) => s"hello $i" and (s: String) => println(s) correspond to Function1 which does have compose method defined, hence they can be composed.
Consider changing () => 10 to (_: Unit) => 10 which changes the type from Function0 to Function1, and then
(intArgFunc compose zeroArgFunc)()
outputs res4: String = hello 10.
Addressing comment by #Duelist, IMHO Function0[T] is not semantically equivalent to Function1[Unit, T]. For example, given
val f = () => 10
val g = (_: Unit) => 10
then
f()
g()
indeed outputs
res7: Int = 10
res8: Int = 10
however
f(println("woohoo")) // error: no arguments allowed for nullary method apply
g(println("woohoo")) // OK!
where we see the two do not have the same behaviour. Nevertheless, if you would like to consider them as equivalent perhaps you could define an extension method on Function0 and be explicit about conversion, for example
implicit class Fun0ToFun1[A, B](f: () => A) {
def toFun1: Unit => A = (_: Unit) => f()
}
would allow the following syntax
(intArgFunc compose zeroArgFunc.toFun1)()
Addressing comment by #egordoe, out-of-the-box compose is only ever defined for Function1, thus Function2, Function3, etc., cannot be composed just like Function0. However we could define extension composeN methods on function, for example, say we want to compose Function1 with Function0, then
implicit class ComposeFun1WithFun0[A, B](f1: A => B) {
def compose0(f2: () => A): () => B = () => f1(f2())
}
gives
(intArgFunc compose0 zeroArgFunc)()
compose on Function1 (which intArgFunc is) is just defined to only accept single-argument functions:
def compose[A](g: (A) => T1): (A) => R
You could write helper functions to convert () => A to/from Unit => A
def toUnitFun[A](f: () => A): Unit => A = _ => f()
def fromUnitFun[A](f: Unit => A): () => A = () => f(())
and then
val zeroAndThenInt = fromUnitFun(intArgFunc compose toUnitFun(zeroArgFunc))
You can even make your original code work by marking to/fromUnitFun as implicit.
The signature of the function getOrElse(...) of Scala's Option[+A] class is
final def getOrElse[B >: A](default: ⇒ B): B
If I use the example
val o1 = Option("Hi")
val o2: Option[String] = Option(null)
println(o1.getOrElse(() => "Else"))
println(o2.getOrElse(() => "Else"))
I get the output
Hi
<function0>
The Scala API says about getOrElse(...):
Returns the option's value if the option is nonempty, otherwise return the result of evaluating default.
But () => "Else") is not evaluated.
The result cannot be evaluated by using brackets:
o2.getOrElse(() => "Else")()
error: Object does not take parameters
o2.getOrElse( () => "Else")()
^
How can I evaluate the result and why it is not evaluated automatically?
Is default: ⇒ B the same as default: () ⇒ B ?
Is default: ⇒ B the same as default: () ⇒ B
No, the first is call by name and the second is a thunk. The type of a call by name parameter is the type of the parameter itself, where the type of a thunk is () => T which is the same as Function0[T].
When you do o1.getOrElse(() => "Else") you are working with heterogeneous types, so Scala will find the least common super type which is in this case is Any.
val orElse: Any = o1.getOrElse(() => "Else")
Consider this:
val e: Function0[String] = () => "Else"
Then you can write:
println(o1.getOrElse(e)) //Hi
println(o2.getOrElse(e)) //<function0>
println(o2.getOrElse(e())) //Else
println(o2.getOrElse((() => "Else")())) //Else
So, suppose, I want to provide a "catch all" fall back for a PartialFunction:
val foo: PartialFunction[Int, String] = { case 1 => "foo" }
val withDefault = foo orElse { _.toString }
This does not compile: missing parameter type for expanded function ((x$1) => x$1.toString).
This:
val withDefault = foo orElse { case x: Int => x.toString }
Does not compile either (same error).
This:
val withDefault = foo orElse { (x: Int) => x.toString }
fails with type mismatch; found : Int => String; required: PartialFunction[?,?]
The only way I could find to make it work is to spell out the whole thing:
val withDefault = foo orElse PartialFunction[Int, String] { _.toString }
Is there any better syntax for this? I mean, one without having to tell it that I am passing a partial function from int to string to where it expects to receive a partial function from in to string. This is not ambiguous at all, why do I have to do this?
Maybe you need applyOrElse:
val withDefault = foo.applyOrElse(_: Int, (_: Int).toString)
Or maybe you would like something like this:
implicit class PartialFunToFun[A,B](val f: PartialFunction[A,B]) extends AnyVal {
def withDefault(bar: A => B) = f.applyOrElse[A,B](_: A, bar)
}
and use it: foo.withDefault(_.toString)(1)
Also if you want to get just another PartialFunction you can use the next syntax:
val withDefault = foo.orElse[Int, String]{case x => x.toString}
The errors you encountered for the first two are not specific to orElse. They also occur when you attempt to define the same functions separately.
scala> { _.toString }
<console>:12: error: missing parameter type for expanded function ((x$1: <error>) => x$1.toString)
{ _.toString }
scala> { case x: Int => x.toString }
<console>:12: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
{ case x: Int => x.toString }
^
For the last one, you are defining a function rather than a PartialFunction, thus leading to the "type mismatch" since orElse expects a PartialFunction to be passed.
scala> { (x: Int) => x.toString }
res3: Int => String = $$Lambda$1127/2044272973#3d5790ea
The final thing I'll add is that orElse is meant as a way to union two PartialFunctions. _.toString in itself is not a PartialFunction, though you could create a PartialFunction that uses it. To me it sounds like you want to have a "default" result for all the values that foo is not defined for, so I think you actually want applyOrElse instead since that is its use case. See the API to learn more.
I am having trouble getting my code with parameterized types to pass the scala compiler. My goal is to be able to express (Predicate, Action) pairs as shown in the MyProg object.
trait ProgBase {
type Predicate[T] = T => Boolean
type Action[T] = T => Unit
private var prog = List[(Predicate[Any], Action[Any])]()
final def on[T <: Any](pred: Predicate[T])(action: Action[T]) = {
prog = (pred, action) :: prog // gives type mismatch
}
// remainder of trait elided
}
object MyProg extends ProgBase {
on[String](s => !s.isEmpty) { s =>
println(s + " is not empty")
}
on[Int](i => i.isValidByte) { i =>
println(i + " can fit in a byte")
}
}
By specifying that T has an upper bound of Any, I hoped this would appease the compiler, but clearly I am missing something:
[error] ......ProgBase.scala:8 type mismatch;
[error] found : (T => Boolean, T => Unit)
[error] required: (Any => Boolean, Any => Unit)
[error] prog = (pred, action) :: prog
[error] ^
First of all, answer to your question, if you write:
private var prog = List[(Predicate[_ <: Any], Action[_ <: Any])]()
It all compiles OK. We should use wildcards, 'cause the type of elements are unknown.
Second, maybe you mistyped, you can't use your on function as you used it, use it something like:
on[String](s => !s.isEmpty)(s => !s.isEmpty)
It caused by type mismatch: type Action[T] = T => Unit but println has type Unit,
so as a variant u can simply write: type Action = Unit. Obviously, u can avoid using this type alias at all.
Third, maybe you already know, and I shoudn't tell you, that in fact, you lose all information about predicate types - let's check it using Scala reflection:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
val s: String = "123"
val i: Int = 123
on[String](s => !s.isEmpty)(s => !s.isEmpty)
on[Int](i => i.isValidByte)(i => i.isValidByte)
getTypeTag((MyProg.prog.head._1)).tpe =:= ru.typeOf[(String) => Boolean] //>false!
So you see the problem.
To deal with it you can use heterogeneous lists. Lists and other various powerful structures you can find in shapeless: https://github.com/milessabin/shapeless
There's an example in "Scala in Depth" where the author is explaining how scala can do some level of inference on the arguments passed into the methods. As an example the following is shown:
def myMethod(functionLiteral: A => B):Unit
myMethod({ arg:A => new B})
myMethod({ arg => new B})
Just to figure out what the author is talking about, I do the following in the REPL:
def myMethod(functionLiteral: Boolean => Boolean):Unit = {}
myMethod({a:Boolean => true})
myMethod({a => true})
The only revelatory thing that happens here is that the compiler doesn't throw an error.
Is the author trying to say that the function argument a is inferred to be a Boolean by the compiler?
Yes the author is saying that dont need to specify that a is a Boolean in myMethod({a => true}) because the type is Boolean => Boolean
== Original answer which makes the first bit compile but misses the point a bit ==
It needed to Be typed with [A,B].
def myMethod[A,B](functionLiteral: A => B): Unit = {}
myMethod((arg:String) => arg.length)
myMethod((arg:Int) => (1 to arg).map(_ *2))
I modified it to return the function so you can see the types in the repl.
scala> def myMethod[A,B](functionLiteral: A => B): A => B = functionLiteral
myMethod: [A, B](functionLiteral: (A) => B)(A) => B
scala> myMethod((arg:String) => arg.length)
res11: (String) => Int = <function1>
scala> res11("hello world!")
res12: Int = 12
scala> myMethod((arg:Int) => (1 to arg).map(_ *2))
res13: (Int) => scala.collection.immutable.IndexedSeq[Int] = <function1>
scala> res13(4)
res14: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8)
Is the author trying to say that the function argument a is inferred to be a Boolean by the compiler?
Absolutely.
Given the following method:
def myMethod(functionLiteral: Boolean => Boolean):Unit = {}
The compiler knows that the parameter to myMethod is a function that takes a boolean parameter, so it does not need you to specify it. In other words, in the following a is unambiguously a boolean parameter:
myMethod{a => true}
Now, it is worth noting that this does not work anymore when mixed with overloading:
def myMethod(functionLiteral: Boolean => Boolean):Unit = {}
def myMethod(functionLiteral: Int => Boolean):Unit = {}
myMethod{a => true} // error: missing parameter type
The reason is that it cannot unambiguously tell if a is of type Boolean or Int.