2

The question first: Is the arrow anti pattern the way to do things in Scala?

I've been transitioning from Java to Scala for about 3 months now. I'm starting to see that the anti arrow pattern as a bit of a standard in Scala.

For example, in Java, I like to return from methods as soon as possible. We don't like a lot of inner nestings. If you have lots of them it's called the arrow anti pattern. You can read about it here: http://c2.com/cgi/wiki?ArrowAntiPattern

Java example:

boolean isValid(String input){
  if (input.trim().length() <1) return false //return early
  if (input.substring(0,3).equals("sth")) return false;

  //do some more checks for validity then return true

  return true
}

If I wrote this in Scala I'd have to use match-case statements which results in a lot of indenting. Keep in mind that this is just a dummy example where I try to convey only the nesting and indentation of Scala.

def isValid(input:String):  Boolean = {
  (input.trim.length < 1) match {
    case true => 
      input.substring(0,3) match {
        case sthCase if(sthCase=="sth") =>
          //do some more checks etc

          //eventually arrive at the "true" branch
               ... case valid => true

        case sthElse if (sthCase=="bla") => //some more code etc
        case _ => false
      }
    case _ => false
  }
}

I know this example could have been written the same way I wrote the Java one, but if instead of returning true or false I wanted to assign that value to a variable ie:val valid = (input.trim.length < 1) match ... then this is the only way to do it since you can't reassign to val. I could use var instead of val, but then I'd be using Java instead of Scala.

Question, re-iterated: So the question is, is the arrow anti pattern the way to do things in Scala or am I missing something? Is there a better way to do in Scala what I just wrote (keeping in mind that I want that match statement result to be assigned to a val variable).

Adrian
  • 5,603
  • 8
  • 53
  • 85

4 Answers4

4

Note that you can always use decomposition in Scala as long as all parts of the code are single entry/single exit. This works because nested functions in Scala can access the local variables of the outer function. E.g.:

def isValid(input: String): Boolean = {
  def testLength = input.trim.length >= 1
  def testSomething = input.substring(0, 3) == "sth"

  return testLength && testSomething
}

You can thus break down any arrow-like structure into its subcomponents as much as you desire.

Note also that using match for testing booleans or comparing something for equality is overkill.

Reimer Behrends
  • 8,600
  • 15
  • 19
  • It's not a really new technique, either. See ["Program Development by Stepwise Refinement" by Niklaus Wirth](http://dl.acm.org/citation.cfm?id=362577). It's probably a major reason why all languages in the Pascal family of languages have nested procedures/functions. – Reimer Behrends Jun 05 '13 at 16:02
  • indeed, but it's a start. I will probably make another post continuing this question, but a bit deeper/more advanced than a few boolean values nested. thanks again – Adrian Jun 05 '13 at 18:19
  • 2
    The `return` keyword can and should be omitted – 0__ Jun 05 '13 at 20:28
  • As a stylistic preference, I like to make the `return` explicit at the end of long functions. Not only does it make it easier to visually find the end of a function (assuming you have syntax highlighting), it also makes it clear that we are dealing with a function instead of a procedure without having to inspect the function signature. The semantics are the same either way, so neither way is objectively better. – Reimer Behrends Jun 06 '13 at 01:16
  • If you omit the `return` it makes your source "grep-able" for `return`s which could be replaced with something else. – Beryllium Jun 06 '13 at 08:56
3

Your java example can easily be translated to an if/else in scala without explicit return and without any additional levels of nesting.

def isValid(input: String) = {
  if (input.trim().length() <1) false
  else if (input.substring(0,3).equals("sth")) false
  else true
}

if/else like everything in scala is an expression and has a return value, so you might as well use it for an assignment:

val isValid =
  if (input.trim().length() <1) false
  else if (input.substring(0,3).equals("sth")) false
  else true

Or in this case you could also simply write

val isValid = (input.trim().length() >= 1) && (!input.substring(0,3).equals("sth"))
drexin
  • 24,225
  • 4
  • 67
  • 81
3

If there are too many returns in a function, functions are missing:

def isValid(s: String): Boolean = {
  def isLengthValid = s.trim().length() > 0
  def shouldNotContainsSomething = s.substring(0, 3) != "sth"

  isLengthValid && shouldNotContainsSomething
}
Beryllium
  • 12,808
  • 10
  • 56
  • 86
  • No need to use `equals` for string comparison in Scala. The `==` operator automatically uses the `equals` method. – 0__ Jun 05 '13 at 20:29
  • It was copied from the Java example - I just appended the `== false` to preserve the condition. So it should really be `!=`. I've updated it. – Beryllium Jun 06 '13 at 08:52
2

Don't do the cargo cult just because some rule says so. The good thing in Scala is that you can do the best from both worlds -- e.g. sometimes algoritm written in a mutable style is much more clear than the immutable one.

By the way, there is also require method, which is used commonly for fail on validation (but it goes up with an exception).

Community
  • 1
  • 1
om-nom-nom
  • 62,329
  • 13
  • 183
  • 228