def foo(implicit i: Int = 1) = i
def bar(implicit j: Int) = foo()
bar(4)
This piece of code evaluates to 1. So the default value has priority over the implicit j, which is instantiated to 4. Therefore, it seems that, at least in this example, the default parameter value trumps implicit, making the definition of foo equivalent to def foo(i: Int = 1) = i.
Do default parameter values always trump implicits? If yes, why is this code legal (given that it is confusing)? If not, what is a counter-example?
Is there a way to get the other behavior, i.e. that a piece of code similar to the above (with a default value for i) would evaluate to 4, without having to pass the argument explicitly?
implicit is applied to the entire parameter list, not just a single parameter (e.g., you can have foo(implicit i: Int, j: Int), and both parameters are implicit, but, if you wanted only one of them to be, you'd have to split them in two lists: def foo(i: Int)(implicit j: Int).
So, to pass implicit parameters to the function, you have to omit the entire list: foo, not foo().
When you have def foo(implicit i: Int), foo() does not even compile, because you are trying to send an empty parameter to list. foo does (as long as an implicit int is in scope), because the list is passed implicitly.
With def foo(implicit i: Int = 1), both uses compile, but mean different things. foo() means "call foo with default values for all parameters", foo means "call foo, passing the implicit parameter list".
So, with bar(implicit j: Int) = foo it will evaluate to the value of j, while bar(implicit j: Int) = foo() evaluates to 1.
Scala compiler gets confused between implicit and default value. foo() makes the compiler to ignore implicit. so just foo does the trick here
def foo(implicit i: Int = 1) = i
def bar(implicit j: Int) = foo
println(bar(5))
Result : 5
Related
Started learning Scala today, and I was curious if you can overload a function to add currying like:
def add(x: Int, y: Int): Int = x + y
def add(x: Int)(y: Int): Int = x + y
But not only does this code not compile, but I've heard that overloading in Scala is not a good idea.
Is there a way to overload add such that it's curried without doing partial application, meaning both add(1, 2) and add(1)(2) work?
The problem is that those add functions are indistinguishable after JVM type erasure: during execution they are both (Int, Int)Int. But they are different during compilation, and Scala compiler can tell which one you are calling.
This means you have to make their argument lists different. To achieve that you can add an implicit argument list with a DummyImplicit argument:
def add(x: Int, y: Int)(implicit dummy: DummyImplicit): Int = x + y
def add(x: Int)(y: Int): Int = x + y
This DummyImplicit is provided by Scala library, and there is always an implicit value for it. Now the first function after erasure has a type (Int, Int, DummyImplicit)Int, and the second one (Int, Int)Int, so JVM can distinguish them.
Now you can call both:
add(1, 2)
add(1)(2)
I've got a way you can use add(1,2) and add(1)(2) but I wouldn't recommend it. It uses Scala's implicit definitions to have a different type for both methods, but use an implicit method to convert to the appropriate type.
case class IntWrapper(value: Int) // Purely to have a different type
object CurryingThing
{
def add(x: IntWrapper)(y: IntWrapper) = x.value + y.value
def add(x: Int, y: Int) = x + y
// The magic happens here. In the event that you have an int, but the function requires an intWrapper (our first function definition), Scala will invoke this implicit method to convert it
implicit def toWrapper(x: Int) = IntWrapper(x)
def main(args: Array[String]) = {
// Now you can use both add(1,2) and add(1)(2) and the appropriate function is called
println(add(1,2)) //Compiles, prints 3
println(add(1)(2)) // Compiles, prints 3
()
}
}
For overloading it's necessary that function should either:
have different number of arguments
or have different argument type(s)
In your example both definitions of add are equivalent hence it's not overloading and you get compilation error.
You could use Kolmar's way (implicit object) below to call both add(1, 2) and add(1)(2) OR you can use Scala's Default Parameter to achieve same thing:
def add(a: Int, b: Int, c: Any = DummyImplicit) = a + b // c is default parameter
def add(a: Int)(b: Int) = a + b
About:
I've heard that overloading in Scala is not a good idea.
You can see Why "avoid method overloading"?
There is a significant difference in how Scala resolves implicit conversions from "Magnet Pattern" for non-overloaded and overloaded methods.
Suppose there is a trait Apply (a variation of a "Magnet Pattern") implemented as follows.
trait Apply[A] {
def apply(): A
}
object Apply {
implicit def fromLazyVal[A](v: => A): Apply[A] = new Apply[A] {
def apply(): A = v
}
}
Now we create a trait Foo that has a single apply taking an instance of Apply so we can pass it any value of arbitrary type A since there an implicit conversion from A => Apply[A].
trait Foo[A] {
def apply(a: Apply[A]): A = a()
}
We can make sure it works as expected using REPL and this workaround to de-sugar Scala code.
scala> val foo = new Foo[String]{}
foo: Foo[String] = $anon$1#3a248e6a
scala> showCode(reify { foo { "foo" } }.tree)
res9: String =
$line21$read.foo.apply(
$read.INSTANCE.Apply.fromLazyVal("foo")
)
This works great, but suppose we pass a complex expression (with ;) to the apply method.
scala> val foo = new Foo[Int]{}
foo: Foo[Int] = $anon$1#5645b124
scala> var i = 0
i: Int = 0
scala> showCode(reify { foo { i = i + 1; i } }.tree)
res10: String =
$line23$read.foo.apply({
$line24$read.`i_=`($line24$read.i.+(1));
$read.INSTANCE.Apply.fromLazyVal($line24$read.i)
})
As we can see, an implicit conversion has been applied only on the last part of the complex expression (i.e., i), not to the whole expression. So, i = i + 1 was strictly evaluated at the moment we pass it to an apply method, which is not what we've been expecting.
Good (or bad) news. We can make scalac to use the whole expression in the implicit conversion. So i = i + 1 will be evaluated lazily as expected. To do so we (surprize, surprize!) we add an overload method Foo.apply that takes any type, but not Apply.
trait Foo[A] {
def apply(a: Apply[A]): A = a()
def apply(s: Symbol): Foo[A] = this
}
And then.
scala> var i = 0
i: Int = 0
scala> val foo = new Foo[Int]{}
foo: Foo[Int] = $anon$1#3ff00018
scala> showCode(reify { foo { i = i + 1; i } }.tree)
res11: String =
$line28$read.foo.apply($read.INSTANCE.Apply.fromLazyVal({
$line27$read.`i_=`($line27$read.i.+(1));
$line27$read.i
}))
As we can see, the entire expression i = i + 1; i made it under the implicit conversion as expected.
So my question is why is that? Why the scope of which an implicit conversion is applied depends on the fact whether or not there is an overloaded method in the class.
Now, that is a tricky one. And it's actually pretty awesome, I didn't know that "workaround" to the "lazy implicit does not cover full block" problem. Thanks for that!
What happens is related to expected types, and how they affect type inference works, implicit conversions, and overloads.
Type inference and expected types
First, we have to know that type inference in Scala is bi-directional. Most of the inference works bottom-up (given a: Int and b: Int, infer a + b: Int), but some things are top-down. For example, inferring the parameter types of a lambda is top-down:
def foo(f: Int => Int): Int = f(42)
foo(x => x + 1)
In the second line, after resolving foo to be def foo(f: Int => Int): Int, the type inferencer can tell that x must be of type Int. It does so before typechecking the lambda itself. It propagates type information from the function application down to the lambda, which is a parameter.
Top-down inference basically relies on the notion of expected type. When typechecking a node of the AST of the program, the typechecker does not start empty-handed. It receives an expected type from "above" (in this case, the function application node). When typechecking the lambda x => x + 1 in the above example, the expected type is Int => Int, because we know what parameter type is expected by foo. This drives the type inference into inferring Int for the parameter x, which in turn allows to typecheck x + 1.
Expected types are propagated down certain constructs, e.g., blocks ({}) and the branches of ifs and matches. Hence, you could also call foo with
foo({
val y = 1
x => x + y
})
and the typechecker is still able to infer x: Int. That is because, when typechecking the block { ... }, the expected type Int => Int is passed down to the typechecking of the last expression, i.e., x => x + y.
Implicit conversions and expected types
Now, we have to introduce implicit conversions into the mix. When typechecking a node produces a value of type T, but the expected type for that node is U where T <: U is false, the typechecker looks for an implicit T => U (I'm probably simplifying things a bit here, but the gist is still true). This is why your first example does not work. Let us look at it closely:
trait Foo[A] {
def apply(a: Apply[A]): A = a()
}
val foo = new Foo[Int] {}
foo({
i = i + 1
i
})
When calling foo.apply, the expected type for the parameter (i.e., the block) is Apply[Int] (A has already been instantiated to Int). We can "write" this typechecker "state" like this:
{
i = i + 1
i
}: Apply[Int]
This expected type is passed down to the last expression of the block, which gives:
{
i = i + 1
(i: Apply[Int])
}
at this point, since i: Int and the expected type is Apply[Int], the typechecker finds the implicit conversion:
{
i = i + 1
fromLazyVal[Int](i)
}
which causes only i to be lazified.
Overloads and expected types
OK, time to throw overloads in there! When the typechecker sees an application of an overload method, it has much more trouble deciding on an expected type. We can see that with the following example:
object Foo {
def apply(f: Int => Int): Int = f(42)
def apply(f: String => String): String = f("hello")
}
Foo(x => x + 1)
gives:
error: missing parameter type
Foo(x => x + 1)
^
In this case, the failure of the typechecker to figure out an expected type causes the parameter type not to be inferred.
If we take your "solution" to your issue, we have a different consequence:
trait Foo[A] {
def apply(a: Apply[A]): A = a()
def apply(s: Symbol): Foo[A] = this
}
val foo = new Foo[Int] {}
foo({
i = i + 1
i
})
Now when typechecking the block, the typechecker has no expected type to work with. It will therefore typecheck the last expression without expression, and eventually typecheck the whole block as an Int:
{
i = i + 1
i
}: Int
Only now, with an already typechecked argument, does it try to resolve the overloads. Since none of the overloads conforms directly, it tries to apply an implicit conversion from Int to either Apply[Int] or Symbol. It finds fromLazyVal[Int], which it applies to the entire argument. It does not push it inside the block anymore, giving:
fromLazyVal({
i = i + 1
i
}): Apply[Int]
In this case, the whole block is lazified.
This concludes the explanation. To summarize, the major difference is the presence vs absence of an expected type when typechecking the block. With an expected type, the implicit conversion is pushed down as much as possible, down to just i. Without the expected type, the implicit conversion is applied a posteriori on the entire argument, i.e., the whole block.
I'm intrigued by the following Scala compiler behavior. When i declare a function of type unit, but nevertheless provide as body a function that evaluate to an Int, the Scala compiler is ok with it.
def add(x:Int, y:Int) = x + y
def main(args: Array[String]): Unit = {add(args(0).toInt, args(0).toInt)}
While the same is not true with other type such in
def afunc: String = {1} //type mismatch; found : Int(1) required: String
Also if i write
def afunc: Unit = {1}
or
def main(args: Array[String]): Unit = {2 + 2} // Which is just like the first addition above
In both case i get the following warning:
a pure expression does nothing in statement position; you may be omitting necessary parentheses
In a sense there is 2 questions here. What is the difference between a function that return evaluate to an Int and the expression 2 + 2. Then why on earth, the compiler does not complain that a function that is suppose to evaluate to Unit, gets a body that evaluate to another type, as it would happens between other types.
Many thanks in advance,
Maatari
What is the difference between a function that return evaluate to an
Int and the expression 2 + 2.
A function that evaluates to an Int might have side effects
var a = 0
def fn: Int = {
a = a + 1
1
}
Every call to fn changes the value of a.
Then why on earth, the compiler does not complain that a function that
is suppose to evaluate to Unit, gets a body that evaluate to another
type, as it would happens between other types.
When you specify Unit as the return type the compiler does an implicit conversion from whatever value the function returns to Unit (there is only one Unit value as it is an object, you can think of it as the void type of Scala).
Unit is inferred as a return type for convenience. For example,
scala> val h = new collection.mutable.HashMap[String,String]
h: scala.collection.mutable.HashMap[String,String] = Map()
scala> h += "fish" -> "salmon"
res1: h.type = Map(fish -> salmon)
we see that the += method on mutable HashMaps returns the map.
But if you don't infer unit, then
def add(a: String, b: String): Unit = h += a -> b
doesn't work.
Which thing is worse--accidentally expecting a return value vs. demanding you explicitly return the most boring possible return value--depends on how functional your code is. If you have more than a few side-effects, not inferring Unit is rather painful.
A function with just the parentheses is mainly called for the side-effects. It may return a result, as it was common in the days of C or Java but in reality we don't care, cause we will not use it.
{} is equivalent to : Unit =, and the annotation of return type can be seen as a cast or an implicit conversion to match the type expected by the function.
Here is another example where this behavior occurs.
def add(a: Int, b:Int) : Double = a + b
add: (a: Int, b: Int)Double
scala> add(4,5)
res17: Double = 9.0
Thus it seems that every value can be transformed to unit.
scala> val a: Unit = 1:Unit
<console>:28: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
val a: Unit = 1:Unit
^
a: Unit = ()
I heard that Scala contains a feature called named and default arguments but I don't know what such parameters do or how to use them.
Can someone explain their usage?
Some special functions call type in Scala
Named arguments:
Named arguments allow you to pass arguments to a function in a different order.For example:
def speed(distance: Float, time: Float): Float = distance / time
And the it can be used like this:
speed(distance = 100, time = 10)
or
speed(time = 10, distance = 100)
Default arguments:
Scala lets you specify default values for function parameters. For example:
def printTime(out: java.io.PrintStream = Console.out) =
out.println("time = "+ System.currentTimeMillis())
Then you can call printTime without giving any output stream like this:
printTime()
Repeated arguments:
Scala allows you to indicate that the last parameter to a function may be repeat. For example:
def echo(args: String*) =
for (arg <- args)
println(arg)
Then you can use it like this:
echo()
echo("one")
echo("hello", "world!")
Default arguments solve the problem other programming languages normally solve with method overloading. When there is a method
def addNumbers(a: Int, b: Int, c: Int, d: Int) = a+b+c+d
that takes multiple parameters it can be useful to set some default values in overloaded methods to provide an API that is easier to use if one doesn't want to fill all parameters:
def addNumbers(a: Int, b: Int, c: Int) = addNumbers(a, b, c, 0)
def addNumbers(a: Int, b: Int) = addNumbers(a, b, 0, 0)
With default arguments it is no longer necessary to overload such a method:
def addNumbers(a: Int, b: Int, c: Int = 0, d: Int = 0) = a+b+c+d
The compiler automatically calls the method with the specific default arguments if they are not specified:
scala> addNumbers(1, 2, 3)
res2: Int = 6
A useful place for default arguments is in constructors. It is easier to write
class A(i: Int, s: String = "")
than
class A(i: Int, s: String) {
def this(i: Int) = this(i, "")
}
Named arguments on the other side can improve the readability of a method call:
def compute(xs: List[Int], executeInParallel: Boolean) = ???
compute(xs, executeInParallel = true) is easier to read than only compute(xs, true)
One can always specify the name of a parameter regardless of its order. This means compute(executeInParallel = true, xs = xs) is the same as compute(xs, true). The compiler often just needs a hint which parameter must be placed at which position when the ordering of the parameters is changed.
A use case where both named and default arguments can be used lies in the copy method of case classes, which are automatically generated by the compiler:
scala> case class Person(name: String, age: Int)
defined class Person
scala> val p = Person("Ruben", 43)
p: Person = Person(Ruben,43)
scala> val oneYearOlder = p.copy(age = p.age+1)
oneYearOlder: Person = Person(Ruben,44)
It may be important to mention that named arguments only work for methods defined in Scala. Parameters of methods defined in Java can't be called by their name.
Furthermore named arguments don't work on function literals:
scala> val f = (i: Int) => i
f: Int => Int = <function1>
scala> f(i = 1)
<console>:9: error: not found: value i
f(i = 1)
^
For further information to this feature one can take a look to docs.scala-lang.org.
I compile the following code
def foo(implicit x: Int, x2: Int) = println(x2 + x)
implicit val x : Int = 2
foo(1)
But the compiler moans about the number of arguments. Why would the above work if there was only parameter x marked as implicit, but it does not work in this example?
You have to put the implicit argument is a separated, its own parenthesis:
scala> def foo(x2: Int)(implicit x: Int) = println(x2 + x)
scala> implicit val x: Int 2
scala> foo(1)
3
If you put non implicit argument and implicit argument in the same parenthesis, you have to explicitly pass both arguments otherwise compiler will complain about the wrong number of arguments. Scala compiler will try to look for implicit arguments when it sees that the argument is marked as implicit and no argument has been passed explicitly. But compiler checks if the right number of argument has been passed before checking for the implicit.
This will work as you want:
def foo(x2: Int)(implicit x: Int) = println(x2 + x)
implicit val x : Int = 2
foo(1)
I'm not too deep into Scala internals and spec so I cannot give an in depth-explanation why this is, but you have to pass implicits with an extra set of parenthesis.
Edit:
Because I was curious I had a look around the interwebs. I will not retype all the stuff I just found myself so you can find more detailed information here: http://daily-scala.blogspot.de/2010/04/implicit-parameters.html
Implicit parameters are all-or-nothing. Either you pass all of them explicitly, or you don't pass any of them and the compiler picks implicits for all.
In the example you should you are passing a parameter to foo, so you have to pass everything. If you had only one parameter in foo, it would work because the number of parameters is correct (and the parameter would be passed explicitly). If you call foo without passing any parameters, it will also work because it will pick implicit val x for both parameters.