Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I use Option as result when fetching an object from the database with an Id?

I have made a definition which fetches a user from the database.

 def user(userId: Int) : User = database withSession {
    (for{
      u <- Users if u.id === userId} 
    yield u).first
  }

Potetially the database could return an empty list if used with an non existing userId.
However I can't see when a non existing userId would be provided. For example my userId is fetched from the logged in user. And if a non existing userId is provided then I think it's ok to fail the request hard.

Any thoughts?


1 Answers

No it's not ok to fail the request hard :

def user(userId: Int) : Option[User] // is OK
def user(userId: Int) : Either[String,User] // is OK
def user(usedId: Int) : User // is not OK

or else you could create a type (a concept) which encapsulate an Integer which make sure it's a valid UserId (at birthing).

sealed case class UserId(u:Int) //extends AnyVal // If it's scala 2.10.0

object UserId {
    def get(i:Int) : Option[UserId] = //some validation

} /// ....

def  user(userId:UserId) : User //is OK // well it depends on the semantic of user destruction.

When you make a def, you must make sure there is a proper relation between the domain (this and args) of your function and the codomain (result).

Anyways, do not hesitate to type (create concepts), it will help you to reason about your code.


Why def user(userId: Int) :User is not Ok ?

Because a relation between the elements of Integer to the elements of User doesn't exist. What if UserIds are all positive integers, but you ask for user(-10) ? (it won't happen, right ?) Should this call raise an exception ? Or return null ?

If you think it should return null, then return an Option, it encapsulates the potential missing correspondance.

If you think it should raise an exception, then return :

  • a Validation[SomethingRepresentingAnError, User] (scalaz),
  • an Either[SomethingRepresentingAnError, User] (scala 2.7, 2.8, 2.9)
  • or a Try[User] (scala 2.10)

Having rich return types will help you to use your API correctly.

Btw Scala doesn't use checked exception, so you cannot use exception as an alternative result. Exception should be keept for truly exceptional behaviour (as Runtime Exceptions).

See also :

  • http://www.scala-lang.org/api/current/index.html#scala.util.control.Exception$
like image 180
jwinandy Avatar answered Dec 02 '25 18:12

jwinandy