154

The limit of int is from -2147483648 to 2147483647.

If I input

int i = 2147483648;

then Eclipse will prompt a red underline under "2147483648".

But if I do this:

int i = 1024 * 1024 * 1024 * 1024;

it will compile fine.

public class Test {
    public static void main(String[] args) {        

        int i = 2147483648;                   // error
        int j = 1024 * 1024 * 1024 * 1024;    // no error

    }
}

Maybe it's a basic question in Java, but I have no idea why the second variant produces no error.

devnull
  • 118,548
  • 33
  • 236
  • 227
WUJ
  • 1,663
  • 3
  • 15
  • 21
  • 10
    Even if the compiler would normally "collapse" the computation into a single value as an optimization, it will not do so if the result would be an overflow, since no optimization should change the behavior of the program. – Hot Licks Jul 10 '14 at 12:24
  • 1
    And it *can't* interpret `2147483648` : this literal makes no sense. – Denys Séguret Jul 10 '14 at 12:25
  • 1
    And Java does not report integer overflows -- the operation "fails" silently. – Hot Licks Jul 10 '14 at 12:28
  • Does C++ or any other language report integer overflows? Just curious. – bbalchev Jul 10 '14 at 12:31
  • 1
    @bbalchev: C# will report overflows in a `checked` block: http://msdn.microsoft.com/en-us/library/74b4xzyw.aspx – Jacob Krall Jul 10 '14 at 16:01
  • 1
    @bbalchev: Any compliant Ada compiler will report overflows. (That means you have to set the right extra flags using Gnat). Ada has special rules : the expression should evaluate as though it is an arbitrary width integer ("Universal Integer" in Ada LRM terms) but assigning the result to a too small variable will raise a Constraint Error exception. –  Jul 10 '14 at 16:05
  • @bbalchev The old IBM PL/S compiler would report overflows for signed integers but not unsigned. – Hot Licks Jul 10 '14 at 16:20
  • 5
    @JacobKrall: C# will report this as a defect regardless of whether checked-ness is turned on; all computations that consist of only constant expressions are automatically checked unless inside an unchecked region. – Eric Lippert Jul 10 '14 at 16:20
  • @EricLippert: yep! I think bbalchev was asking about integer overflows in general, though. – Jacob Krall Jul 10 '14 at 16:26
  • 54
    I discourage you from asking "why not" questions on StackOverflow; they are difficult to answer. A "why not" question presupposes that the world obviously ought to be a way that it is not, and that there needs to be a good reason for it to be that way. This assumption is almost never valid. A more precise question would be something like "what section of the specification describes how constant integer arithmetic is computed?" or "how are integer overflows handled in Java?" – Eric Lippert Jul 10 '14 at 20:30
  • @bbalchev C and C++ implementations can "report" overflow any way they want, as the behaviour is not defined. So the implementation may cause the program to core dump. Some compilers have a switch to do that. The default is usually to do whatever the CPU does, which is usually modulo computations. – curiousguy Jul 13 '14 at 03:47

5 Answers5

232

There's nothing wrong with that statement; you're just multiplying 4 numbers and assigning it to an int, there just happens to be an overflow. This is different than assigning a single literal, which would be bounds-checked at compile-time.

It is the out-of-bounds literal that causes the error, not the assignment:

System.out.println(2147483648);        // error
System.out.println(2147483647 + 1);    // no error

By contrast a long literal would compile fine:

System.out.println(2147483648L);       // no error

Note that, in fact, the result is still computed at compile-time because 1024 * 1024 * 1024 * 1024 is a constant expression:

int i = 1024 * 1024 * 1024 * 1024;

becomes:

   0: iconst_0      
   1: istore_1      

Notice that the result (0) is simply loaded and stored, and no multiplication takes place.


From JLS §3.10.1 (thanks to @ChrisK for bringing it up in the comments):

