tags:

views:

131

answers:

2

In the code snippet included below, I have a recursive function call, used to facilitate a retry if a network call fails (Amazon SimpleDB will occasionally return a 503 and require retry.)

When I try to compile, the Scala complains recursive method simpledb_update needs result type.

// sends data to SimpleDB. Retries if necessary
def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) = {
 try {
  db(config("simpledb_db")) += (name, metadata)
 } catch {
  case e =>
   // if it fails, try again up to 5 times
  if(attempt < 6)
  {
   Thread.sleep(500)
   simpledb_update(name, metadata, attempt + 1)
   } else
     AUlog(name + ": SimpleDB Failed")
   }
 }

Why is this required on recursive functions? My thought is to just return a true/false boolean to satisfy the compiler... the following compiles fine.

// sends data to SimpleDB. Retries if necessary
 def simpledb_update(name: String, metadata: Map[String,String], attempt: Int): Boolean = {
 try {
  db(config("simpledb_db")) += (name, metadata)
  true
 } catch {
  case e =>
   // if it fails, try again up to 5 times
   if(attempt < 6)
   {
    Thread.sleep(500)
    simpledb_update(name, metadata, attempt + 1)
   } else
    AUlog(name + ": SimpleDB Failed")
    false
  }
}
+2  A: 

Just remove the = from the line and it will return Unit, this means that you don't need to return anything.

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int) {

I believe the need for return types, it to make sure all recursion paths have the correct type. On a normal function, the type would be inferred from all return points.

Thomas
Ahhh... makes perfect sense.
Joshua
You simply can't infer the type from the return points, because at least one of the return points has the type that you are just trying to infer.
Jörg W Mittag
@Jorg - Actually, it's not that hard to infer (but it's harder than one might want). If you get the type of every path return value that is not the recursive return value, that must be the return value's type. But this gets complicated when pushed into mutually recursive functions.
Rex Kerr
Right. It's like tail recursion. _Many_ of the equations that result are solvable, and without too much difficulty. The problem is that not _all_ of the equations are solvable. A language spec needs to declare bright-line rules whereby all of the acceptable constructs can be solved by the compiler, and all of the unacceptable constructs have a short error message saying why they are unacceptable. "Recursive methods require explicit return types" is one of Scala's bright-line rules, and hopefully not too onerous.
Dave Griffith
+6  A: 

As I understand it, recursive functions need a return type because the type inference algorithm is not powerful enough to determine return types for all recursive functions.

However, you don't need to make up a return type, you just need to declare the return type you were already using: Unit. Unit is a special type with only one element (). It's also the type of most "statements" in Scala, and is the return type to declare for methods that don't need to return anything, but are executed only for their side-effects (as yours is). You can either declare your method as returning unit as you would other types

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int):Unit = {

More idiomatically Scala provides a special syntax for Unit-returning methods, just leave off the return type and the equals sign

def simpledb_update(name: String, metadata: Map[String,String], attempt: Int){
Dave Griffith