I get "type mismatch; found : Int(1) required: String" error when I try to return the incremented value of the input parameter from a Scala generic method below.
I did try using the Case method for this but it did not work as well. Basically I want to decide the operation based on input Type to the method and return the calculated/modified value.
object GenericOperations {
// def increment[typ](val x:typ):typ = x match {
// case _:Int => x + 1
// case _:String => x + "x"
// }
def increment2(x:Any):Any = {
if(x.isInstanceOf[Int]) {
x+1
}
else if (x.isInstanceOf[String]) {
x + "x"
}
else {
println("No Match type")
}
}
}
I would rather use method overloading:
def increment2(x: Int) = x + 1
def increment2(x: String) = x + "x"
If you are sure you need exactly one function you may use match.
def increment2(x: Any): Any = x match {
case v: Int => v + 1
case v: String => v + "x"
case _ =>
throw new Exception("No Match type")
}
But returning Any isn't good thing as you cannot use its result without type cast
GenericOperations.increment2(3) + 3 // type mismatch
Still you may use the same match way:
def increment2[T](x: T): T = (x match {
case v: Int => v + 1
case v: String => v + "x"
case _ => throw new Exception("No Match type")
}) match {
case v: T => v
case _ => throw new Exception("Invalid increment expression result type")
}
As it has been mentioned in the comments there is also typeclass way:
//type class
trait Incrementable[T] {
def inc(x: T): T
}
//type class instance for String
implicit val incString = new Incrementable[String] {
def inc(x: String) = x + "x"
}
//type class instance for Int, single abstract method (SAM) form
implicit val incInt: Incrementable[Int] = (x: Int) => x + 1
def increment2[T: Incrementable](x: T): T = implicitly[Incrementable[T]].inc(x)
You have declared x to be of type Any. Which means you are only allowed to use the methods of Any.
You are calling x.+(1). There is no + method in Any. Therefore, you can't use +.
You should be getting an error about + not existing, but you don't, so what's happening here?
There is an implicit conversion for string concatenation, which can convert an arbitrary object into a String and then concatenate another String to it. In this case, it converts x to an any2stringadd and then tries to add 1 to it, but the any2stringadd.+ method only takes a String as its argument, and thus you get the strange error message that it is expecting a String.
You, however, are passing 1 as an argument, which is an Int not a String.
Note that any2stringadd is deprecated in Scala 2.13, so in the future you would just get an error about a non-existent method.
Note that you have tagged this question with generics and also talk about generics multiple times in the subject and the question body, yet there are no generics in your code. In fact, with generics, this problem would not exist.
See also
Scala Beginner trying to use Parameterised Type
Type parameter in scala
Maybe something like this , even though I still don't like it because the usage of getOrElse , but here you go anyway:
object GenericOperations {
// def increment[typ](val x:typ):typ = x match {
// case _:Int => x + 1
// case _:String => x + "x"
// }
def increment2(x:Any):Any = {
if(x.isInstanceOf[Int]) {
toInt(x).getOrElse(0)+1
}
else if (x.isInstanceOf[String]) {
x + "x"
}
else {
println("No Match type")
}
}
def toInt(x: Any): Option[Int] = x match {
case i: Int => Some(i)
case _ => None
}
}
Related
I need to instantiate a different class depending on a the value of a particular argument in my application. Something like:
class x { val z = 5}
class y { val z = 10}
def myClass(input:String): Class[_] = {
input match{
case "x" => x
case "y" => y
}
}
val a = new myClass("x")
Any ideas how to do this or if this is possible? It tried the above code and I get a type mismatch with the output so maybe it's as simple as specifying the output type correctly, which I'm pretty sure I'm not.
Thanks.
You should clarify what you're trying to accomplish because runtime reflection would allow you to do this, but 99.9% of the time it's the wrong way to solve your problems.
You can do something like:
trait A
case class B(value: String) extends A
case class C(value: Int) extends A
def doSomething(input: String): A = input match {
case "x" => B("Wahoo")
case "y" => C(123)
}
It's not clear what it is you are actually trying to do: on one hand, you are saying that you need to instantiate the class, on the other, your function is declared to return the Class itself, not an instance.
So, if you are trying to create an instance, something like this would work:
def myClass(input: String): AnyRef = input match {
case "x" => new x
case "y" => new y
}
Note: there are two problems with this function. First, it will throw an exception if input happens to be neither x nor y ... This is not very nice. It is a better idea to make it return an Option, and add a default to None, when input isn't matched:
def myClass(input: String): Option[_] = Option(input) collect {
case "x" => new x
case "y" => new y
}
Another problem is that you cannot do very much with the value returned by this function the way it is written, because you don't know what type it has, so, you can't access any of it's members (other than the common stuff like toString, equals etc.).
It may be a better idea to define a common trait like the other answer suggests, and narrow down the return type of the function to that trait:
trait Foo { def z: Int }
class x extends Foo { val z = 5 }
class y extends Foo { val z = 10 }
def myClass(input: String): Option[Foo] = Option(input) collect {
case "x" => new x
case "y" => new y
}
Finally, if what you wanted was to actually return the Class object, and not an instance, then you almost have it, except, you need to add a classOf keyword (it's still better to make the result optional, in case input does not match):
def myClass(input: String): Option[Class[_]] = Option(input) collect {
case "x" => classOf[x]
case "y" => classOf[y]
}
Or, better, with the type boundary:
def myClass(input: String): Option[Class[_ <: Foo]] = Option(input) collect {
case "x" => classOf[x]
case "y" => classOf[y]
}
I am pretty a fresh man to learn scala.
I want to ask how to check the function return value type?
For example :
def decode(list :List[(Int, String)]):List[String] = {
//val result = List[String]()
//list.map(l => outputCharWithTime(l._1,l._2,Nil))
//result
excuteDecode(list,List[String]())
def excuteDecode(list:List[(Int,String)],result:List[String]):List[String] = list match {
case Nil => Nil
case x::Nil=>outputCharWithTime(x._1,x._2,result)
case x::y =>excuteDecode(y,outputCharWithTime(x._1,x._2,result))
}
def outputCharWithTime(times:Int,str:String , result :List[String]):List[String]={
times match{
case 0 => result
case x => outputCharWithTime(times-1,str,str::result)
}
}
}
In this code , all the function return type is set to List[String], also created one empty List[String] parameter for excuteDecode() function .
However I get a compilation error:
Error:(128, 5) type mismatch;
found : Unit
required: List[String]
}
Anyone can tell me why there exist problem and how to check the actual return type by ourself ?
The order of statements matters here.
def decode(list :List[(Int, String)]):List[String] = {
def excuteDecode(list:List[(Int,String)],result:List[String]):List[String] = list match {
case Nil => Nil
case x::Nil=>outputCharWithTime(x._1,x._2,result)
case x::y =>excuteDecode(y,outputCharWithTime(x._1,x._2,result))
}
def outputCharWithTime(times:Int,str:String , result :List[String]):List[String]={
times match{
case 0 => result
case x => outputCharWithTime(times-1,str,str::result)
}
}
excuteDecode(list,List[String]()) // Moved here
}
In Scala, the last expression in a block defines, what the whole block returns; statements such as def are defined to produce a Unit (()).
In Scala we have a by-name-parameters where we can write
def foo[T](f: => T):T = {
f // invokes f
}
// use as:
foo(println("hello"))
I now want to do the same with an array of methods, that is I want to use them as:
def foo[T](f:Array[ => T]):T = { // does not work
f(0) // invokes f(0) // does not work
}
foo(println("hi"), println("hello")) // does not work
Is there any way to do what I want? The best I have come up with is:
def foo[T](f:() => T *):T = {
f(0)() // invokes f(0)
}
// use as:
foo(() => println("hi"), () => println("hello"))
or
def foo[T](f:Array[() => T]):T = {
f(0)() // invokes f(0)
}
// use as:
foo(Array(() => println("hi"), () => println("hello")))
EDIT: The proposed SIP-24 is not very useful as pointed out by Seth Tisue in a comment to this answer.
An example where this will be problematic is the following code of a utility function trycatch:
type unitToT[T] = ()=>T
def trycatch[T](list:unitToT[T] *):T = list.size match {
case i if i > 1 =>
try list.head()
catch { case t:Any => trycatch(list.tail: _*) }
case 1 => list(0)()
case _ => throw new Exception("call list must be non-empty")
}
Here trycatch takes a list of methods of type ()=>T and applies each element successively until it succeeds or the end is reached.
Now suppose I have two methods:
def getYahooRate(currencyA:String, currencyB:String):Double = ???
and
def getGoogleRate(currencyA:String, currencyB:String):Double = ???
that convert one unit of currencyA to currencyB and output Double.
I use trycatch as:
val usdEuroRate = trycatch(() => getYahooRate("USD", "EUR"),
() => getGoogleRate("USD", "EUR"))
I would have preferred:
val usdEuroRate = trycatch(getYahooRate("USD", "EUR"),
getGoogleRate("USD", "EUR")) // does not work
In the example above, I would like getGoogleRate("USD", "EUR") to be invoked only if getYahooRate("USD", "EUR") throws an exception. This is not the intended behavior of SIP-24.
Here is a solution, although with a few restrictions compared to direct call-by-name:
import scala.util.control.NonFatal
object Main extends App {
implicit class Attempt[+A](f: => A) {
def apply(): A = f
}
def tryCatch[T](attempts: Attempt[T]*): T = attempts.toList match {
case a :: b :: rest =>
try a()
catch {
case NonFatal(e) =>
tryCatch(b :: rest: _*)
}
case a :: Nil =>
a()
case Nil => throw new Exception("call list must be non-empty")
}
def a = println("Hi")
def b: Unit = sys.error("one")
def c = println("bye")
tryCatch(a, b, c)
def d: Int = sys.error("two")
def e = { println("here"); 45 }
def f = println("not here")
val result = tryCatch(d, e, f)
println("Result is " + result)
}
The restrictions are:
Using a block as an argument won't work; only the last expression of the block will be wrapped in an Attempt.
If the expression is of type Nothing (e.g., if b and d weren't annotated), the conversion to Attempt is not inserted since Nothing is a subtype of every type, including Attempt. Presumably the same would apply for an expression of type Null.
As of Scala 2.11.7, the answer is no. However, there is SIP-24, so in some future version your f: => T* version may be possible.
I am trying to implement a method using a case statement, but the following code does not compile.
I am aware I can get this working by using a pattern match, but am curious as to why the case statement is incompatible as a direct implementation....
trait Calculation[Input, Result] {
def calculate(in: Input): Result
}
class CalculationImpl : Calculation[String, int] {
// missing parameter type for expanded function
// The argument types of an anonymous function must be fully known. (SLS 8.5)
def calculate = {
case "one" => 1
case "two" => 2
case s: String => 0
}
}
As a compromise, I could change the semantics of the trait so that calculate becomes a parameterless method which returns a Function1, rather than a method which takes an Input parameter and returns a Result. However, this is not ideal...
trait Calculation[Input, Result] {
def calculate: Input => Result // Works, but semantics have changed.
}
class CalculationImpl : Calculation[String, int] {
def calculate = {
case "one" => 1
case "two" => 2
case s: String => 0
}
}
(note: the above is pseudo-code - I have not tried compiling this exact code)
You just need to fix your syntax and it will work:
def calculate(s: String) = s match {
case "one" => 1
case "two" => 2
case s: String => 0
}
You can get closer to the original semantics and still cut the boilerplate by defining calculate as a function value:
trait Calculation[Input, Result] {
type F = Input => Result
val calculate: F
}
class CalculationImpl extends Calculation[String, Int] {
val calculate: F = {
case "one" => 1
case "two" => 2
case s: String => 0
}
}
implicit val odkaz = head;
def vypis(implicit odkaz:Prvek):String = {
odkaz match{
case null => ""
case e => e.cislo + " " + e.pocet + "\n" + vypis(e.dalsi)
}
}
...
def main(args:Array[String]){
val q = new MyQueue() // insert some values
println(q.vypis)
}
This method(vypis) is a member of an queue-class so I'll always want to implicity start the recursion from the start of the queue, when calling the method from outside. Is there a way how to write it, that the method from outside calling, there's no paramter, but in inside, there's a parameter - for recursion...?
The compiler complains that the parameter is not defined when called from outside
Or is there are way how can specify the default value for a method's parameter?
Using a nested method
def sum(list: List[Int]) = {
#annotation.tailrec
def sum(ls: List[Int], s: Int): Int = ls match {
case x :: xs => sum(xs, x + s)
case _ => s
}
sum(list, 0)
}
Using a default parameter for the accumulator
#annotation.tailrec
def sum(list: List[Int], s: Int = 0): Int = list match {
case x :: xs => sum(xs, x + s)
case _ => s
}
The second approach (only possible with Scala 2.8) unneccesarily broadens the public API, so I would recommend the first.
In Scala 2.8, default method (and constructor) parameters are available:
def m1(i: Int = 23): Int = i * 2