It is a compile-time error if a decimal literal of type int is larger than 2147483648 (231), or if the decimal literal 2147483648 appears anywhere other than as the operand of the unary minus operator (§15.15.4).

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • 12
    And for the multiplication the JLS says, If an integer multiplication overflows, then the result is the low-order bits of the mathematical product as represented in some sufficiently large two's-complement format. As a result, if overflow occurs, then the sign of the result may not be the same as the sign of the mathematical product of the two operand values. – Chris K Jul 10 '14 at 12:30
  • 3
    Excellent answer. Some people seem to have the impression that overflow is some kind of error or failure, but it is not. – Wouter Lievens Jul 10 '14 at 14:59
  • I am curious if this is still an error with 64bit JVM. Does 64-bit JVM change this? I thought that the issue WUJ is describing is a limitation of 32bit computations. – iowatiger08 Jul 10 '14 at 19:09
  • I appended the link that answers my curiosity on this. – iowatiger08 Jul 10 '14 at 19:42
  • 3
    @iowatiger08 The language semantics are outlined by the JLS, which is independent of the JVM (so it shouldn't matter which JVM you use). – arshajii Jul 10 '14 at 20:17
  • 4
    @WouterLievens, overflow _is_ normally an "unusual" condition, if not an outright error condition. It is a result of finite-precision math, which most people are not intuitively expecting to happen when they do math. In some cases, like `-1 + 1`, it's harmless; but for `1024^4` it could blindside people with totally unexpected results, far from what they would expect to be seeing. I think there should be at least a warning or note to the user, and not silently ignore it. – Phil Perry Jul 11 '14 at 15:48
  • @WouterLievens: These people have probably used programming languages which check against under-/overflow (like Pascal). – Martin Schröder Jul 17 '14 at 11:53
  • 1
    @iowatiger08: The size of int is fixed; it does _not_ depend on the JVM. Java is _not_ C. – Martin Schröder Jul 17 '14 at 11:55
42

1024 * 1024 * 1024 * 1024 and 2147483648 do not have the same value in Java.

Actually, 2147483648 ISN'T EVEN A VALUE(although 2147483648L is) in Java. The compiler literally does not know what it is, or how to use it. So it whines.

1024 is a valid int in Java, and a valid int multiplied by another valid int, is always a valid int. Even if it's not the same value that you would intuitively expect because the calculation will overflow.

Example

Consider the following code sample:

public static void main(String[] args) {
    int a = 1024;
    int b = a * a * a * a;
}

Would you expect this to generate a compile error? It becomes a little more slippery now.
What if we put a loop with 3 iterations and multiplied in the loop?

The compiler is allowed to optimize, but it can't change the behaviour of the program while it's doing so.


Some info on how this case is actually handled:

In Java and many other languages, integers will consist of a fixed number of bits. Calculations that don't fit in the given number of bits will overflow; the calculation is basically performed modulus 2^32 in Java, after which the value is converted back into a signed integer.

Other languages or API's use a dynamic number of bits (BigInteger in Java), raise an exception or set the value to a magic value such as not-a-number.

Cruncher
  • 7,641
  • 1
  • 31
  • 65
  • 8
    For me, your statement, "`2147483648` ISN'T EVEN A VALUE(although `2147483648L` is)," **really** cemented the point that @arshajii was trying to make. – kdbanman Jul 11 '14 at 18:10
  • Ah, sorry, yes, that was me. I was missing the notion overflow / modular arithmetic in your answer. Note that you can roll back if you don't agree with my edit. – Maarten Bodewes Jul 14 '14 at 16:54
  • @owlstead Your edit is factually correct. My reason for not including it was that: regardless of how `1024 * 1024 * 1024 * 1024` is handled I really wanted to emphasise that it is not the same thing as writing `2147473648`. There are many ways(and you've listed a few) that a language could potentially deal with it. It's reasonably separated, and useful. So I'll leave it. Lots of information becomes increasingly necessary when you have a high ranked answer on a popular question. – Cruncher Jul 14 '14 at 16:59
15

I have no idea why the second variant produces no error.

The behaviour that you suggest -- that is, the production of diagnostic message when a computation produces a value that is larger than the largest value that can be stored in an integer -- is a feature. For you to use any feature, the feature must be thought of, considered to be a good idea, designed, specified, implemented, tested, documented and shipped to users.

For Java, one or more of the things on that list did not happen, and therefore you don't have the feature. I don't know which one; you'd have to ask a Java designer.

For C#, all of those things did happen -- about fourteen years ago now -- and so the corresponding program in C# has produced an error since C# 1.0.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 45
    This doesn't add anything helpful. While I don't mind taking stabs at Java, it didn't answer the OPs question at all. – Seiyria Jul 10 '14 at 20:08
  • 30
    @Seiyria: The original poster is asking a "why not?" question -- "why is the world not the way I think it should be?" is not a *precise technical question about actual code*, and this is therefore a bad question for StackOverflow. The fact that the correct answer to a vague and nontechnical question is vague and nontechnical should be unsurprising. I encourage the original poster to ask a better question, and avoid "why not?" questions. – Eric Lippert Jul 10 '14 at 20:22
  • 18
    @Seiyria: The accepted answer I note also does not answer this vague and non-technical question; the question is "why is this not an error?" and the accepted answer is "because it's legal". This is simply *restating the question*; answering "why is the sky not green?" with "because it's blue" doesn't answer the question. But since the question is a bad question, I don't at all blame the answerer; the answer is a perfectly reasonable answer to a poor question. – Eric Lippert Jul 10 '14 at 20:26
  • 13
    Mr. Eric, This is the question which I posted : " Why int i = 1024 * 1024 * 1024 * 1024; without error report in eclipse? ". and the answer of arshajii is exactly what I what (maybe more). Sometimes I can't express any questions in a very accurate way. I think that's why there are some people modify some posted questions more accurate in Stackoverflow. I think if I want get the answer "because it's legal", I won't post this question. I will try my best to post some "regular questions", but please understand someone just like me who is a student and not so professional. Thanks. – WUJ Jul 11 '14 at 12:35
  • @WUJ: As a developer, you should know that answers will be literal. "It's not an error" is the correct answer to your question. I answered the question "why is it not an error" below. If you just wanted a general rant about a Java feature or misfeature, that's not a question. – gnasher729 Jul 11 '14 at 16:38
  • 1
    Perhaps you could say "the ability to perform math on members of a wrapping algebraic ring is a feature which can be useful in those rare cases where such math is required; C# only enables that feature within an 'unchecked' arithmetic context, but Java enables it all the time". – supercat Jul 11 '14 at 17:06
  • 5
    @WUJ This answer IMHO provides additional insight and perspective. After reading all the answers I found this answer to provide just as much validity as the other answers provided. Also it raises the awareness that developers are not the only implementors of some software products. – SoftwareCarpenter Jul 12 '14 at 02:28
  • 4
    @Eric: While the ad-hominem attacks are clearly foolish, this answer is completely wrong. IF this code generated an error at runtime, then it would be useful to perform cost-benefit analysis of adding compiler logic to detect it at compile time (or editor logic to detect it pre-compile). But in Java, there is no error here. A feature to generate an error prior to run-time would not only require documentation, implementation, and testing, it would also be wrong according to the language specification. – Ben Voigt Jul 12 '14 at 16:24
  • Whether or not a language ought to permit integer overflow is debatable, but once that is specified as permitted, there's no room for designers of the tooling to decide that overflow detection is "considered to be a good idea". I'm not sure, perhaps your answer meant to discuss this in the context of the language, not the tooling. In that case, because the question concerns the tooling, it seems necessary to clarify that you aren't talking about the same thing the question is. – Ben Voigt Jul 12 '14 at 16:25
  • Of course, these are somewhat different between Java and C#, because for C# both language designers and tooling teams work for the same entity, and the Visual Studio team has significant influence over the language design. But this question is about Eclipse, a third-party Java IDE. I don't see how one would expect language design to be a function of the editor team in that case. – Ben Voigt Jul 12 '14 at 16:32
  • 2
    I'm not sure why @EricLippert is making the assumption that "I have no idea why" implies that the OP believes that is how it 'ought' to be. At most it implies that it contradicts his expectations of how it should perform based on what he knows, and thus he's asking for clarification. Nowhere in his question does he imply that this is a flaw in Java. Also why was C# even mentioned? I understand it's an example to show how other languages differ but it is just stated as a fact at the end so the intent in mentioning it isn't very clear. – Rahat Ahmed Jul 12 '14 at 19:58
  • 4
    @BenVoigt: The question as I understood it was not about Eclipse, but why the design of the Java language does not make this an error. Since clearly it is *possible* to make it an error in the language -- C# does -- then the reason why it is *not* an error in Java must be one of the things I listed did not happen. The Java team never thought of it, thought of it but didn't like it, liked it but didn't specify, implement, test or ship it. Which of those is true I don't know, but one of them must be. The question should be referred to one of the Java designers. – Eric Lippert Jul 13 '14 at 01:16
  • @RahatAhmed: You are correct that the OP *desires* the feature or *thinks its a good idea* can only be *inferred*; it is never *stated directly*. I will therefore update my answer to indicate that the feature is *suggested* by the OP, not *desired*. – Eric Lippert Jul 13 '14 at 01:18
  • 2
    @RahatAhmed: My intent in mentioning C# is to reinforce my point: that this design decision is not some sort of technical impossibility, but rather, like all design processes, one of making choices about the pros and cons of various features. Feature budgets are limited and different companies have different attitudes towards advancing the state of the art of programming language design. If the question were "what are good reasons for implementing this feature?" I certainly could answer that in more detail, but the question is effectively why the Java team did *not* do something; ask them! – Eric Lippert Jul 13 '14 at 01:23
  • 1
    @owlstead: Perhaps you should read my answer again. **One of** the things on my list did not happen. I don't know which it was; I wasn't in the Java design meeting at the time, so I don't when, if ever, the feature was thought of and rejected, and if it was, why it was rejected. I don't know if it made it as far as implementation or testing before it was rejected. As I've said several times now, a "why not?" question is a bad question because it cannot be answered without knowing details of the design process. – Eric Lippert Jul 14 '14 at 16:29
  • 4
    @owlstead: The notion that I am "bashing" Java is of course ridiculous. Pointing out that one language design team did implement a feature but another did not is simply stating relevant facts. You'll note that nowhere in my answer do I ever state that the Java team were *wrong* to fail to implement this feature. Rather, I have repeatedly gone out of my way to point out that *all design processes involve compromises and cost-benefit analyses*. If the Java team thought of this feature and rejected it, they likely did so for sensible reasons. What those reasons are, I don't know -- ask them. – Eric Lippert Jul 14 '14 at 16:32
  • You do not even explain which feature is missing, and why the literal creates a compile error and the calculation does not. This was clearly what was asked. That alone makes this "not an answer". And you know as well as I do that you cannot just add this feature to Java without breaking a lot of stuff. On top of that you create a statement that C# already has this feature for 14 years now, which has clearly no relevance whatsoever. Note that many scripting languages - including **bc** - don't overflow at all. Since 1991 or so. – Maarten Bodewes Jul 14 '14 at 17:06
  • 2
    "You cannot just add this feature to Java without breaking a lot of stuff"--isn't that exactly the point Eric is making? That features have costs that have to be justified before they can be implemented? I'm sure he would be the first one to tell you that there are plenty of features that he wished he could have added to C#, but couldn't for whatever reason. Surely no serious developer believes that the Java language designers need to justify themselves to the C# language designers; this whole tangent seems silly to me. – Cole Campbell Jul 14 '14 at 17:45
  • @owlstead: I assumed that the reader could deduce which feature the original poster was discussing: the production of an error. You'll note that I put the relevant quotation from the OP in a grey box at the top of my answer to make sure that was clear. Apparently it was insufficiently clear; I shall try in the future to be more clear. What was "clearly asked" was, again, the bit that I put in a grey box; I'm not sure how you've deduced that something else was "clearly asked". – Eric Lippert Jul 14 '14 at 18:41
  • 1
    @owlstead: Whether or not the feature could easily be added to Java now is not the question that was asked. Were you to ask "could the feature of giving an error or warning when an expression of integer type containing only constants can be known to overflow at compile time be added to Java today?" the answer would be "yes"; implementing such a warning would be pretty straightforward work. Of course there are no "cheap" features in any compiler, as I have frequently pointed out, but this one could be done without too much difficulty. – Eric Lippert Jul 14 '14 at 18:45
  • 1
    @owlstead: As I have already explained, the relevance of the fact that C# implemented this feature long ago is to indicate that the reason for *not* doing the feature is not because it is impossible or onerous; clearly it is neither. Therefore the reason must be because either the Java team never thought of it, or they thought of it and rejected it. I don't know which is the case; the "why not?" question can only be reasonably answered by a Java designer, which is what makes it a bad fit for SO. – Eric Lippert Jul 14 '14 at 18:46
  • 1
    @owlstead: Your point about there being other languages that do not have integer overflows at all is an excellent one, and supports my central point: that the desired feature is not impossible, but rather has either been not thought of, or thought of and rejected. A built-in BigInteger type in C# was thought of and rejected early on; in hindsight, I think it is unfortunate that it took a decade to get `BigInteger` in the framework when it is clearly useful, but other features took priority. Again, design is the process of trading off between many competing goals. – Eric Lippert Jul 14 '14 at 18:48
  • 1
    OK, changed my vote, as it is now clear what feature is meant at least. It can make a useful addition to the answers given. I agree that asking why something is not implemented is often a hard to answer question, for anybody but the designer anyway. On the other hand, explaining the difference between the constant and the calculated value is not that hard and was likely meant by the author (also according to the accept). But I hope you can also see why this answer is/was seen as flame bait, even if this was not your intention. – Maarten Bodewes Jul 14 '14 at 19:52
  • @EricLippert I think the problem is not so much that this is a "why not" question. But because it's a question about a decision that someone made. Surely, this could be worded as "Why does 1024*1024*1024*1024 compile". This is now a completely positive question. Anyway, I think the OP clearly wanted some intuition. Some reason why `1024*1024*1024*1024` and `2147483648` don't produce the same result. There are definitely good reasons to treat these differently, as many have suggested. Frankly I would rather this overflow than give a compile-time error. Why add exceptional cases to the JLS? – Cruncher Jul 14 '14 at 20:19
  • 4
    @owlstead: I understand why people read things as flame bait that were never intended as such; in fact, I wrote an essay on a closely related subject, which you can read here: http://blogs.msdn.com/b/ericlippert/archive/2008/02/20/how-to-not-get-a-question-answered.aspx. Here I criticized nothing, yet many people interpreted my statement of facts as criticism. That came first, from within them, and second, because an all-text one-way medium does not convey tone or intent; the mechanisms for correcting misunderstandings -- these comments -- are clunky, time-consuming and hard to use. – Eric Lippert Jul 14 '14 at 20:36
12

In addition to arshajii's answer I want to show one more thing:

It is not the assignment that causes the error but simply the use of the literal. When you try

long i = 2147483648;

you'll notice it also causes a compile-error since the right hand side still is an int-literal and out of range.

So operations with int-values (and that's including assignments) may overflow without a compile-error (and without a runtime-error as well), but the compiler just can't handle those too-large literals.

Ry-
  • 218,210
  • 55
  • 464
  • 476
piet.t
  • 11,718
  • 21
  • 43
  • 52
  • 1
    Right. Assigning an int to a long includes an implicit cast. But the value can never exist as the int in the first place to get casted :) – Cruncher Jul 11 '14 at 18:14
4

A: Because it is not an error.

Background: The multiplication 1024 * 1024 * 1024 * 1024 will lead to an overflow. An overflow is very often a bug. Different programming languages produce different behavior when overflows happen. For example, C and C++ call it "undefined behavior" for signed integers, and the behavior is defined unsigned integers (take the mathematical result, add UINT_MAX + 1 as long as the result is negative, subtract UINT_MAX + 1 as long as the result is greater than UINT_MAX).

In the case of Java, if the result of an operation with int values is not in the allowed range, conceptually Java adds or subtracts 2^32 until the result is in the allowed range. So the statement is completely legal and not in error. It just doesn't produce the result that you may have hoped for.

You can surely argue whether this behavior is helpful, and whether the compiler should give you a warning. I'd say personally that a warning would be very useful, but an error would be incorrect since it is legal Java.

Naveen Kumar Alone
  • 7,536
  • 5
  • 36
  • 57
gnasher729
  • 51,477
  • 5
  • 75
  • 98