I´ve been watching some examples of monads transformers with Cats, and I was trying to reproduce those in Scalaz
Here I have a for comprehension where I first receive an optional which I flatMap with OptionalT, and the second function return a Future of Employee.
Here my code
//Attributes for this example
sealed trait Employee {
val id: String
}
final case class EmployeeWithoutDetails(id: String) extends Employee
final case class EmployeeWithDetails(id: String, name: String, city: String, age: Int) extends Employee
case class Company(companyName: String, employees: List[EmployeeWithoutDetails])
trait HybridDBOps {
protected def getDetails(employeeId: String): Future[EmployeeWithDetails]
protected def getCompany(companyName: String): Option[Company]
}
class DbHybrid extends HybridDBOps {
override def getDetails(employeeId: String): Future[EmployeeWithDetails] = Future {
EmployeeWithDetails("1", "name", "city", 36)
}
override def getCompany(companyName: String): Option[Company] = Some(Company(companyName, List(EmployeeWithoutDetails("1"))))
}
def getEmployeeAgeScalaZHybrid(employeeId: String, companyName: String): Future[Option[Int]] = {
val db = new DbHybrid
val eventualOption = (for {
company <- OptionT.fromOption(db.getCompany(companyName)) --> Wont compile
if company.employees map (_.id) contains employeeId
details <- OptionT.liftF(db.getDetails(employeeId)) --> Wont compile
} yield details.age).run
eventualOption
}
This code is from cats version, and in scalaz the OptionT.fromOption to wrap a Option does not exist, I notice that I can do OptionT(Some(db.getCompany(companyName)) and then compile but now the signature of the method says that I returning an Optional instead of a future.
Also how can use the OptionT.liftF in ScalaZ
Here the complete example https://github.com/politrons/reactiveScala/blob/master/scala_features/src/main/scala/app/impl/scalaz/MonadTransformer.scala
Regards.
These should work as substitutes:
import scalaz.std.future._
import scalaz.syntax.monad._
// instead of OptionT.fromOption(db.getCompany(companyName))
OptionT(db.getCompany(companyName).pure[Future])
// instead of OptionT.liftF(db.getDetails(employeeId))
db.getDetails(employeeId).liftM[OptionT]
However, it would be good to have both methods also on OptionT. You could add them and open a pull request.
Related
I'm trying to use implicits in Scala.
object TypeClasses extends App {
trait HTMLWritable {
def toHTML: String
}
case class User(name: String, age: Int, email: String) extends HTMLWritable {
override def toHTML: String = s"<div>$name ($age yo) <a href=$email/> </div>"
}
val john = User("John", 32, "john#rockthejvm.com")
trait HTMLSerializer[T] {
def serialize(value: T): String
}
object UserSerializer extends HTMLSerializer[User] {
def serialize(user: User): String = s"<div>${user.name} (${user.age} yo) <a href=${user.email}/> </div>"
}
implicit class HTMLEnrichment[T](value: T) {
def toHTML(serializer: HTMLSerializer[T]): String = serializer.serialize(value)
}
println(john.toHTML(UserSerializer))
}
this code won't compile:
Error:(41, 23) type mismatch;
found : lectures.part4implicits.TypeClasses.UserSerializer.type
required: Int
println(john.toHTML(UserSerializer))
I'm having trouble understanding the message, because according to IntelliJ, john.toHTML is a call to the toHTML method on the HTMLEnrichment class, which expects a HTMLSerializer, which is what I have given it. Nowhere have I defined a toHTML method which requires an Int.
It's because you've accidentally overloaded the toHTML method. The error you're getting is because String.apply returns the character at a given index, which is why you are getting that error about the Int.
Intelij is not always efficient at picking out this kind of shadowing. It's a good idea to keep implicit mechanisms away from domain model, e.g de-couple specialised serialisations into implicits, just like you are doing with:
implicit object UserSerializer extends HTMLSerializer[User] {
def serialize(user: User): String = s"<div>${user.name} (${user.age} yo) <a href=${user.email}/> </div>"
}
Then remove everything from your user, and maybe add a helper.
trait HTMLSerializer {
def toHTML: String
}
object HTMLSerializer {
// if you put this here you don't need to explicitly import it.
implicit class HTMLEnrichment[T](val value: T) extends AnyVal {
def toHTML(implicit serializer: HTMLSerializer[T]): String =
serializer.serialize(value)
}
}
This means you can simply get the same effect as having a companion method, but you can keep everything nicely de-coupled, and you don't risk having those kinds of shading effects.
I am trying to learn about the cake pattern.
I am reading this blog about it.
The example code from that blog is:
case class User (name:String,email:String,supervisorId:Int,firstName:String,lastName:String)
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
trait UserRepositoryComponent {
def userRepository: UserRepository
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
}
trait Users {
this: UserRepositoryComponent =>
def getUser(id: Int): User = {
userRepository.get(id)
}
def findUser(username: String): User = {
userRepository.find(username)
}
}
trait UserInfo extends Users {
this: UserRepositoryComponent =>
def userEmail(id: Int): String = {
getUser(id).email
}
def userInfo(username: String): Map[String, String] = {
val user = findUser(username)
val boss = getUser(user.supervisorId)
Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
def userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepository {
def get(id: Int) = {
???
}
def find(username: String) = {
???
}
}
}
object UserInfoImpl extends
UserInfo with
UserRepositoryComponentImpl
I can simplify that code by removing Users:
package simple {
case class User(name: String, email: String, supervisorId: Int, firstName: String, lastName: String)
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
trait UserRepositoryComponent {
def userRepository: UserRepository
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
}
trait UserInfo {
this: UserRepositoryComponent =>
def userEmail(id: Int): String = {
userRepository.get(id).email
}
def userInfo(username: String): Map[String, String] = {
val user = userRepository.find(username)
val boss = userRepository.get(user.supervisorId)
Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
def userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepository {
def get(id: Int) = {
???
}
def find(username: String) = {
???
}
}
}
object UserInfoImpl extends
UserInfo with
UserRepositoryComponentImpl
}
and it compiles just fine.
1) Why is the code in the blog so complicated ?
2) Is that the idiomatic way to use the cake pattern ?
3) Why is the Users class needed in this example ?
4) Is that the way the cake pattern supposed to look like (with that seemingly unnecessary Users class?
5) Or is the simplified version just fine ?
At first it might look like it's complicated, but once you get familiar with that pattern it's just... boilerplaty and cumbersome. For every service of yours you have to create an accompanying component that will be wrapping that service. So in the provided example you have a UserRepository that's wrapped by a UserRepositoryComponent. And this is only the abstraction, so you need to have a concrete implementation for both the component and the service (i.e. UserRepositoryComponentImpl wrapping UserRepositoryImpl). And so far you have only one service that might be used in your modules, imagine the effort to create dozens of services ;)
Yes, this is the idiomatic way to use that pattern. However there are also other variations of that pattern, e.g. thin cake pattern or parfait (a term coined by Dick Wall)
You're asking about User, yet your code simplification was to remove Users, so I'll describe both of them. User is a simple case class, that should make that example more accessible/easier to grasp. Users however were not necessary here (it's just another intermediate level of abstraction), and in my opinion they bring some unnecessary noise to the example.
I would say that your simplified version shows exactly how cake pattern should look like. You have an abstract UserRepository wrapped inside of UserRepositoryComponent, you have a concrete implementation of both those traits, and you have some service (UserInfo) that requires the repository of users (which is "injected" using self-type annotation).
Already answered.
I am working on a web app where I have a bunch of models.
Every model extends and implements the following abstract class:
abstract class BaseModel {
val dateCreated: String
val dateUpdated: String
}
trait BaseModelCompanion[A <: BaseModel] {
implicit val reads: Reads[A]
implicit val writes: Writes[A]
}
Example:
case class User(id: String, name: String, dateCreated: String, dateUpdated: String) extends BaseModel {
...
}
object User extends BaseModelCompanion[User] {
implicit val reads = Reads[User] = (...)
implicit val writes = new Writes[User] { ... }
}
Now I want to add an abstract method to my BaseModel called update, where each model will take in some Json and return a clone of itself. This is what an implementation would look like:
case class User(id: String, dateCreated: String, dateUpdated: String) extends BaseModel {
// Every model needs one of these
def update(jsValue: JsValue): User = {
copy(
name = (jsValue \ "name").as[String].get,
...
)
}
}
My problem is that I am struggling to define the abstract method signature:
abstract class BaseModel {
val dateCreated: String
val dateUpdated: String
def update(jsValue: JsValue): ______ // How do I say return an object of type "self"
}
You can use F-bounded polymorphism
abstract class BaseModel[A <: BaseModel[A]] {
val dateCreated: String
val dateUpdated: String
def update(jsValue: String): A
}
case class User(id: String, dateCreated: String, dateUpdated: String) extends BaseModel[User] {
def update(jsValue: String): User = {
copy(id = jsValue)
}
}
EDIT by oxbow_lakes
The feature you are hoping for has been called mytype and has been suggested in the past as trivially implementable by scalac as an additional language feature (by #extempore). IIRC it was rejected at the time because of some obscure corner cases. (See the distant history of the scala mailing lists)
I am still pretty new to Scala and looking at using Slick.
I also am looking at Accord (github.com/wix/accord) for validation.
Accord's validation seems to be on objects as a whole, but I want to be able to define validators for field types, so I've thought of using type aliasing using value classes so that I can easily re-use validations across various case classes that use those field types.
So, I've defined the following:
object FieldTypes {
implicit class ID(val i: Int) extends AnyVal
implicit class UserPassword(val s: String) extends AnyVal
implicit class Email(val s: String) extends AnyVal
implicit class Name(val s: String) extends AnyVal
implicit class OrgName(val s: String) extends AnyVal
implicit class OrgAlias(val s: String) extends AnyVal
}
package object validators {
implicit val passwordValidator = validator[UserPassword] { _.length is between(8,255) }
implicit val emailValidator = validator[Email] { _ is notEmpty }
implicit val nameValidator = validator[Name] { _ is notEmpty }
implicit val orgNameValidator = validator[OrgName] { _ is notEmpty }
implicit val teamNameValidator = validator[TeamName] { _ is notEmpty }
}
case object Records {
import FieldTypes._
case class OrganizationRecord(id: ID, uuid: UUID, name: OrgName, alias: OrgAlias)
case class UserRecord(id: ID, uuid: UUID, email: Email, password: UserPassword, name: Name)
case class UserToOrganizationRecord(userId: ID, organizationId: ID)
}
class Tables(implicit val p: JdbcProfile) {
import FieldTypes._
import p.api._
implicit object JodaMapping extends GenericJodaSupport(p)
case class LiftedOrganizationRecord(id: Rep[ID], uuid: Rep[UUID], name: Rep[OrgName], alias: Rep[OrgAlias])
implicit object OrganizationRecordShape extends CaseClassShape(LiftedOrganizationRecord.tupled, OrganizationRecord.tupled)
class Organizations(tag: Tag) extends Table[OrganizationRecord](tag, "organizations") {
def id = column[ID]("id", O.PrimaryKey)
def uuid = column[UUID]("uuid", O.Length(36, varying=false))
def name = column[OrgName]("name", O.Length(32, varying=true))
def alias = column[OrgAlias]("alias", O.Length(32, varying=true))
def * = LiftedOrganizationRecord(id, uuid, name, alias)
}
val organizations = TableQuery[Organizations]
}
Unfortunately, I clearly misunderstand or overestimate the power of Scala's implicit conversions. My passwordValidator doesn't seem to recognize that there is a length property to UserPassword and my * declaration on my Organizations table doesn't seem to think that it complies to the shape defined in LiftedOrganizationRecord.
Am I just doing something really dumb here on the whole? Should I not be even trying to use these kinds of custom types and simply use standard types instead, defining my validators in a better way? Or is this an okay way of doing things, but I've just forgotten something simple?
Any advice would be really appreciated!
Thanks to some helpful people on the scala gitter channel, I realized that the core mistake was a misunderstanding of the conversion direction for value classes. I had understood it to be ValueClass -> WrappedValueType, but it's actually WrappedValueType -> ValueClass. Thus, Slick wasn't seeing, as an exmaple, ID as an Int.
I have two case classes, let's call them case class User & case class Ticket. Both of these case classes implement the operations required to be members of a the same TypeClass, in this case Argonaut's EncodeJson.
Is it possible to view these two separate types as the same without creating an empty marker type that they both extend?
trait Marker
case class User extends Marker
case class Ticket extends Marker
To make this concrete,we have two separate functions that return these case classes:
case class GetUser(userId: Long) extends Service[Doesn't Matter, User] {
def apply(req: Doesn't Matter): Future[User] = {
magical and awesome business logic
return Future[User]
}
}
case class GetTicket(ticketId: Long) extends Service[Doesn't Matter, Ticket] {
def apply(req: Doesn't Matter): Future[Ticket] = {
magical and awesome business logic
return Future[Ticket]
}
}
I would like to compose these two Services so that they return the same type, in this case argonaut.Json, but the compiler's response to an implicit conversions is "LOLNO"
implicit def anyToJson[A](a: A)(implicit e: EncodeJson[A]): Json = e(a)
Any ideas? Thanks!
If you've got these case classes:
case class User(id: Long, name: String)
case class Ticket(id: Long)
And these instances:
import argonaut._, Argonaut._
implicit val encodeUser: EncodeJson[User] =
jencode2L((u: User) => (u.id, u.name))("id", "name")
implicit val encodeTicket: EncodeJson[Ticket] = jencode1L((_: Ticket).id)("id")
And the following services (I'm using Finagle's representation):
import com.twitter.finagle.Service
import com.twitter.util.Future
case class GetUser(id: Long) extends Service[String, User] {
def apply(req: String): Future[User] = Future(User(id, req))
}
case class GetTicket(id: Long) extends Service[String, Ticket] {
def apply(req: String): Future[Ticket] = Future(Ticket(id))
}
(These are nonsense but that doesn't really matter.)
Then instead of using an implicit conversion to change the return type, you can write a method to transform a service like this:
def toJsonService[I, O: EncodeJson](s: Service[I, O]): Service[I, Json] =
new Service[I, Json] {
def apply(req: I) = s(req).map(_.asJson)
}
And then apply this to your other services:
scala> toJsonService(GetTicket(100))
res7: com.twitter.finagle.Service[String,argonaut.Json] = <function1>
You could also provide this functionality as a service or a filter, or if you don't mind getting a function back, you could just use GetTicket(100).andThen(_.map(_.asJson)) directly.
The key idea is that introducing implicit conversions should be an absolute last resort, and instead you should use the type class instance directly.