Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit within pattern match

I have a method, with have a lot of implicit parameters:

def hello(message:String)(implicit a:A,b:B,c:C, ..., user: User) = {...}

Now consider such a class:

object Users extends Controller {
  implicit a: A = ...
  implicit b: B = ...
  ...

  def index(id:String) = Action {
     User.findById(id) match {
       case Some(user) => {
          implicit val _user = user
          hello("implicit")
       }
       case _ => BadRequest
     }
  }
}

You can see this line in the above sample:

implicit val _user = user

It exists just to make the object user as an implicit object. Otherwise, I have to call hello as:

hello("implicit")(a,b,c,... user)

I'm thinking if there is any way to improve the code, e.g. we don't need to define that _user variable but make the user is implicit.

like image 479
Freewind Avatar asked Mar 09 '12 11:03

Freewind


2 Answers

Yes, there is a way to eliminate _user variable while making user implicit:

def index(id:String) = Action {
  User.findById(id) map (implicit user => hello("implicit")) getOrElse BadRequest
}

UPDATE: Addressing your question about many cases in the comments below.

It all depends what value type is returned by User.findById. If it's Option[User] but you want to match on specific users (assuming User is a case class), then the original solution still applies:

def index(id:String) = Action {
  User.findById(id) map { implicit user =>
    user match {
      case User("bob") => hello("Bob")
      case User("alice") => hello("Alice")
      case User("john") => hello("John")
      case _ => hello("Other user")
    }
  } getOrElse BadRequest

Or you can match on anything else if you want, as long as User.findById is String => Option[User]

If, on the other hand, User.findById is String => User then you can simply define a helper object like:

object withUser {
  def apply[A](user: User)(block: User => A) = block(user)
}

And use it as follows (again assuming User is a case class):

def index(id: String) = Action {
  withUser(User findById id) { implicit user =>
    user match {
      case User("bob") => hello("Bob")
      case User("alice") => hello("Alice")
      case User("john") => hello("John")
      case _ => BadRequest
    }
  }
}

or matching on some other value, say an Int:

def index(id: String, level: Int) = Action {
  withUser(User findById id) { implicit user =>
    level match {
      case 1 => hello("Number One")
      case 2 => hello("Number Two")
      case 3 => hello("Number Three")
      case _ => BadRequest
    }
  }
}

I hope this covers all the scenarios you may have.

like image 181
romusz Avatar answered Oct 13 '22 17:10

romusz


I know of no trick such as case Some(implicit user) but what about

def hello(message: String, user: User)(implicit a: A, ... z: Z) = ...
def hello(message: String)(implicit a: A, ... z: Z, user: User) = hello(message, user)

case Some(user) => hello("implicit", user)
like image 37
Didier Dupont Avatar answered Oct 13 '22 18:10

Didier Dupont