2

I like the use of require, assert, assume, and ensuring to document pre-conditions and post-conditions of a given function, but I have also come to use scalaz.Validation mostly to perform checks that require used to do. But, lately, I have been most interested in using PartialFunction, possibly with Validation, to document a pre-condition. Something like:

case class Summary(user: String, at: DateTime, ....)

val restricted_add: PartialFunction[(Summary, Summary), Summary] = {
  case (s1: Summary, s2: Summary) if s1.user != s2.user && s1.at == s2.at =>    

}

with a utility function for capturing and converting a match error into a validation failure (e.g. restricted_add.lift(_).toSucess("Cannot add.")). Somehow the case clause above seems less noisy than a For with scalaz.Validation. But I feel like I am going against the language. I'm not using def's natural syntax for defining parameters, every client of such a function would have to use a utility function when invoking it, I would be capturing exceptions and converting them into validations, instead of working only with validations or only with exceptions.

What seems like the least noisy, most functional way of documenting these pre-conditions through code? Validation returning functions, require statements, PartialFunction, other...?

Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
  • Things like `require`, `assert`, `assume` etc. _only_ serve to "document" a design for users who are forced to read the source code of the library they are using. That is _not_ documentation! – Randall Schulz Mar 31 '13 at 23:20
  • Agreed, I'm thinking more internally between developers on the same team, using/extending/maintaining each others code. –  Apr 01 '13 at 01:08

1 Answers1

1

As @RandallSchulz already stated, implicitly documenting preconditions in code only serves for your private/interal methods, never for your public API. If you're writing public methods, you should also document the preconditions in the methods docs and maybe the usage examples, if they're counter-intuitive.


That being said, in my opinion the least noisy and the most functional way are not the same in Scala. This is because require cannot be considered functional, since it throws an exception if the condition is not met, which would be catched somewhere, changing the control flow and thus being a side effect.

Nonetheless, I think that require is by far the least noisy way to specify a preconditions:

def non_func(x:Int, y:Int):Int = {
    require(x >= 0 && y >= 0)
    x + y
}

I'm not entirely sure about the most functional way to check preconditions, but I think that using pattern matching and returning an Option could be considered functional, but noisier than require:

def func(x:Int, y:Int):Option[Int] = (x,y) match {
    case (x, y) if x >= 0 && y >= 0 => Some(x + y)
    case _ => None
}

The advantage of using an Option is that you can flatMap that shit (scnr):

val xs = List((1,2), (0,0), (-1,0), (-1,-1), (3,4))
xs.flatMap(x => func(x._1, x._2)) # => List(3, 0, 7)

The alone is probably a good enough reason to add just a little more noise compared to require since it enables you to use a lot of the standard Scala library more concisely.

Regarding partial functions, you are basically answering your own question, since you say that its more cumbersome to use and to define. I don't have any experience with Scalaz though, so I can't really compare the "pure scala" approach to anything one might do with Scalaz.

Community
  • 1
  • 1
fresskoma
  • 25,481
  • 10
  • 85
  • 128