Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit parameter not found on function application

If I define a print function that only takes numbers as:

def print[T <% Number](value:T) {}
print: [T](value: T)(implicit evidence$1: (T) => java.lang.Number)Unit

I can call the above with:

print(5)
print(5.5)
print(6L) 

But not with a String:

print("aaa")  
<console>:7: error: could not find implicit value for evidence parameter of type (java.lang.String) => java.lang.Number
       print("aaa")

This is expected.

But if I define the print function as:

def print2[T <% Number]: T => Unit = value => { } 
print2: [T](implicit evidence$1: (T) => java.lang.Number)(T) => Unit

Notice how the implicit parameter is the first parameter instead of the last.

If I try to manually define the above function:

def print3[T](implicit f: (T) => java.lang.Number)(value:T):Unit =  { }  
<console>:1: error: '=' expected but '(' found.
       def print3[T](implicit f: (T) => java.lang.Number)(value:T):Unit =  { }

Basically the above is not a valid function definition but the compiler creates it when I previously defined print2.

When I call print2 with an Int:

print2(5)
<console>:7: error: type mismatch;
 found   : Int(5)
 required: (?) => java.lang.Number
       print2(5)

if I parameterize it:

print2[Int](5)
<console>:7: error: type mismatch;
 found   : Int(5)
 required: (Int) => java.lang.Number
       print2[Int](5)

It looks like it can't find the implicit conversion from scala.Int => java.lang.Integer.

How can I redefine print such that it returns functions and also accesses implicits in the correct way?

like image 787
ssanj Avatar asked Feb 22 '11 00:02

ssanj


People also ask

How do you pass an implicit parameter?

The implicit parameter in Java is the object that the method belongs to. It's passed by specifying the reference or variable of the object before the name of the method. An implicit parameter is opposite to an explicit parameter, which is passed when specifying the parameter in the parenthesis of a method call.

What is an implicit parameter?

Implicit parameters are the parameters that are passed to a function with implicit keyword in Scala, which means the values will be taken from the context in which they are called.

How many implicit parameters can a method have?

A method or constructor can have only one implicit parameter list, and it must be the last parameter list given.

How implicit works in Scala?

The implicit system in Scala allows the compiler to adjust code using a well-defined lookup mechanism. A programmer in Scala can leave out information that the compiler will attempt to infer at compile time. The Scala compiler can infer one of two situations: A method call or constructor with a missing parameter.


1 Answers

The problem here is that you are passing 5 as the implicit parameter.

Now that I'm on a computer, a few corrections:

def print[T <% Number](value:T) {}

You call this a function, but it is a method.

def print2[T <% Number]: T => Unit = value => { }

Again, you call this a function. Actually, it is a method which returns a function. The method receives one type parameter, T, and one implicit parameter.

print2(5)

So, here, you call the method print2 passing 5 as its implicit parameter. The type T hasn't been infered yet because it is first trying to conform 5 to the expected type T => Number. However, since 5 doesn't conform to Function1[T, Number], it fails without even inferring T.

There are many ways to call print2. For example:

print2(implicitly[Int => Number])
print2[Int]
(print2: Int => Unit)
val f: Int => Unit = print2

However, to call the function that is returned by print2, you have to avoid making (5) look like the implicit parameter to the method print2. There's actually only one case above that needs something different:

print2(implicitly[Int => Number])(5)
print2[Int].apply(5)
(print2: Int => Unit)(5)
val f: Int => Unit = print2; f(5)

Now, most of these examples have explicit, instead of inferred, type parameters. Let's consider what would happen in its absence:

print2.apply(5)

Because no parameter was passed to print2, it selects the most specific type that conforms to the bounds of T. Since T has no bounds, Nothing is chosen. It then tries to find an implicit Nothing => Unit. Because there's no such implicit, it fails.

The parameter to the function that would be returned by print2 is never looked into to help type inference.

like image 156
Daniel C. Sobral Avatar answered Oct 11 '22 03:10

Daniel C. Sobral