tags:

views:

188

answers:

4

Idle pondering from a Scala learner perhaps, but ... in my tinkerings I've written the following:

( n.child.size > 0 ) && ( n.child.filter( ! _.isInstanceOf[Text] ).size == 0 )

('n' is a scala.xml.Node, but that's not important. Nor is the particular logic.)

Calling child() twice isn't so good, so I was about to change it:

val list = n.child
( list.size > 0 ) && ( list.filter( ! _.isInstanceOf[Text] ).size == 0 )

But given how much I've come to much appreciate being able to filter() and map() and such without needing to declare intermediate variables, I found this immediately smelly. It's so... so... so Java-ish! :p

Alas, digging through SO and Google and the ScalaDocs (especially Any and AnyRef) and The Book has turned up nothing appropriate. I was hoping perhaps for something like:

n.child{ list => ( list.size > 0 ) && ( list.filter( ! _.isInstanceOf[Text] ).size == 0 ) }

or even

n.child.with{ list => ... }

Does something like this exist? Or am I just getting caught up in a variable-less-ness fervour?

+9  A: 

"with" is, of course, a reserved word in Scala, so let's call it "let", from the similar binding form in Lisp and Haskell. Turns out "let" is just a backwards way of writing function application.

def let[A,B](param:A)(body: A=>B):B = body(param)

let(n.child){list=> ...}

If the bound variable is used only once, you could of course use the anonymous function form, but that defeats the purpose.

Dave Griffith
Nice! And now I've got a new bit of Scala syntax to puzzle through. :-)
Rodney Gitzel
+1  A: 

If you just want to limit the scope of your intermediate variable, you can also just create a block around the predicate:

val n = getNodeByMagic()
val passesTest = {
    val child = n.child
    child.length == 0 && !child.filter(_.isInstanceOf[Text]).isEmpty
}
// child is not defined outside of the block
David Winslow
+14  A: 
{
    import n.child._
    ( size > 0 ) && ( filter( ! _.isInstanceOf[Text] ).size == 0 )
}
Ken Bloom
+4  A: 
class Tap[A](underlying:A){
   def tap[B](func: A=>B) = func(underlying)
}

implicit def anyToTap[A](underlying:A)=new Tap(underlying)

n.child.tap{x =>
   ( x.size > 0 ) &&
   ( x.filter( ! _.isInstanceOf[Text] ).size == 0 )
}
Ken Bloom