1

I am learning Scala as a personal interest and I'm perplexed by the return value of the following:

var t : Long = 1
def product(s:String):Long = {
    if(s.length > 1) t *= product(s.tail)
    else  t *= s.toLong 
}

This is a recursive function,but the compiler tall me two errors that:

<console>:13: error: type mismatch;
 found   : Unit
 required: Long
       if(s.length > 1) t *= product(s.tail)
                          ^
<console>:14: error: type mismatch;
 found   : Unit
 required: Long
       else  t *= s.toLong 
               ^

and in scala-doc ,i can't find the def *= in Long.

HongYi
  • 33
  • 4

5 Answers5

2

t *= product(s.tail) is shorthand for t = t * product(s.tail)

If you want to return he value of t, you have to do it explicitly:

var t : Long = 1
def product(s:String):Long = {
    if(s.length > 1) t *= product(s.tail)
    else  t *= s.toLong 

    t
}

But seeing you are side-effecting t here, it is not really in the spirit of functinal programming.

I prefer a pure function:

def product(s:String, t: Long):Long = {
    if(s.length > 1) t * product(s.tail, t)
    else  t * s.toLong 
}
triggerNZ
  • 4,221
  • 3
  • 28
  • 34
1

The x *= e construct returns Unit

scala> var t : Long = 1
t: Long = 1

scala> :type t *= 42
Unit

scala> 
ReyCharles
  • 1,772
  • 10
  • 30
0

t *= … is, if not overloaded, a shorthand for t = t * … - a simple assigment. And since those have Unit return type instead of yielding the new value (Long), you're getting a type error here (twice).

Changing your function to the following should work:

def product(s:String): Long = {
    t *= if(s.length > 1) product(s.tail) else s.toLong
    t
}

However you probably should either change the return type to Unit if you only care about the side effect of changing t anyway:

var t: Long = 1
def product(s:String): Unit = {
    t *= if(s.length > 1) product(s.tail) else s.toLong
}

or make the function pure and not mutate the variable:

val t: Long = 1
def product(s:String): Long =
    t * if(s.length > 1) product(s.tail) else s.toLong
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Assignment expression (using "=" sign) returns nothing, which we can call it Unit in Scala.

*= means * first and then make assignment. Therefore, you actually returns Unit, not Long.

chenzhongpu
  • 6,193
  • 8
  • 41
  • 79
0

When you use the expression *=, you are creating a side-effect that modifies the variable on the left side, in this case, t. Because a side-effect by its very nature has no return value, the Scala compiler tells you that you have a type mismatch, specifically, that Unit does not conform to Long.

Since t carries the value that you want, where product modifies t, t needs to be explicitly returned by product. Placing it in the last line makes it the return value (Scala does not require writing return t, but you could; it is equivalent either way). Others have posted their fixes, but in situations like this, consider doing this:

var t : Long = 1
def product(s:String) = {
  if(s.length > 1) t *= product(s.tail)
  else  t *= s.toLong
  t  //Made t the return, which is what you want.
}

and working through your definitions from there. This does not compile, but it shows you the next step. Think about how to make product return t in all cases. Think carefully about how you are using recursion.

Nicholas Montaño
  • 935
  • 10
  • 24