Google App Engine Data Store Api is definitely beta
Was very surprised to see that when querying the data store service for a key and the key does not exist the service actually throws an exception instead of returning null or indicating the absence of value in another way. Definitely need a code review from Josh Bloch. Josh wrote in his Effective Java "Exceptions ... should never be used for ordinary control flow".
In Scala it actually makes things very ugly, instead of doing
ds.get(queryKey) match {
case null => {
logger.info("did not got it: " + queryKey.toString)
...
}
case entity: Entity if (null != entity) => {
logger.info("got it: " + entity.toString)
...
}
}
I must go with something like try {
val entity = ds.get(queryKey)
logger.info("got it: " + entity.toString)
...
}
catch {
case ex: EntityNotFoundException => {
logger.info("did not got it: " + queryKey.toString)
...
}
}Which may totally disrupt a nice chain of pattern matching.Keeping an eye on Issue 1961







5 comments:
I think this is a very "ActiveRecord" way of doing things, where if you do a Model.find(nonexistent_key) it'll throw a RecordNotFound exception. The reason that paradigm seems to work is specifically because the Rails framework provides some syntatically pleasant ways of handling exceptions for an entire group of methods or for globally handling an exception.
Yeah, I can see why this sucks for GAE. I'm surprised there isn't an option to throw an exception or return null on an invalid key. Next version, I guess.
def exceptionToRight[T](f : => T): Either[T,java.lang.RuntimeException] =
try {
Left(f)
} catch {
case ex => Right(ex)
}
exceptionToRight(ds.get(queryKey)) match {
case Right(_) => { logger.info("did not got it: " + queryKey.toString)
...
}
case Left(entity: Entity) if (null != entity) => {
logger.info("got it: " + entity.toString)
...
}
}
Doesn't seem much worse.
Very nice!
Thanks Daniel.
I wonder if it throwing an exception is anything to do with python dictionaries? In python, if you attempt to access a non-existant key in a dictionary it throws an exception.
I think the design is correct. get is used for looking up a known key. if the key doesnt exist, that is an exceptional situation. If you dont know if the key exist or not, you should write a query.
Think of it as Map.apply in scala (which also throws an exception for unknown keys), and suddenly its starting to look quite good.
Lacking a proper Option type in java, I very much prefer the explicit EntityNotFoundException over the dreaded NullpointerException.
Post a Comment