15

I am writing my own simple javax.sql.DataSource implementation, the only method of it I need to work is getConnection: Connection, but the interface inherits many other methods (which I don't need) from javax.sql.CommonDataSource and java.sql.Wrapper. So, I would like to "implement" those unneeded methods a way they wouldn't actually work but would behave an adequate way when called. For example I implement boolean isWrapperFor(Class<?> iface) as

def isWrapperFor(iface: Class[_]): Boolean = false

and I'd like to implement <T> T unwrap(Class<T> iface) as

def unwrap[T](iface: Class[T]): T = null

But the last doesn't work: the compiler reports type mismatch.

Will it be correct to use null.asInstanceOf[T] or is there a better way? Of course I consider just throwing UnsupportedOperationException instead in this particular case, but IMHO the question can still be interesting.

4 Answers 4

26

This is because T could be a non-nullable type. It works when you enforce T to be a nullable type:

def unwrap[T >: Null](iface: Class[T]): T = null

unwrap(classOf[String]) // compiles

unwrap(classOf[Int]) // does not compile, because Int is not nullable
Sign up to request clarification or add additional context in comments.

5 Comments

Didn't new that there are non-nullable types in Scala... I thought Int is nullable unlike Java primitive int...
Int is of type AnyVal and value types are not nullable.
as @oxbow_lakes mentions though, throwing is preferable to returning null in most cases
This helped me out (trying to write a helper that makes it easier to call a Java library). As a side note do you know why you can't you use an upper bound of AnyRef? I thought Null a subtype of all reference classes?
You can use AnyRef, but then you have to cast null to T. Also I think it's just clearer to say this type has to be nullable instead of saying it has to be a reference type.
6

The "correct" solution is to do something which will immediately fail. Like so:

def unwrap[T](iface: Class[T]): T = sys.error("unimplemented")

In scala 2.10, this would have been implemented as:

def unwrap[T](iface: Class[T]): T = ???

Because there is a new method in Predef called ???. This works because an expression of the form throw new Exception has the type Nothing, which is a subtype of any type (it is called bottom in type-theoretical circles).

The reason that this is correct is that it is much better to fail instantly with an error, rather than use a null which may fail later and obfuscate the cause.

2 Comments

I haven't dealt with isWrapperFor/unwrap in practice but suppose that unwrap is to equal null in case isWrapperFor equals false and implementing isWrapperFor as = null seems the most adequate in case the object can never be a wrapper. Am I not right?
def ??? = throw new UnsupportedOperationException // very easy to add in Scala < 2.10
1

As said in comments, this solution doesn't work

If I understood your problem well, you can also assign default values, as explained in details in what does it mean assign "_" to a field in scala?. You can find more infos in 4.2 Variable Declarations and Definitions of the The Scala Language Specification

So you can simply do:

def unwrap[T](iface: Class[T]): T = _

which will set unwrap with null without the type mismatch.

1 Comment

That is true, I didn't know this didn't work with functions, which by the way is sad. Thanks for the correction
0

You can use option:

def nullHandledFunctionCall[T]( obj: Option[T], function: T=>T ) = {
    if(obj == null){
      None
    }else{
      obj.map(function)
    }
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.