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.
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.
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)
Related
I want to refactor by update action below to look a little more readable and also handle the failure case better
The userService has the following functions:
class UserService {
def getUserByUsername: Future[Option[Int]] // which is the UserId
def getUserById: Future[User]
}
My action looks like:
def update(userId: Int) = Action.async { implicit request =>
request.body.validate[User] match {
case JsSuccess(user, _) => {
userService.getUserByUsername(user.username).map { userId =>
userService.getUserById(userId.get).map { existingUser =>
userService.update(user.username)
Ok
}
}
}
case JsError(err) => Future.sucessful(BadRequest(err))
}
}
How do I handle the situation where getUserByUsername returns a None?
Would this look cleaner if it was in a for comprehension, is it better style?
You have some missing data in your questions such as case classes for the User model, userService class.
also better to attach the original function.
Anyways, I will do something as follows:
def update(userId: Int) = Action { implicit request =>
request.body.validate[User] match {
case JsSuccess(user: User, _) => {
val userId = getUserByUsername(user.username)
userId match {
case Some(userId) => {
for {
_ <- userService.getUserById(userId)
_ <- userService.update(user.username)
} yield Ok
}.recover {
case t: Throwable =>
Metrics.errOnUpdate.increment() // Some metric to monitor
logger.error(s"update userId: $userId failed with ex: ${t.getMessage}") // log the error
InternalServerError(Json.toJson(Json.obj("error" -> "Failure occured on update"))) // return custom made exception to the client
}
case None => Future.successful(NotFound(s"No such user with ${user.username}"))
}
}
case JsError(err) => Future.sucessful(BadRequest(err))
}
}
Note: If .update returns Future, you actually not waiting to update before returning Ok to the user, thus, if its fails, its still returns Ok.
To fix that, use flatMap and then map the value of update response.
You can also separate the recovering for the getUserById and update if you prefer.
Edit:
def update(userId: Int) = Action { implicit request =>
request.body.validate[User] match {
case JsSuccess(user: User, _) => {
getUserByUsername(user.username).flatMap {
case Some(userId) => for {
_ <- userService.getUserById(userId)
_ <- userService.update(user.username)
} yield Ok
case None => Future.successful(NotFound(s"No such user with ${user.username}"))
}
}.recover {
case t: Throwable =>
Metrics.errOnUpdate.increment() // Some metric to monitor
logger.error(s"update userId: $userId failed with ex: ${t.getMessage}") // log the error
InternalServerError(Json.toJson(Json.obj("error" -> "Failure occured on update"))) // return custom made exception to the client
}
}
case JsError(err) => Future.sucessful(BadRequest(err))
}
}
First, you probably need to use Option.fold:
#inline final def fold[B](ifEmpty: => B)(f: A => B)
Then you can do something like this:
def update(userId: Int) = Action.async { implicit request =>
def handleJsonErrors(errors: Seq[(JsPath, collection.Seq[JsonValidationError])]): Future[Result] = ???
def updateUser(userWithoutId: User): Future[Result] = {
for {
userId <- userService.getUserByUsername(userWithoutId.username)
_ <- userService.getUserById(userId.get)
_ <- userService.update(userWithoutId.username)
} yield {
Ok
}
}
request.body.asJson.fold {
Future.successful(BadRequest("Bad json"))
} {
_.validate[User].fold(handleJsonErrors, updateUser).recover {
case NonFatal(ex) =>
InternalServerError
}
}
}
I want to generate a bunch of objects at compile time that follow a simple pattern, so I wrote the following macro:
object MyMacro {
def readWrite[T](taName: String, readParse: String => T, label: String, format: T => String): Any = macro readWriteImpl[T]
def readWriteImpl[T: c.WeakTypeTag](c: Context)(taName: c.Expr[String], readParse: c.Expr[String => T], label: c.Expr[String], format: c.Expr[T => String]): c.Expr[Any] = {
import c.universe._
def termName(s: c.Expr[String]): TermName = s.tree match {
case Literal(Constant(s: String)) => TermName(s)
case _ => c.abort(c.enclosingPosition, "Not a string literal")
}
c.Expr[Any](q"""
object ${termName(taName)} extends TypeAdapter.=:=[${implicitly[c.WeakTypeTag[T]].tpe}] {
def read[WIRE](path: Path, reader: Transceiver[WIRE], isMapKey: Boolean = false): ${implicitly[c.WeakTypeTag[T]].tpe} =
reader.readString(path) match {
case null => null.asInstanceOf[${implicitly[c.WeakTypeTag[T]].tpe}]
case s => Try( $readParse(s) ) match {
case Success(d) => d
case Failure(u) => throw new ReadMalformedError(path, "Failed to parse "+${termName(label)}+" from input '"+s+"'", List.empty[String], u)
}
}
def write[WIRE](t: ${implicitly[c.WeakTypeTag[T]].tpe}, writer: Transceiver[WIRE], out: Builder[Any, WIRE]): Unit =
t match {
case null => writer.writeNull(out)
case _ => writer.writeString($format(t), out)
}
}
""")
}
}
I'm not sure I have the return value for readWrite and readWriteImpl correct--the compiler complains mightily about some assertion failure!
I'm also not sure how to actually consume this macro. First I tried (in a separate compilation unit):
object TimeFactories {
MyMacro.readWrite[Duration](
"DurationTypeAdapterFactory",
(s: String) => Duration.parse(s),
"Duration",
(t: Duration) => t.toString)
}
Didn't work. If I tried to reference TimeFactories.DurationTypeAdapterFactory I got an error saying it wasn't found. Next I thought I'd try assigning it to a val...didn't work either:
object Foo {
val duration = MyMacro.readWrite[Duration](
"DurationTypeAdapterFactory",
(s: String) => Duration.parse(s),
"Duration",
(t: Duration) => t.toString).asInstanceOf[TypeAdapterFactory]
}
How can I wire this up so I get generated code compiled like this:
object TimeFactories{
object DurationTypeAdapterFactory extends TypeAdapter.=:=[Duration] {
def read[WIRE](path: Path, reader: Transceiver[WIRE], isMapKey: Boolean = false): Duration =
reader.readString(path) match {
case null => null.asInstanceOf[Duration]
case s => Try( Duration.parse(s) ) match {
case Success(d) => d
case Failure(u) => throw new ReadMalformedError(path, "Failed to parse Duration from input 'Duration'", List.empty[String], u)
}
}
def write[WIRE](t: Duration, writer: Transceiver[WIRE], out: Builder[Any, WIRE]): Unit =
t match {
case null => writer.writeNull(out)
case _ => writer.writeString(t.toString, out)
}
}
// ... More invocations of the readWrite macro with other types for T
}
I don't think, that you can generate new identifiers using macros and than use them publicly.
Instead, try to replace object ${termName(taName)} extends TypeAdapter simply with new TypeAdapter and assign invocation of the macro to a val (as in your second example). You will then reference an anonymous (and generated) class stored in a val. Parameter taName becomes redundant.
I currently have something that looks like:
Class UserLocation {
def handleUser1(user: User): Unit = user.location match {
case ... => ..
case ... => ..
case _ => ..
}
}
Class UserLocation2 {
def handleUser2(user: User): Unit = user.location match {
case ... => ..
case ... => ..
case _ => ..
}
}
Class UserLocation3 {
def handleUser3(user: User): Unit = user.location match {
case ... => ..
case ... => ..
case _ => ..
}
}
How can I convert the above to a partial function so I can do something like:
def handleUser(user: User): Unit = handleUser1(user) orElse handleUser2(user) orElse handleUser3(user)
There are a few problems with the your layout and your goal. For one thing, all the handleUser methods are hidden in their own class so the goal, as stated, is impossible because they aren't all in scope at the same time. They might be pulled into scope by making the classes implicit, but for that each class needs a constructor parameter.
So here's one possible solution achieved by dropping all the individual classes.
case class User(location: String)
val handleUser1: PartialFunction[User,Unit] = {
case User("Bern") => println("there")
case User("NYC") => println("here")
}
val handleUser2: PartialFunction[User,Unit] = {
case User("Spain") => println("there")
case User("USA") => println("here")
}
val handleUser3: PartialFunction[User,Unit] = {
case User("moon") => println("far")
case User("earth") => println("near")
case User(_) => println("unknown") // the only default
}
val handleUser = handleUser1 orElse handleUser2 orElse handleUser3
handleUser(User("Bern")) // "there"
handleUser(User("moon")) // "far"
handleUser(User("Boon")) // "unknown"
You can define the functions as PartialFunctions and then compose them using orElse:
val f :PartialFunction[Int, Int] = {
case 1 => 1
}
val f2 :PartialFunction[Int, Int] = {
case 2 => 2
}
val f3 :PartialFunction[Int, Int] = {
case 3 => 3
}
def g = f orElse f2 orElse f3
g(1) // 1
g(2) // 2
g(3) // 3
g(4) // scala.MatchError
P.S
#Suma - Thanks for the input.
How do I define the method return type in the following case:
working code
def deleteInstance(model: String, uid: Long) = model match {
case "menu" => Model.all(classOf[Menu]).filter("uid", uid).get().delete()
case "articles" => Model.all(classOf[Articles]).filter("uid", uid).get().delete()
case "news" => Model.all(classOf[News]).filter("uid", uid).get().delete()
case "image" =>Model.all(classOf[Image]).filter("uid", uid).get().delete()
case "files" =>Model.all(classOf[Files]).filter("uid", uid).get().delete()
case _ => false
}
non-working code:
class ModelManager{
def getModel(model: String) = {
model match{
case "menu" => classOf[Menu]
case "articles" => classOf[Articles]
case _ => false
}
def deleteInstance(model:String, uid: Long) = {
Model.all(getModel(model)).filter("uid", uid).get().delete()
}
}
}
Error raised is:
recursive method getModel needs result
type
It looks like you need an Option:
class ModelManager{
def getModel(model: String) = model match {
case "menu" => Some(classOf[Menu])
case "articles" => Some(classOf[Articles])
case _ => None
}
def deleteInstance(model:String, uid: Long) =
getModel(model) map { m =>
Model.all(m).filter("uid", uid).get().delete()
} getOrElse false
}
You can think of an Option as a container that can hold at most one element. The Option that holds an element x is Some(x). The empty Option is None. Option has several useful methods, including the map and getOrElse methods used above.
The map method applies a function to each element of the "container". Of course, if the container is None, it does nothing (except perhaps to change the static type of the Option). In your case (assuming delete returns a Boolean), the map method will change the Option[Class] into an Option[Boolean].
The getOrElse method returns the element of the option, if there is one, and otherwise returns a default value (false in this case).
Note that you can also simplify your implementation by using the condOpt method defined in PartialFunction:
class ModelManager{
def getModel(model: String) = condOpt(model) {
case "menu" => classOf[Menu]
case "articles" => classOf[Articles]
}
def deleteInstance(model:String, uid: Long) =
getModel(model) map { m =>
Model.all(m).filter("uid", uid).get().delete()
} getOrElse false
}
It looks like getModel will return a Class sometimes, a Boolean others. In Scala, this would typically be modeled using the Either class:
def getModel(model: String) = {
model match{
case "menu" => Left(classOf[Menu])
case "articles" => Left(classOf[Articles])
case _ => Right(false)
}
Left and Right represent the two possible choices of an Either. Callers of this method will need to inspect the return value (probably by using pattern matching as well) to decide if the method returned a Class or Boolean.
It seems you didn't close with parens in the right place. Did you mean this?
class ModelManager{
def getModel(model: String) = {
model match{
// snip
}
} // end method here
def deleteInstance(model:String, uid: Long) = {
Model.all(getModel(model)).filter("uid", uid).get().delete()
}
}
It does not look like you're trying to define a recursive method... Then you're likely to have other issues to resolve as you need a method that returns Class[_] not a combination of Boolean and Class[_] (which would be Any). So may be this would work better?
def getModel(model: String): Class[_] = {
model match{
case "menu" => classOf[Menu]
case "articles" => classOf[Articles]
} // end method here
How would you implement class that parses some input via regex and transforms founded string to some other type? My approach is:
class ARegex[T](regex:Regex, reform:Option[String => T]){
def findFirst(input:String):Option[T] = {
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s) // this won't compile because of type mismatch
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
class BRegex[T](regex:Regex, reform:Option[String => T]) {
def findFirst(input:String) = { //returns Option[Any] - erasure
(regex.findFirstIn(input), reform) match{
case (None, _) => None
case (Some(s), None) => Some(s)
case (Some(s), Some(fun)) => Some(fun(s))
}
}
}
We can solve this problem by eliminating the Option part of the reform's type, and using a different mechanism to indicate that we don't want to change the match in any way. This mechanism is to use identity as a default parameter or pass identity when you don't want the type to change.
class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){
def findFirst(input:String):Option[T] = {
regex.findFirstIn(input) match{
case None => None
case Some(s) => Some(reform(s))
}
}
}
new ARegex("something".r).findFirst("something else") //returns Option[String]
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int]
Well, the problem is the type mismatch, because you are returning either a String or a T, which, of course, are unified at Any. You can't say you are going to return Option[T] and then return Option[String].
Other than that, a simplified version of that code is this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Any] =
regex findFirstIn input map { s => reform map (_(s)) getOrElse s }
}
You could return an Option[Either[String, T]], though. The code would look like this:
class ARegex[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[Either[String, T]] =
regex findFirstIn input map { s => reform map (_(s)) toRight s }
}
Why is reform Option[String => T] instead of just String => T? If you don't pass in a mechanism for creating an instance of your desired type, there's no mechanism for the runtime system to actually create the appropriate object. If you really need to pass in an Option[String => T] then your second case should simply return None.
Also, flatMap is your friend, and will give you the correct behavior (i.e. if reform is None, the method returns None.
class RegexExtractor[T](regex: Regex, reform: Option[String => T]) {
def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f))
}