This discussion is archived
1 2 3 Previous Next 33 Replies Latest reply: Nov 14, 2007 10:05 AM by 807603 RSS

using casting combined with the ternary operator

807603 Newbie
Currently Being Moderated
Hi everyone.
I have the following code, which works without problem:
if (list.get(0) instanceof A) {
    something = ((A) list.get(0)).getSomething();
} else {
    something = ((B) list.get(0)).getSomething();
}
...but my eyes hurt when I see it: two identical lines save for the type casting. So I tried this:
something = ((list.get(0) instanceof A? (A) : (B)) list.get(0)).getSomething();
...and it doesn't work! It gives me the following errors:

something = ((list.get(0) instanceof A? *(A)* : (B)) list.get(0)).getSomething();
A cannot be resolved

something = ((list.get(0) instanceof A? (A) : *(B)* ) list.get(0)).getSomething();
B cannot be resolved

something = ((list.get(0) instanceof A? (A) : (B)) list.get(0)).getSomething();
Syntax error on token "list", delete this token

Is it impossible to use the ternary operator here? I tried several combinations of parenthesis, just in case, unsuccessfully.

Thanks!
  • 1. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    Any way you slice it, that code looks bad. Is there a common supertype of both A and B that defines getSomething? And can you use generics in such a way to avoid casting entirely?
  • 2. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    Well, I'm using code not implemented by me, so I can't change the implementation. There's a superclass, let's call it X, and three subclasses: A, B and C. I know for a fact that the members of list are instances either of A or of B. C doesn't have a method getSomething(), so class X can't have a method getSomething(). Is this what you meant?
  • 3. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    Check your parenthesis the segment in bold are grouped
    something = ( (list.get(0) instanceof A? (A) : (B)list.get(0)) ) .getSomething();
  • 4. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    something = ( (list.get(0) instanceof A? *(A)* : (B)list.get(0)) ) .getSomething();

    Now it says A cannot be resolved. The problem seems to be that you can't have a cast that's not contiguous to the object you're casting: it doesn't have a problem with B, that is next to list.get(0), but it doesn't recognize A.

    The reason behind my choice of parenthesis is that the "value" (not a value but a type in this case, and I think that's the problem) returned by the expression list.get(0) instanceof A? (A) : (B) must be either (A) or (B). In your example you're including list.get(0) in the "else" of the ternary operator.

    Any other idea?
    Thanks for the suggestion.

    Edited by: black_blizzard on Nov 14, 2007 9:15 AM
  • 5. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    Wait a minute. If you're assigning the result to "something", and you're using object types, then "something" must have a type that's a supertype of A and B.

    So why are you casting at all?

    If you're using primitive types...then use a conversion method to change the type, rather than casting.
  • 6. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    I dont know what you are doing but this works
         public static void main(String[] args) {
              List lst = new ArrayList(2);
              lst.add("Hello");
              lst.add(new Integer(2));
              String s = lst.get(0) instanceof String?(String)lst.get(0):((Integer)lst.get(0)).toString();
              System.out.println(s);
         }
  • 7. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    To paulcw: Sorry, I don't think I get what you're saying. The thing is this:
    * There is a class called X.
    * There are three subclasses of X called A, B and C.
    * A and B have a method called getSomething that returns a double, but C doesn't have that method.
    * list is an ArrayList<X>.
    * I know for a fact that list.get(0) is either of class A or B.

    To WirajR: in your case you're repeating lst.get(0) twice. I know that works, but I was wondering if there was a way to avoid it.

    Edited by: black_blizzard on Nov 14, 2007 9:25 AM
  • 8. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    import java.util.*;
    
    class X {}
    
    class A extends X {
        public double getSomething() {
            return 0.0;
        }
    }
    
    class B extends X {
        public double getSomething() {
            return 1.0;
        }
    }
    
    class C extends X {}
    
    public class CrazyExample {
        public static void main(String[] args) {
            test(new A());
            test(new B());
        }
    
        static void test(X x) {
            List<X> list = new ArrayList<X>();
            list.add(x);
    
            X elt = list.get(0);
            double value = (elt instanceof A) ? ((A) elt).getSomething() : ((B) elt).getSomething();
            System.out.println(value);
        }
    }
    The design is still wacky.
  • 9. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    You're repeating code. I know how to do that, I'm asking if there's away to avoid that.
    And the design isn't mine. Believe me, if it was things would be very different.
  • 10. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    WirajR wrote:
    I dont know what you are doing but this works
    String s = lst.get(0) instanceof String?(String)lst.get(0):((Integer)lst.get(0)).toString();
    That's totally useless though. Just call toString() on the elements and assign it. Integer.toString() will still work, even if it's static type is Object. String.toString() returns the string itself, so there's no need to differentiate there. Let polymorphism work for you.
    String s = lst.get(0).toString();
  • 11. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    hunter9000 wrote:
    WirajR wrote:
    I dont know what you are doing but this works
    String s = lst.get(0) instanceof String?(String)lst.get(0):((Integer)lst.get(0)).toString();
    That's totally useless though. Just call toString() on the elements and assign it. Integer.toString() will still work, even if it's static type is Object. String.toString() returns the string itself, so there's no need to differentiate there. Let polymorphism work for you.
    String s = lst.get(0).toString();
    But WirajR conjured up a crap example, and toString is not a general solution.
  • 12. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    black_blizzard wrote:
    To paulcw: Sorry, I don't think I get what you're saying. The thing is this:
    * There is a class called X.
    * There are three subclasses of X called A, B and C.
    * A and B have a method called getSomething that returns a double, but C doesn't have that method.
    * list is an ArrayList<X>.
    * I know for a fact that list.get(0) is either of class A or B.
    In that case, there's no need to do any casting at all. You ought to read up on polymorphism and static vs dynamic typing. If you do this:
    something = list.get(0).getSomething();
    Then the dynamic type (the type that the object actually is (A or B) as opposed to the type that you're referencing it with (Object) ) determines which implementation of the method gets called. If it's actually an A, then A's version of getSomething gets called. If it's a B, then B's version is called.
  • 13. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    jToohey wrote:
    But WirajR conjured up a crap example, and toString is not a general solution.
    I know, it wasn't meant as a general solution to the OP's problem, just a response to his post.
  • 14. Re: using casting combined with the ternary operator
    807603 Newbie
    Currently Being Moderated
    hunter9000 wrote:
    black_blizzard wrote:
    To paulcw: Sorry, I don't think I get what you're saying. The thing is this:
    * There is a class called X.
    * There are three subclasses of X called A, B and C.
    * A and B have a method called getSomething that returns a double, but C doesn't have that method.
    * list is an ArrayList<X>.
    * I know for a fact that list.get(0) is either of class A or B.
    In that case, there's no need to do any casting at all. You ought to read up on polymorphism and static vs dynamic typing. If you do this:
    something = list.get(0).getSomething();
    Then the dynamic type (the type that the object actually is (A or B) as opposed to the type that you're referencing it with (Object) ) determines which implementation of the method gets called. If it's actually an A, then A's version of getSomething gets called. If it's a B, then B's version is called.
    If all you're doing is assigning something, then you don't need the cast. X is the supertype of A and B, and you know that the object must be an A or a B, so you can assign it to X. No problem.

    If you're going to invoke getSomething, then you'll have to cast it, because Java won't know whether the object is an A or a B, or a C. But in this case I'd strongly advise changing your design or at least the type hierarchy. For example you could define an interface that requires getSomething, declare A and B as implementing that interface, and then cast the the item from the list to be that interface. This could be a hack though.
1 2 3 Previous Next