tags:

views:

80

answers:

3

Hi, I'm rater new to scala, but basically have found my way around...

Here, I'm asking for the recommended/best practice/idiomatic way of implementing this:

  • internally, MyClass uses a state type, which is implemented by a sealed hierarchy of case classes
  • but on the API, only some boolean predicate should be exposed, which gets implemented by matching against the (internal) state.

Currently, my implementation is along the lines of...

def isSane: Boolean = state match {
    case Ok(_,'valid) => true
    case _            => false
}

But this solution feels awkward to me, as if expressing something in 3 lines of code which has only information content worth one line of code. Actually, what I'd like to write would be:

def isSane: boolean = state matches Ok(_, 'valid)

Probably/likely it's possible to implement a suitable operator yourself in scala, but before I look into that, I'd like to know what would be the usual way to solve this problem. Maybe there's also some existing library implementation around?

+1  A: 

If the Symbol property is statically known to be a property of the type of state:

def isSane: Boolean =
  state.secondSymbolPropertyWhateverItsCalled == 'valid

If you don't know that state is an Ok, then:

def isSane: Boolean =
  state.isInstanceOf[Ok] && state.asInstanceOf[Ok].symbolProp == 'valid

but at this point, it's not really superior to what you wrote.

Lastly, you could just define isSane on that hierarchy of types and delegate to it:

def isSane: Boolean =
  state.isSane
Randall Schulz
In the example I had in mind, the point is just really to match on some property in one of the possible states.
Ichthyo
well... another intersting question would be regarding performance.
Ichthyo
...My guess would be that the compiler actually generates something similar to your second example from the original pattern match, while OTOH, placing the isSane into the State hierarchy would allow to trade some additional storage for possibly improved performance. But anyway, in most cases such fine differences won't matter, given the performance of today's systems
Ichthyo
+2  A: 

I may be old-fashioned, but why not use polymorphism?

trait State { def sane: Boolean }

trait InvalidState extends State { def sane = false }

case class Ok(whatever: Whatever, s: Symbol) extends State {
   def sane = { s == 'valid }
}

case class Failure(msg: String) extends InvalidState 

case class WarmingUp extends InvalidState

// ...

def isSane(): Boolean = state.sane

Of course, if that's not a possibility for whatever reason, you can generalize Daniel's solution somewhat:

class Matcher[T](o: T) {
   def matches(pf: PartialFunction[T, Unit]) = pf isDefinedAt o
}

object Matcher {
   implicit def o2matcher[T](o: T): Matcher[T] = new Matcher(o)
}

// then
def isSane = state matches { case Ok(_,'valid) => }
Aaron Novstrup
It seems to me that `State` is not the class on which `sane` is being called, just a class used internally.
Daniel
I'd go for the classical OO-style solution as soon as the check gets more complicated to implement. I don't consider that old-fashioned, just form me the *readability* is the criterion. That is, if the pattern match based solution can be written in one line and in a way which immediately communicates my intention, then I'd prefer it over the classical approach
Ichthyo
+2  A: 

I'd do something like this:

abstract class State {
  def matches(pf: PartialFunction[State, Unit]) = pf isDefinedAt this
}

// then

def isSane = state matches { case Ok(_,'valid) => }

Because matches is defined to receive a partial function, you can follow it with a function literal with only the case statements that should result in true. You do not need to return anything, as the partial function is defined as returning Unit. Finally, the matches method uses the isDefinedAt method of partial functions to verify if there's a case statement covering itself.

Daniel
yeah, indeed that's what I had in mind, in case it would be necessary to implement it myself....
Ichthyo