ternary operator error

Discussion in 'Java' started by Jacob, Jun 30, 2003.

  1. Jacob

    Jacob Guest

    The following produce a compilation error:

    int a = 0;
    String s = "b" + (a == 0 ? "c" : a);

    I can sort of understand why, but on the
    other hand it is pretty apparent what I
    try to acheive.

    Why is the compiler so strict?

    Thanks!
     
    Jacob, Jun 30, 2003
    #1
    1. Advertising

  2. Jacob

    Jon Skeet Guest

    Jacob <> wrote:
    > The following produce a compilation error:
    >
    > int a = 0;
    > String s = "b" + (a == 0 ? "c" : a);
    >
    > I can sort of understand why, but on the
    > other hand it is pretty apparent what I
    > try to acheive.
    >
    > Why is the compiler so strict?


    You're suggesting that the type of an expression should be different
    depending on runtime evaluation - that sounds like a pretty strange bit
    of specification. It makes everything simpler if the type of an
    expression will always be the same, and it *very* rarely impacts on
    real life code, IME.

    --
    Jon Skeet - <>
    http://www.pobox.com/~skeet/
    If replying to the group, please do not mail me too
     
    Jon Skeet, Jun 30, 2003
    #2
    1. Advertising

  3. On Mon, 30 Jun 2003 10:57:32 +0200, Jacob wrote:
    > The following produce a compilation error:
    >
    > int a = 0;
    > String s = "b" + (a == 0 ? "c" : a);
    >
    > I can sort of understand why, but on the
    > other hand it is pretty apparent what I
    > try to acheive.
    >
    > Why is the compiler so strict?


    Every expression must have a type that is unambiguous and can be
    evaluated at compile time. That means that both branches of the
    conditional operator must evaluate to the same type, so that the
    expression itself can be assigned a type that can be used when the
    surrounding expression is evaluated.

    The compiler sees something like this:

    String <-- String + E

    where E is

    (boolean ? String : integer)

    So what is the type of E?

    An integer and a String are not the same type, and what you
    *subsequently* do with the resulting value (i.e. in the enclosing
    expression) does not change that fact. A type for E cannot be assigned
    at compile time.

    Consider that the compiler might need to emit different code depending
    on the whether the conditional expression evaluates to an integer or a
    String.

    You can help it though:

    String s = "b" + (a == 0 ? "c" : Integer.toString(a));

    /gordon

    --
    [ do not send me private copies of your followups ]
    g o r d o n . b e a t o n @ e r i c s s o n . c o m
     
    Gordon Beaton, Jun 30, 2003
    #3
  4. Jacob

    Tomy Guest

    Jacob <> wrote:
    > The following produce a compilation error:
    >
    > int a = 0;
    > String s = "b" + (a == 0 ? "c" : a);
    >
    > I can sort of understand why, but on the
    > other hand it is pretty apparent what I
    > try to acheive.
    >
    > Why is the compiler so strict?
    >
    > Thanks!



    Because java specification is strict in that way.
    Type of the data must be known which is not
    the case here since the result of your tenary
    (in the way you want to use it) cannot be known
    at compile time since it depends on value of a.

    It is the same reason which prohibits you from
    writing a method which can return either int
    or String.

    This might be solved in 1.5 with autoboxing-unboxing
    feature. I'm just guessing here....

    ---
    Tomy.
    -----------------------
     
    Tomy, Jun 30, 2003
    #4
  5. Jacob

    Tomy Guest

    Marco Schmidt <> wrote:
    > Tomy:
    >
    > [...]
    >
    >> This might be solved in 1.5 with autoboxing-unboxing
    >> feature. I'm just guessing here....

    >
    > AFAIK that feature will only lead to easier handling of primitive
    > types and their respective wrapper classes, e.g. int and Integer.
    >
    > Transparent conversion between int and String is a different thing.



    Not really I think in this example....
    "b" + (a == 0 ? "c" : a)
    "c" is String
    a is int, gets implicitely boxed in Integer....
    Tenary expression has type of Object....
    "b" + Object is legal so everything OK....

    I'm not sure things will work this way, but they might
    since ternary expression now has "a type that is unambiguous and can be
    evaluated at compile time" Object type.... (Thank you Gordon on this phrase,
    my english
    is not so good ).....

    Tomy.
    -------------------------------------
     
    Tomy, Jun 30, 2003
    #5
  6. Tomy <> scribbled the following:
    > begin 666 smile.gif
    > M1TE&.#EA#P`/`)$!`````+^_O___`````"'Y! $```$`+ `````/``\```(N
    > MC V9QY$"X6(@6GGJO0!)+3RA$XDA:&Y6JGXMIX$K%G,8^2EE]G:4?&ID%+Y#
    > #`0`[
    > `
    > end


    > begin 666 frown.gif
    > M1TE&.#EA#P`/`)$``````+V]O8RM_[V]O2'Y! $```,`+ `````/``\```(O
    > MG V9QY,"X6) QBK P?A*E$5BI76/9*:7*K:K"Y^H,CK6^-GPM>U9(T,U-@H-
    > $HP``.P``
    > `
    > end


    Could you please stop with this MIME stuff, thanks?

    --
    /-- Joona Palaste () ---------------------------\
    | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    | http://www.helsinki.fi/~palaste W++ B OP+ |
    \----------------------------------------- Finland rules! ------------/
    "Hasta la Vista, Abie!"
    - Bart Simpson
     
    Joona I Palaste, Jun 30, 2003
    #6
  7. Jacob

    pete kirkham Guest

    Jon A. Cruz wrote:

    > Gordon Beaton wrote:
    >
    >>
    >> You can help it though:
    >>
    >> String s = "b" + (a == 0 ? "c" : Integer.toString(a));

    >
    >
    > A better way is
    > String s = "b" + (a == 0 ? "c" : String.valueOf(a));
    >


    the source code for String.valueOf is:

    public static String valueOf(int i) {
    return Integer.toString(i, 10);
    }

    so you only end up making an extra method call, so for code where you've
    decided that a is an integer the integer version is more efficient.

    In this particular situation the compiler doesn't have to know the type
    as the + operator is expanded to calls to StringBuffer, so:

    String s = "s" + ( test ? X : Y);

    gets expanded to something like:
    StringBuffer _temp = new StringBuffer();

    _temp.append("s");

    String _temp2;

    if (test) goto :1
    _temp2 = Y;
    goto :2
    :1
    _temp2 = X;
    :2

    _temp.append(_temp2);

    String s = _temp.toString();

    (_temp<x> being either a virtual local variable or a stack value)

    but it /could/ be expanded to:
    StringBuffer _temp = new StringBuffer();

    _temp.append("s");

    if (test) goto :1
    _temp.append(Y);
    goto :2
    :1
    _temp.append(X);
    :2

    String s = _temp.toString();

    with the types of X and Y only being used to determine which append call
    to make, which loosens the constraint that X and Y be the same type.

    this wouldn't break anything, and the + operator for strings is
    different from other operators anyway.

    (though since StringBuffer.append(int) calls String.valueOf(int) which
    calls Integer.toString(int, int) it saves one indirection to use
    StringBuffer.append(Integer.toString(int)) rather than
    StringBuffer.append(int))


    Pete
     
    pete kirkham, Jun 30, 2003
    #7
  8. Jacob

    Dale King Guest

    "Jon A. Cruz" <> wrote in message
    news:...
    > Gordon Beaton wrote:
    > >
    > > You can help it though:
    > >
    > > String s = "b" + (a == 0 ? "c" : Integer.toString(a));

    >
    > A better way is
    > String s = "b" + (a == 0 ? "c" : String.valueOf(a));



    The best way is:

    String s;

    if( a == 0 )
    {
    s = "bc";
    }
    else
    {
    s = "b" + a;
    }
    --
    Dale King
     
    Dale King, Jun 30, 2003
    #8
  9. "Gordon Beaton" <> wrote in message news:bdovnq$b7p$...
    >
    > The compiler sees something like this:
    >
    > String <-- String + E
    >
    > where E is
    >
    > (boolean ? String : integer)
    >
    > So what is the type of E?


    In a different language, the answer might be "String or int" which
    actually doesn't seem like all that unreasonable of an answer.


    Marshall
     
    Marshall Spight, Jul 1, 2003
    #9
  10. Jacob

    Jon A. Cruz Guest

    pete kirkham wrote:
    > the source code for String.valueOf is:


    No. Not "the" source. "A source"

    Other JVM's (including many of IBM's, which are often top performers)
    use the fact that the String class can access the internals of the
    String class (while the Integer class can not) to optimize if needed.

    Remember, the language spec only said it behaves "as if"
    Integer.toString() is called, not that it must call it.

    >
    > so you only end up making an extra method call,


    Myabe, or maybe not. A lot depends on the specific VM's implementation.


    > so for code where you've
    > decided that a is an integer the integer version is more efficient.
    >


    Ahh.. But also...

    If you happen to change the declaration of the variable ('a' in this
    case) to some other type (long for example), then Integer.toString() is
    broken. However, String.valueOf() will work for boolean, for char, for
    char[], for double, for float, for int, for long and for Object.

    That also makes the code more OO friendly.




    > (though since StringBuffer.append(int) calls String.valueOf(int) which
    > calls Integer.toString(int, int) it saves one indirection to use


    Or String.valueOf() uses an optimized version that deals with the
    internals of the String class directly and gets much better performance.
    Again, that detail all depends on the VM being used.
     
    Jon A. Cruz, Jul 1, 2003
    #10
  11. Tomy:

    >Not really I think in this example....
    >"b" + (a == 0 ? "c" : a)
    >"c" is String
    >a is int, gets implicitely boxed in Integer....
    >Tenary expression has type of Object....
    >"b" + Object is legal so everything OK....


    OK, in this context the autoboxing feature could work. However, I
    don't really know how this feature is implemented in the compiler. If
    the fact that a variable X is an int produces an error, will the
    compiler start again and treat X as an Integer?

    Regards,
    Marco
    --
    Please reply in the newsgroup, not by email!
    Java programming tips: http://jiu.sourceforge.net/javatips.html
    Other Java pages: http://www.geocities.com/marcoschmidt.geo/java.html
     
    Marco Schmidt, Jul 1, 2003
    #11
  12. Jacob

    pete kirkham Guest

    Jon A. Cruz wrote:
    > pete kirkham wrote:
    >
    >> the source code for String.valueOf is:

    >
    >
    > No. Not "the" source. "A source"


    Even so, but you were saying '~blah~ is better than ~wibble~' not saying
    '~blah~'s better because some VM with undefined internals may implement
    it in a more optimal manner than the reference implementation of ~wibble~'.

    > Other JVM's (including many of IBM's, which are often top performers)
    > use the fact that the String class can access the internals of the
    > String class (while the Integer class can not) to optimize if needed.


    I've taken a quick look at IBM's java site and can't find anything like
    that. Where did you get this information? Why on earth don't they use
    the same optimized code for both: there's such thing as 'private' in
    machine code? Why do they change the calling pattern so as to break
    mixed-use with other libraries?

    > Remember, the language spec only said it behaves "as if"
    > Integer.toString() is called, not that it must call it.


    Hence the quote from the reference implementation, not the API

    > > so for code where you've
    >> decided that a is an integer the integer version is more efficient.

    > Ahh.. But also...
    >
    > If you happen to change the declaration of the variable ('a' in this
    > case) to some other type ..


    Yes, if you haven't decided than a is an integer, then the other
    approach is more flexible. Such changes should idealy be done by a tool
    not the programmer.

    > That also makes the code more OO friendly.


    Personally, I think what would make the code more OO friendly would be
    to turn type checking off where the result is being passed to a form
    which doesn't care what the type is, as in the StringBuffer calls I
    posted. The Java language tries to be both OO and strongly typed, and so
    falls into the mud between.


    Pete
     
    pete kirkham, Jul 1, 2003
    #12
  13. Jacob

    pete kirkham Guest

    Jon A. Cruz wrote:
    > Ok.
    >
    > It is better because:
    >
    > 1) It is clearer as to the intent. Most experts say to write for clarity
    > first.


    I'd say that writing "s" + (a==0 ? "foo" : a) is clearer to the intent.

    > 2) It is an 'optimization' that usually doesn't make any noticeable
    > difference, and is very commonly premature.


    So use a tool to optimize: a lot of Java would greatly benefit from a
    preprocessor/macro expander. If you put the optimization into a tool,
    that expands a generic form, then you save time optimizing by hand.

    > 3) It helps reduce bugs.
    > 4) It makes the code hold up even if the type of the variable changes.
    > 5) It allows the code to be copy-n-pasted and reused without having to
    > be changed. Reduces rogue tile occurances.


    They are identical in this respect.

    > 6) On the fastest VM's, doing it that way can be faster. (although you
    > should note point 2)


    Is the IBM VM faster when running on OS X? I couldn't find any benchmarks ;)

    > ...
    >
    > There, is that better?


    I think you missed the point, and I maybe would have been better to post
    without the aside on the extra method indirections; the main gain I was
    driving at was to allow a tool to expand the generic form where deciding
    the type can be left until the expression is used (given that changing
    the language seems a bit optimistic). OK, so if you're targeting one
    particular vendor's JVM, then a small gain can be made by customizing
    the expansion in a different way than what is better for the standard one.

    > You seem to misunderstand. It's all in Java-land, not native land. Also
    > it does nothing to break use, and does not introduce any other problems
    > to do so.


    Yes, not having had any reason to inspect the 1.1 implementation of the
    IBM libraries, I misunderstood your use of internal, and assumed it was
    internal to the JVM implementation not it's libraries.

    > The reference implementation is just to be consulted on points on which
    > the language spec does not cover. Since it does in fact cover this
    > point, the reference implementation does not trump it.


    Neither the language spec nor the API spec cover whether it's any
    'better'. The reference implementation does indicate that it's
    (marginally) better to expand one way rather than the other in terms of
    calls, so I chose to do it that way, which AFAI can tell is better on
    the JVMs I get to use.

    > I disagree. If you need to change a variable declaration, it should not
    > require a tool to assist you to do so. If that is the case, it sounds
    > like your code is probably too fragile and unmaintainable.


    In the absence of a customisable compiler, writing a tool that expands

    <String> + (<bool> ? <type A> : <type B>)

    into the StringBuffer calls I suggested would make it less fragile, not
    more, for reasons you've already pointed to.

    Such a tool should also be able to pick up on forms such as

    String s = "foo";

    if (a != 3) {
    s += a;
    }

    s += "bar";

    Which could use only the one StringBuffer instead of the two that javac
    does (the one in the OS X JDK, maybe IBM's compiler already has this
    covered, I don't know, they don't do OS X developer kits).


    Pete
     
    pete kirkham, Jul 2, 2003
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roger Leigh

    ternary operator and ostreams

    Roger Leigh, Jan 16, 2004, in forum: C++
    Replies:
    6
    Views:
    670
    Roger Leigh
    Jan 19, 2004
  2. marco_segurini
    Replies:
    4
    Views:
    814
    Dan Cernat
    Sep 21, 2004
  3. Paul E Johnson

    union, ternary operator, and C. What a mess!

    Paul E Johnson, Oct 17, 2003, in forum: C Programming
    Replies:
    3
    Views:
    472
    Ed Morton
    Oct 17, 2003
  4. Paul E Johnson
    Replies:
    2
    Views:
    585
    Christian Bau
    Oct 17, 2003
  5. glongword

    Need for the ternary operator

    glongword, May 16, 2004, in forum: C Programming
    Replies:
    6
    Views:
    536
    Dan Pop
    May 17, 2004
Loading...

Share This Page