• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

I can't quite understand an aspect of numeric promotion and casting

 
Greenhorn
Posts: 3
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello. I'm new here, and I've recently started studying for the OCP 1Z0-829 by the Study Guide book, and while reading the sections about numeric promotion and casting, some doubts have arisen.

Firstly, what I did understand was:
1) "The compiler doesn't require casting when working with literal values that fit into the data type."
So, I understand why this code compile:



That is clear to me; bread is an int, and it fits on the long cake variable, so casting isn't needed, as the compiler does it automatically for what I understood (since it'd be impossible for underflow or overflow to occur in this case).

2) "By default, Java assumes you are defining an int value with a numeric literal."
So, the first line wouldn't compile because the compiler interprets the literal as an int, and the literal's value is out of range for an int. And the second line would compile, because adding an L to the literal makes the compiler interpret it as a long value. That is also clear to me.




3) The problem is when I try to combine these two statements. Like in the following piece of code, which I know it compiles, but I can't make out how, as both statements seem conflicting here:



As of the second statement, I understood that the compiler will interpret the literal 10 as an int. But as of the first statement, casting should only be optional when the literal value fit into the data type. Now, I know that 5 is in range for a short data type, but given that the compiler treats numeric literals as an int, how come it doesn't need to be cast to a short to fit properly in the carrot variable?
For example, if I do this instead, it does indeed requires casting:



Since in both examples we are dealing with ints when assigning them to the short variable carrot, how come one compiles and the other doesn't? What I am missing here?

Thank you for any help!
 
Saloon Keeper
Posts: 15727
368
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to CodeRanch!

Rule 1 happened.

The integer literal 10 can be assigned to a variable of type short, because the compiler can see that the value 10 is within range of a short. Casting isn't necessary.

The value of variable carrot can then be assigned to the variable milk, because a short always fits into an int.

In the last code snippet, you're trying to assign the value of a variable of type int to a variable of type short. This is not allowed without casting because int does not fit into short. It doesn't matter that the value is 10: you're not assigning an integer literal, you're assigning the value of another variable (which, as far as the compiler is concerned, could be ANY int value, and not just 10).

Rule 1 only applies if the value you're assigning is a literal.
 
Author
Posts: 310
12
Scala IntelliJ IDE Netbeans IDE Python Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
While we're on the topic "rule 1" as presented is incomplete. The convenient assignment of an "int that's small enough for the target type" applies to *compile-time constants", of which literals are merely one example.

Try the following:

 
Gabriel Bristot
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Simon Roberts wrote:While we're on the topic "rule 1" as presented is incomplete. The convenient assignment of an "int that's small enough for the target type" applies to *compile-time constants", of which literals are merely one example.

Try the following:



I see now! Does this happens because, since the value of onlyTen is constant, the compiler is sure of it's value (and that it won't change) during compilation?

And could you give me some more examples of compile-time constants? All I can think of now are boolean and string literals.
 
Stephan van Hulst
Saloon Keeper
Posts: 15727
368
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Gabriel Bristot wrote:Does this happens because, since the value of onlyTen is constant, the compiler is sure of it's value (and that it won't change) during compilation?


Correct.

And could you give me some more examples of compile-time constants? All I can think of now are boolean and string literals.


First, I'm not quite sure where the term "compile-time constant" comes from. It's widely used on CodeRanch, and I have also used the term on occasion, but the technical term is "constant expression".

Here is what the Java Language Specification says about constant expressions: https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.29

Normally the JLS is quite difficult to read, but in this particular case the paragraph I linked to should be easy to understand. Anyway, here's my short summary:


A constant expression is any expression that consists of primitive literals, string literals, "pure" operators* and final variables that were themselves initialized with a constant expression.

* A pure operator is an operator that doesn't have any side-effects. The increment, decrement, and (compound) assignment operators all have side-effects (namely, changing the value of a variable).


So, here are a few examples of constant expressions:

As you can see, all of these expressions consist only of literals, other constant variables, and pure operators.

