5

I tried this way:

  def add[A](a:A, b:A): A = {
    a + b
  }

The compiler says:

Error:(47, 9) type mismatch; found : A required: String a + b

Any one tell me why this error happened? Thank you.

Kai Liu
  • 121
  • 2
  • 7
  • 1
    Possible duplicate of [Scala: How to define "generic" function parameters?](http://stackoverflow.com/questions/1252915/scala-how-to-define-generic-function-parameters) – Jun Zhang Feb 08 '17 at 05:33

3 Answers3

8

Actually Scala doesn't see any common grounds between a Double's + and a an Int's + and also scala keeps this restriction by using Numeric. and its subclasses like Fractional and Integral. You can do your work in different ways like below

def addition[T](x: T, y: T)(implicit num: Numeric[T]): T = {
  import num._
  x + y
}

or

def add[A](x: A, y: A)(implicit numeric: Numeric[A]): A = numeric.plus(x, y)
Dilan
  • 1,389
  • 5
  • 14
  • 24
  • 2
    Or `def add[A:Numeric](x: A, y: A): A = implicitly[Numeric[A]].plus(x,y)`, another alternative. – jwvh Feb 08 '17 at 07:26
0

Here, you are getting the error because the compiler cannot infer the actual type of variable a and b and therefore, it cannot determine if the + method is defined for that type A.

Since you want to add two variables and not just two numbers,you could pass anonymous function in the method to define how you want to perform the addition between those variables. In this way, you could specify, how you want to add two strings or two integers or two parameters of any type:

def add[A](a:A,b:A,sum:(A,A)=> A): A = {
    sum(a,b)
  }

add("john","watson", (a:String,b:String) => a.concat(" "+b))
//result: john watson

add(1,2,(a:Int,b:Int) => a + b)
//result: 3
oblivion
  • 5,928
  • 3
  • 34
  • 55
  • 1
    That's a pretty poor solution. Defining a "generic" add where you have to pass the specific add every time you use it isn't very useful – The Archetypal Paul Feb 08 '17 at 06:43
  • 1
    @TheArchetypalPaul, is there any "perfect" solution here? if you have no information about the `A` here, how can you define its `add` action? – armnotstrong Feb 08 '17 at 06:45
  • "the compiler cannot infer the type of variable A" There is no variable `A` in this code. There is a _type parameter_ `A`, but it doesn't need to be inferred here. – Alexey Romanov Feb 08 '17 at 07:16
  • @AlexeyRomanov yes, right, actually i meant `type of variable a and b`.I have edited my answer. – oblivion Feb 08 '17 at 07:22
  • @TheArchetypalPaul I am quite aware of that. I expect you wanted to direct this comment elsewhere. – Alexey Romanov Feb 08 '17 at 08:21
  • @AlexeyRomanov, Oops. Apologies. Wrong person indeed. Removed/readded the comment – The Archetypal Paul Feb 08 '17 at 08:33
  • 1
    @armnotstrong you can either use Numeric - thereby providing "information about the A" , as in the previous answer, or a typeclass (implicit definition of addition). It you have "no information about A" you cannot know addition is even possible – The Archetypal Paul Feb 08 '17 at 08:34
0

You can use type classes to achieve this.

First, define a base trait for your operation

trait Addable[T] {
  def +(x: T, y: T): T
}

Next, define an default implicits for all the types you wish to be able to add:

implicit object LongAddable extends Addable[Long] {
  def +(x:Long, y:Long) = x + y
}
implicit object IntAddable extends Addable[Int] {
  def +(x:Int, y:Int) = x + y
}
implicit object StringAddable extends Addable[String] {
  def +(x:String, y:String) = s"${x}${y}"
}

Finally, define your method in terms of your type class, using implicit evidence to constrain your parameters:

def add[A](a:A, b:A)(implicit ev: Addable[A]): A = {
     ev.+(a,b)
}

Putting all that together allows you to add Ints,Longs, and Strings, all with the same method.

scala> object Example {
     |   trait Addable[T] {
     |     def +(x: T, y: T): T
     |   }
     |   implicit object LongAddable extends Addable[Long] {
     |     def +(x:Long, y:Long) = x + y
     |   }
     |   implicit object IntAddable extends Addable[Int] {
     |     def +(x:Int, y:Int) = x + y
     |   }
     |   implicit object StringAddable extends Addable[String] {
     |     def +(x:String, y:String) = s"${x}${y}"
     |   }
     |   def add[A](a:A, b:A)(implicit ev: Addable[A]): A = {
     |       ev.+(a,b)
     |   }
     | }
defined object Example

scala> Example.add(1,2)
res2: Int = 3

scala> Example.add(1L,2)
res3: Long = 3

scala> Example.add("2", "3")
res4: String = 23
Jon Anderson
  • 696
  • 4
  • 9