views:

202

answers:

4

There are a number of times I've run into a simple pattern when programming in Java or C++ for which a custom control structure could reduce the boilerplate within my code. It goes something like:

 if( Predicate ){
     Action

     return Value
 }

that is, a "return if"-type statement. I've tried making functions with signature like foo[A,B]( pred:((A,A)=>Boolean), value:Option[B] ) but then I wind up checking if I've returned Some or None. I'm tripped up by the return statement.

Is there an inherit way of making such control structures in functional languages or more specifically Scala?

Edit:

I was not as clear with my description and it's confusing people who are trying to help me. The key reason my foo doesn't work is that it can't short-circuit the evaluation of the containing function. That is

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {
    return_if( withinBounds( geometry, projection ), logToString( logger, "Geometry outside " + projection.toString ), EmptyGeometry() )
    return_if( topologicallyCorrect( geometry ), intersect( correct( geometry ), reference )
    //rest of the function
}

and still allow for tail recursion within the return_if.

+2  A: 

It looks like you're using this as a conditional escape from the control flow of the code.

You can do this in Scala too (just annotate the method with the type to return) if it's really the most elegant solution to the problem. Sometimes code needs to act like a multi-stage filter, and this pattern works well for that.

Of course you can always nest if-statements, but that gets awkward.

There are a couple of other things to consider in Scala, however. One can

methodReturningOption.getOrElse(
  // All the code for the None case goes in here
)

which usually works pretty well at consolidating different branches in the case that there is a sensible default (or you'll end up throwing an exception if there's not).

Alternatively, you can abuse pattern matching for this:

None match {  // Could use a real variable instead of None if it helped
  case _ if (Predicate1) => Action1; Value1
  case _ if (Predicate2) => Action2; Value2
  . . .
  case _ => ErrorHandlingPerhaps
}

But you also might be able to think about your problem in a different way so that these sort of predicates become less useful. (Without knowing more details, I can't suggest something.)

Rex Kerr
+7  A: 

I would use a partial function:

def whatevs[A, B](options : PartialFunction[(A,A), B]) : Option[B] = {
  val myInput = generateInput
  if(options.isDefined(myInput)) {
    Some(options(myInput))
  } else None
}

Then your usage could look like the following:

whateves {
   case (x,y) if x > y =>   "Biggerz"
   case (x,y) if y > x =>   "Tiny!"
}

In general, you do not need a return statement. If-expression will evaluate to the last expression used in each block. You may need to help the compiler figure out the type-result of the if expression, but the return is unneeded.

Partial Functions are a mechanism to perform an action if some condition holds true. In the above, the two conditions are x > y or y > x from the tuple.

If the whatevs function is not quite what you're talking about I'd recommend using raw pattern matching.

jsuereth
+2  A: 

Hmm, as far as I understand it you want the return in the control structure to exit the function it is embedded in.

So in your example it should exit the method intersect?

I am not sure if thats possible. Because a return inside the return_if will always exit return_if and I don't think there is a way to tell scala, that the return should exit the function return_if is embedded in.

I hope I understood what you wanted to do :)

Plankalkül
yes, you're right. I hadn't even thought of that. If the return_if was passed a return_if it could cause issues.
wheaties
The way to achieve this would be to throw an exception which is then handled by an outer method - see how `break` has been implemented. Instead of `return`, you'd call a method (like `break`) which would throw the exception
oxbow_lakes
+1  A: 

I am at a loss to understand why you would want this. Here's the code you want to write:

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {

  return_if( withinBounds( geometry, projection ), 
    logToString( logger, "Geometry outside " + projection.toString ), 
    EmptyGeometry() )

  return_if( topologicallyCorrect( geometry ), 
    intersect( correct( geometry )), 
    reference )

    // rest of the function
}

while here's what it looks like in "ordinary" Scala:

def intersect( geometry:Geometry, reference:Geometry ):Geometry = {

  if (withinBounds( geometry, projection )) {
    logToString( logger, "Geometry outside " + projection.toString )
    return EmptyGeometry() }

  if( topologicallyCorrect( geometry )) {
    intersect( correct( geometry ))
    return reference }

  //rest of the function
}

To me the "ordinary" version looks a lot clearer. For one thing it makes it very clear what is being returned. It's not even more verbose. I suspect you have a more complex use case. If you show us that, maybe we will be able to direct you to patterns that are more appropriate.

Magnus