user425367
user425367

Reputation:

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?

Upvotes: 3

Views: 218

Answers (3)

jwinandy
jwinandy

Reputation: 1749

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$

Upvotes: 4

Randall Schulz
Randall Schulz

Reputation: 26486

Option is the most minimalistic way to represent the return value from some computation that may fail. Throwing exceptions or returning null are acceptable only when dealing with Java code and your hands are somehow tied by an existing API (and when you're code is being called from Java code).

The next step up from Option would be Either[FailureIndication, SuccessValue].

A further improvement is ScalaZ's Validation.

Upvotes: 1

kompot
kompot

Reputation: 798

I think it's always good idea to return Option[] when fetching data by id. You can not be sure that user with such id exist. E. g. another request has deleted this user or somebody was trying to tamper with your input data. Database is an external system to your application and if you know how to recover from such failures then you should do it. Especially in Scala where Option is a good tool for such task.

Upvotes: 1

Related Questions