I am beginner in scala language, I am confused with Any class in scala.
def f(x: Any) = println(x)
is above code represents that x variable can be of any datatype(example:int,string etc.)
rewritten code:
def f(x:Any)=x+5
<console>:13: error: type mismatch;
found : Int(5)
required: String
def f(x:Any)=x+5
if x can accept any type then why am I getting above error. I might confused understanding of any in scala. Please correct me.
In a statically typed language you can only call a method m on a value x of type A if m is defined by A. By the nature of Any, there aren't any useful methods on Any that you could call (except a few things like toString or hashCode), certainly no plus operation is defined. Imagine you passed a Boolean into that method, which is allowed since Boolean is a sub-type of Any. If the compiler allowed your code, it would run into a problem, because there is no such thing as + on a Boolean. In a dynamically typed language you could run that code and would then encounter a runtime error.
The error message looks weird, because you can concatenate strings with + and due to an implicit conversion it is possible to concatenate things with strings:
def f(x: Any) = x + "hello" // implicitly converts x to a string
f(true) // "truehello"
This is a source of great confusion and hopefully will disappear from the language. If you used a different method, the error would be more obvious:
def f(x:Any)=x-5
<console>:54: error: value - is not a member of Any
def f(x:Any)=x-5
^
If you look at println() sources you will see:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
where String.valueOf is
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Class Any already has toString method but doesn't have + method (you know that all operators such +, - etc. are methods, see http://tomjefferys.blogspot.com/2011/11/operator-overloading-in-scala.html).
Related
lately I've decided to port my project's codebase to Scala for performance reasons but just as I was getting started, I was stopped by an error I did not understand. This is the minimal amount of code that causes the error:
class Foo[A](var x: A) {
def +(other: Foo[A]) = new Foo[A](this.x + other.x)
}
And the error itself:
test.scala:2: error: type mismatch;
found : A
required: String
def +(other: Foo[A]) = new Foo[A](this.x + other.x)
^
After looking around, I found some forum posts about similar errors which were apparently caused by Scala implicitly converting the template type to a string(?).
As mentioned in the comments, the compiler doesn't have enough information about type A to know how to + two of them.
The reason for the confusing error message is that the compiler "knows" that everything has a toString() method and that type String has a + method. So why doesn't it convert both to type String and + them together? It's because the A-to-String transition is an implicit conversion and the compiler won't do more than one implicit conversion in order to resolve an expression.
Thus the found:A, required:String error. The compiler is saying, "I've already converted the first A to String in order to resolve the + method but, now that I've done that, I can't do it again on the 2nd A element."
There are a few different ways around this. Here's one.
class Foo[A:Numeric](var x: A) {
def +(other: Foo[A]) =
new Foo[A](implicitly[Numeric[A]].plus(this.x, other.x))
}
A is restricted to types found in the Numeric type class. To add two As together, pull the implementation for Numeric[A] out of the implicit scope and invoke its plus() method.
The problem here is that the plus method in this.x + other.x is not the plus method defined in Foo[A]. It comes from A. And as A is still undefined, can be Any. The compiler, as always, will look a way to make things compile and in this case will find a conversion that will allow this.x call to + method. It will find this in Predef.scala that is in scope and has
implicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
Therefore if this.x is a String to be able to concatenate that.x, it should also be a String. Which is not the case.
You can check it in https://github.com/scala/scala/blob/706ef1b291134a5e5bce2275df2c222261f73451/src/library/scala/Predef.scala#L381
I am new to scala, and got a little doubt about function definition & default return type.
Here is a function definition:
def wol(s: String) = s.length.toString.length
The prompt says it's:
wol: (s: String)Int
But, the code didn't specify return type explicitly, shouldn't it default to Unit, which means void in Java.
So, what is the rules for default return type of a Scala function?
The return type in a function is actually the return type of the last expression that occurs in the function. In this case it's an Int, because #length returns an Int.
This is the work done by the compiler when it tries to infer the type. If you don't specify a type, it automatically gets inferred, but it's not necessarily Unit. You could force it to be that be stating it:
def wol(s: String): Unit = s.length.toString.length
EDIT [syntactic sugar sample]
I just remembered something that might be connected to your previous beliefs. When you define a method without specifying its return type and without putting the = sign, the compiler will force the return type to be Unit.
def wol(s: String) {
s.length.toString.length
}
val x = wol("") // x has type Unit!
IntelliJ actually warns you and gives the hint Useless expression. Behind the scene, the #wol function here is converted into something like:
// This is actually the same as the first function
def wol(s: String): Unit = { s.length.toString.length }
Anyway, as a best practice try to avoid using this syntax and always opt for putting that = sign. Furthermore if you define public methods try to always specify the return type.
Hope that helps :)
I'm trying to define a generic add function to numeric values:
def add[A](x:A, y:A): A = {
x + y
}
console:16: error: type mismatch;
found : A
required: String
x + y
^
What's the compiler complaining about?
Some of the stuff I've googled does not quite make sense to me at this moment.
Since you define A with no boundaries and no extra information, it could be any type, and not any Scala type has a + method - so this can't compile.
The error message is a result of the compiler's attempt to implicitly convert x into a String (because String has a + method, and every type can be converted to string using toString), but then it fails because y isn't a string.
To create a method for all numeric types, you can use the Numeric type:
def add[A](x:A, y:A)(implicit n: Numeric[A]): A = {
n.plus(x, y)
}
add(1, 3)
add(1.4, 3.5)
EDIT: or an equivalent syntax:
def add[A: Numeric](x:A, y:A): A = {
implicitly[Numeric[A]].plus(x, y)
}
To be able to do something like this the compiler needs to know that A has a method
def +(a: A): A
so ideally you would want to do something like
def add[A :< Numeric](x:A, y:A): A = { ...
but you can't because the numeric types in Scala have no common super type (they extend AnyVal). Look here for a related question.
I've written a simple code in Scala with implicit conversion of Function1 to some case class.
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int):String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
But it doesn't work. Compiler doesn't want to pass someFunction as an argument to abc. I can guess its reasons but don't know exactly why it doesn't work.
When you use a method name as you have, the compiler has to pick how to convert the method type to a value. If the expected type is a function, then it eta-expands; otherwise it supplies empty parens to invoke the method. That is described here in the spec.
But it wasn't always that way. Ten years ago, you would have got your function value just by using the method name.
The new online spec omits the "Change Log" appendix, so for the record, here is the moment when someone got frustrated with parens and introduced the current rules. (See Scala Reference 2.9, page 181.)
This has not eliminated all irksome anomalies.
Conversions
The rules for implicit conversions of methods to functions (§6.26) have been tightened. Previously, a parameterized method used as a value was always implicitly converted to a function. This could lead to unexpected results when method arguments were forgotten. Consider for instance the statement below:
show(x.toString)
where show is defined as follows:
def show(x: String) = Console.println(x)
Most likely, the programmer forgot to supply an empty argument list () to toString. The previous Scala version would treat this code as a partially applied method, and expand it to:
show(() => x.toString())
As a result, the address of a closure would be printed instead of the value of s. Scala version 2.0 will apply a conversion from partially applied method to function value only if the expected type of the expression is indeed a function type. For instance, the conversion would not be applied in the code above because the expected type of show’s parameter is String, not a function type. The new convention disallows some previously legal code. Example:
def sum(f: int => double)(a: int, b: int): double =
if (a > b) 0 else f(a) + sum(f)(a + 1, b)
val sumInts = sum(x => x) // error: missing arguments
The partial application of sum in the last line of the code above will not be converted to a function type. Instead, the compiler will produce an error message which states that arguments for method sum are missing. The problem can be fixed by providing an expected type for the partial application, for instance by annotating the definition of sumInts with its type:
val sumInts: (int, int) => double = sum(x => x) // OK
On the other hand, Scala version 2.0 now automatically applies methods with empty parameter lists to () argument lists when necessary. For instance, the show expression above will now be expanded to
show(x.toString())
Your someFunction appears as a method here.
You could try either
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
val someFunction = (i:Int) => "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction))
}
or
object MyApp extends App{
case class FunctionContainer(val function:AnyRef)
implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)
def someFunction(i:Int): String = "someString"
def abc(f : FunctionContainer):String = "abc"
println(abc(someFunction(_: Int)))
}
By the way: implicitly casting such common functions to something else can quickly lead to problems. Are you absolutely sure that you need this? Wouldn't it be easier to overload abc?
You should use eta-expansion
println(abc(someFunction _))
If I try to define an implicit conversion for a primitive type, then it doesn't seem to work. E.g.:
implicit def globalIntToString(a: Int) : String = { a.toString() + "globalhi" }
1.toInt + "hi"
The above will still return simply "1hi" as the result.
However, it seems that if I parameterize a class or a def and then pass in the implicit for the parametrized case, then it seems to work. Does anyone know what the reasons are? E.g. does this have something to do with boxing/unboxing of primtives (e.g., parameterized primitives are boxed)? Does implicit only work with reference types and not primitive types?
class typeConv[T] { implicit def tToStr(a: T) : String = { a.toString() + "hi" } }
class t[K](a: K)(tc : typeConv[K]) { import tc._; println(a + "cool"); println(1.toInt + "cool" ) }
new t(1)(new typeConv[Int])
There are a few subtle things going on here. #yan has already explained the core issue - I'll try to add some more specific information.
As noted, 1.toInt + "hi" will never use any implicit conversion because Scala Int class actually has a method + that takes a String parameter. The compiler will look for an implicit view only when it can't find matching member in the original type.
A little more complicated stuff is happening inside your t class. Scalac will look for implicit conversion from a generic type K to any type that has a + method that takes a String parameter. There will be two candidates for such a conversion: your own tc.tToStr and Scala built-in scala.Predef.any2stringadd.
Normally, any2stringadd would be used, but in your example, your own conversion is used. Why does it have precedence over any2stringadd?
During implicit search, tc.tToStr is seen as a function of type K => String, while any2stringadd is seen as a function of type Any => StringAdd. My guess is that K => String is seen by the compiler as a more specific conversion than Any => StringAdd, but someone would have to confirm it with a proper reference to Scala Language Specification.
As you can see, defining such conversions may cause you a lot of strange behaviour. I'd definitely say that introducing an implicit conversion to a String is asking for trouble.
This happens because Scala defines a + operator on the Int type that takes a String and does not need to resolve an implicit conversion. Also, converting to String is usually a bad idea, as you'd generally have a custom, one-off type that would define the methods you're trying to add.