3

I've the following scala hierarchy:

sealed trait SessionResult[+T] {
  def toOption: Option[T]
}

object SessionResult {
  trait SessionValue[T] extends SessionResult[T] {
    def session: T
    def toOption: Option[T] = Some(session)
  }
  trait NoSessionValue[T] extends SessionResult[T] {
    def toOption: Option[T] = None
  }

  case class Decoded[T](session: T) extends SessionResult[T] with SessionValue[T]
  case class CreatedFromToken[T](session: T) extends SessionResult[T] with SessionValue[T]

  case object NoSession extends SessionResult[Nothing] with NoSessionValue[Nothing]
  case object TokenNotFound extends SessionResult[Nothing] with NoSessionValue[Nothing]
  case object Expired extends SessionResult[Nothing] with NoSessionValue[Nothing]
  case class Corrupt(e: Exception) extends SessionResult[Nothing] with NoSessionValue[Nothing]
}

But I use this code from java and the following piece of code does not compile:

SessionResult<SomeSession> sr = ...
System.out.println(sr instanceof NoSession)

Why? And also how can I use instanceof to check the class of scala's object?

The error I'm getting is:

Inconvertible types; cannot cast SessionResult<SomeSession> to NoSession.
8
  • why exactly does it not compile? i would guess, because you already know that sr instanceof SessionResult<SomeSession> Commented Jul 20, 2017 at 13:43
  • @XtremeBaumer I get: Inconvertible types; cannot cast SessionResult<SomeSession> to NoSession. Commented Jul 20, 2017 at 13:46
  • then look at what i said next in my previous comment. i am pretty sure that is the reason Commented Jul 20, 2017 at 13:51
  • @XtremeBaumer but I need to get the particular type. Commented Jul 20, 2017 at 13:52
  • try something like sr.get(0) instanceof NoSession or sr instaceof SessionResult<NoSession> Commented Jul 20, 2017 at 13:54

1 Answer 1

5

The problem lies in the fact that you're putting a hard bound on the generic parameter - NoSession is a SessionResult[Nothing].

So (in Java parlance) the only compatible variant of SessionResult<T> compatible to SessionResult.NoSession$ can be SessionResult<Nothing$>.

i.e. this will compile

public SessionResult<Nothing$> test() {

    return null;
}

public void blah() {
    if(test() instanceof SessionResult.NoSession$) {
    }
}

while e.g. this won't

public <T> SessionResult<T> test() {

    return null;
}

public void blah() {
    if(test() instanceof SessionResult.NoSession$) {
    }
}

Fortunately, since NoSession is an object, hence you can just reference-test the singleton value:

SessionResult.NoSession$.MODULE$.equals(test());

(equals is required as due to the variance you need upcast to Object - you can do that manually, but equals saves you some time on that)


Alternatively, you can just selectively wildcard the generic parameter, i.e.:

public static SessionResult<?> testYay() {
    return SessionResult.NoSession$.MODULE$;
}

public static SessionResult<?> testNay1() {
    return null;
}

public static SessionResult<?> testNay2() {
    return SessionResult.Expired$.MODULE$;
}

public static <T> SessionResult<T> testNay3() {
    return null;
}

public static void blah() {
    //prints true
    System.out.println(testYay() instanceof SessionResult.NoSession$);
    //prints false
    System.out.println(testNay1() instanceof SessionResult.NoSession$);
    //prints false
    System.out.println(testNay2() instanceof SessionResult.NoSession$);
    //prints false (and compiles)
    System.out.println((SessionResult<?>) testNay3() instanceof SessionResult.NoSession$);
}

This is a very hacky solution, but probably the most convenient for code that mostly deals with such equality checks in Java. As demonstrated in the testNay3, you can limit the "collateral damage" of using generic types this way via simple in-place casts.

EDIT: changed to wildcard as per Alexey's hint.

Sign up to request clarification or add additional context in comments.

2 Comments

I'd prefer SessionResult<?> to raw SessionResult.
@AlexeyRomanov : arghh, completely forgotten about Java wildcards! Thanks for the hint!

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.