Because each expression is a constant expression, we can do the following:

  • Assign an expression of type int to a variable of type short, without casting.
  • Assign an expression of type int to a variable of type byte, without casting.
  • Compare a constant variable of type string to a string literal using the == operator. The result is true because both expressions refer to the same string object.
  •  
    Gabriel Bristot
    Greenhorn
    Posts: 3
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I finally understood it. Thank you Stephan and Simon for the crystal clear explanations
     
    Marshal
    Posts: 79952
    396
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Gabriel Bristot wrote:I finally understood it. . . .

    Well done
     
    Ranch Hand
    Posts: 39
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    If a line of code has an explicit cast, then does the cast happen before or after the arithmetic?

    For example (I know this doesn't compile, but trying to understand why...)





    I believe the cast happens first? Using the example above, fruit is casted to an int, however, we are then trying to add a float to an int, which the compiler doesn't like...? Or is it that float is bigger than a long when dealing with promotion?
     
    Saloon Keeper
    Posts: 10928
    87
    Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    In your case the cast only applies to 'fruit' and then the addition takes place. If you want to return 'long' use this:

    Also, you should (almost) never use 'float', use double instead as it is almost always more efficient. 'float' is mainly used when trying to interface with legacy code that requires it.
     
    Tim Bant
    Ranch Hand
    Posts: 39
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thanks Carey, trying to study for the exam so saw this example and couldn't quite work it out
     
    Campbell Ritchie
    Marshal
    Posts: 79952
    396
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Another way of putting it is that casts (I don't like that word) have the same precedence as ++x, higher than * / % + (addition) and - (subtraction).
     
    Master Rancher
    Posts: 5060
    81
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Stephan van Hulst wrote:First, I'm not quite sure where the term "compile-time constant" comes from. It's widely used on CodeRanch, and I have also used the term on occasion, but the technical term is "constant expression".


    It used to be in the JLS, up through Java SE 7.  [https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28]JLS SE 7 15.28 Constant Expressions[/url] began:

    A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:


    The italics and section title indicate that the official term was always constant expression, but the modifier "compile-time" was encouraged from the beginning.  Subsequently in Java SE 8 this was changed to omit "compile-time" from that sentence, and the section number later changed from 15.28 to 15.29.  But they can't force us old fogeys to forget what it used to say.

    Campbell Ritchie wrote:Another way of putting it is that casts (I don't like that word) have the same precedence as ++x, higher than * / % + (addition) and - (subtraction).


    Hmmm, what term would you prefer?  "Cast" seems well-supported by the JLS.  As for precedence, I see that this Java Precedence table lists other unary operations as higher in precedence than casts, rather than equal.  I think that's incorrect -- as you say, they are equal in precedence -- but to be fair, I can't come up with a good code example where this distinction would actually make a difference.  And the JLS doesn't seem to directly say either way.
     
    Campbell Ritchie
    Marshal
    Posts: 79952
    396
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Mike Simmons wrote:. . . Hmmm, what term would you prefer? . . .

    Don't know. The problem I have with that word is that it is used both of primitives, where it can change the value of the expression, and reference types, where it cannot change its type. Little example, which happens to use unboxing conversion too:-

    $ jshell
    |  Welcome to JShell -- Version 22.0.1
    |  For an introduction type: /help intro

    jshell> Double d = 1.234e56;
    d ==> 1.234E56

    jshell> (int)d
    |  Error:
    |  incompatible types: java.lang.Double cannot be converted to int
    |  (int)d
    |       ^

    jshell> double d = 1.234e56;
    d ==> 1.234E56

    jshell> (int)d
    $3 ==> 2147483647

    Yes, I know it is useless code, but when you write double the cast proceeds normally and when you write Double it won't even compile. The sort of thing we old hands are familiar with, but I think it can confuse beginners.
     
    Campbell Ritchie
    Marshal
    Posts: 79952
    396
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Mike Simmons wrote:. . . ]this Java Precedence table lists other unary operations as higher in precedence than casts, rather than equal.  I think that's incorrect . . .

    Agre; this JLS section lists CastExpression as one kind of unary expression.

    but to be fair, I can't come up with a good code example where this distinction would actually make a difference. . . .

    Nor can I.
     
    MyExamCloud Software Support
    Posts: 753
    3
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Widening conversions occur when a number is converted to a type that has more bits, without losing any precision. For unsigned values, the extra space is filled with zeros, while for signed values, the sign is preserved in the most significant bit and the rest is set to the extended two's complement value.


    Narrowing conversions occur when a number is converted to a type that has fewer bits, resulting in a potential loss of precision. The most significant bits are discarded, leaving only the lowest part of the number.

    Read this article for more info.

     
    Campbell Ritchie
    Marshal
    Posts: 79952
    396
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Jhonson Fernando wrote:. . . Read this article for more info.

    You used a term I don't like in that article: “sign bit”. In S&M (=sign and magnitude, not some other meaning!) integers, there is a true sign bit; changing the leftmost bit converts 123 to −123 and vice versa But I have never seen S&M integers used, only unsigned and two's complement. In two's complement, the leftmost bit has a value, but unlike all the other bits, that value is negative. equivalent to adding −2147483648 (for an int). Changing the first bit in an int usually changes both sign and magnitude.

    jshell> {
      ...>     int i = 123456;
      ...>     System.out.printf("i = %d; i with first bit changed = %d%n", i, i ^ 0x8000_0000);
      ...> }
    i = 123456; i with first bit changed = -2147360192

    That leftmost bit determines the sign, but it does more than that so I don't think “sign bit” is an accurate name for it.
    Now, IEEE754 numbers work on a sort of S&M basis; if you change the first bit in 123.45e67, you do indeed get −123.45e67, so that leftmost bit can accurately be called a sign bit.
     
    Clowns were never meant to be THAT big! We must destroy it with this tiny ad:
    Gift giving made easy with the permaculture playing cards
    https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
    reply
      Bookmark Topic Watch Topic
    • New Topic