Brian Hsu
Brian Hsu

Reputation: 8821

For comprehension body to execute when Lift Box[T] has Empty value

I'm quite happy with working with Option type in Scala, and Lift's Box[T] is great too.

But I'm little confused with how to dealing with Empty when it's a valid state.

For example, my program has three vals: title, startDate and endDate, title and startDate are required field, but endDate could be empty.

Now, I want get those data from database, so I wrapped them into Box[T], and in the following case, endDate returned Empty which means in database it is NULL.

Now I want print those data on screen, so I've the following code, but it will not work because endDate is Empty, so the body of for comprehension will not execute.

import net.liftweb.common._

object Main
{
    val title: Box[String] = Full("title")
    val startDate: Box[String] = Full("startDate")
    val endDate: Box[String] = Empty

    def main(args: Array[String]) {

        for (title <- this.title; startDate <- this.startDate; 
             endDate <- this.endDate)  
        {   
            println("Title:" + title)
            println("StartDate:" + startDate)
            println("EndDate:" + endDate)   // I hope now endDate = Empty or None
        }
    }
}

If I make endDate as Box[Option[String]], it will works fine, but I feel it is a little ugly, because Box[String] should be sufficient to denote that endDate is NULL in database.

Upvotes: 1

Views: 653

Answers (2)

leedm777
leedm777

Reputation: 24062

If you want to handle the case where endDate is Empty, then simply don't extract it.

for (title <- this.title; startDate <- this.startDate) {
  println("Title:" + title)
  println("StartDate:" + startDate)
  println("EndDate:" + this.endDate)   // this.endDate == Empty
}

Edit:

If you to handle failures, just add match..case or if tests.

this.endDate match {
  case f: Failure =>
    // handle failure
  case endDate =>
    for (title <- this.title; startDate <- this.startDate) {
      println("Title:" + title)
      println("StartDate:" + startDate)
      println("EndDate:" + endDate)   // endDate == Empty
    }
}

Upvotes: 1

Brian Hsu
Brian Hsu

Reputation: 8821

Finally I come out with this implicit conversion and wrapper class:

class ValidEmptyBox[T](box: Box[T])
{
    def validEmpty: Box[Box[T]] = box match {
        case Full(x) => Full(Full(x))
        case Empty => Full(Empty)
        case Failure(msg, exception, chain) => Failure(msg, exception, chain)
    }
}

object ValidEmptyBox {
    implicit def toValidEmptyBox[T](box: Box[T]) = new ValidEmptyBox(box)
}

for(empty <- Empty.validEmpty) {
    println(empty) // Empty
}

for(full <- Full("AA").validEmpty) {
    println(full)  // Full(AA)
}

for(fail <- Failure("Failure").validEmpty) {
    println(fail)  // No output
}

It seems works for me, but I will still like to know if there is a better way to do this.

Upvotes: 1

Related Questions