Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I was reading this question on SO which discusses some common undefined behavior in C++, and I wondered: does Java also have undefined behaviour?

If that is the case, then what are some common causes of undefined behaviour in Java?

If not, then which features of Java make it free from such behaviours and why haven't the latest versions of C and C++ been implemented with these properties?

share|improve this question
2  
Java is very rigidly defined. Check the Java Language Specification. –  user1249 Jun 22 '12 at 8:50
1  
add comment

4 Answers

up vote 11 down vote accepted

In Java, you can consider behavior of incorrectly synchronized program undefined.

Java 7 JLS uses word "undefined" once, in 17.4.8. Executions and Causality Requirements:

We use f|d to denote the function given by restricting the domain of f to d. For all x in d, f|d(x) = f(x), and for all x not in d, f|d(x) is undefined...

Java API documentation specifies some cases when results are undefined - for example, in (deprecated) constructor Date(int year, int month, int day):

The result is undefined if a given argument is out of bounds...

Javadocs for ExecutorService.invokeAll(Collection) state:

The results of this method are undefined if the given collection is modified while this operation is in progress...

Less formal kind of "undefined" behavior can be found for example in ConcurrentModificationException, where API docs use term "best effort":

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness...


Appendix

One of the question comments refers to an article by Eric Lippert which provides helpful introduction into topic matters: Implementation-defined behaviour.

I recommend this article for the language-agnostic reasoning, although it is worth keeping in mind that author targets C#, not Java.

Traditionally we say that a programming language idiom has undefined behaviour if use of that idiom can have any effect whatsoever; it can work the way you expect it to or it can erase your hard disk or crash your machine. Moreover, the compiler author is under no obligation to warn you about the undefined behaviour. (And in fact, there are some languages in which programs that use "undefined behaviour" idioms are permitted by the language specification to crash the compiler!)...

By contrast, an idiom that has implementation-defined behaviour is behaviour where the compiler author has several choices about how to implement the feature, and must choose one. As the name implies, implementation-defined behaviour is at least defined. For example, C# permits an implementation to throw an exception or produce a value when an integer division overflows, but the implementation must pick one. It cannot erase your hard disk...

What are some of the factors that lead a language design committee to leave certain language idioms as undefined or implementation-defined behaviours?

The first major factor is: are there two existing implementations of the language in the marketplace that disagree on the behaviour of a particular program? ...

The next major factor is: does the feature naturally present many different possibilities for implementation, some of which are clearly better than others? ...

A third factor is: is the feature so complex that a detailed breakdown of its exact behaviour would be difficult or expensive to specify? ...

A fourth factor is: does the feature impose a high burden on the compiler to analyze? ...

A fifth factor is: does the feature impose a high burden on the runtime environment? ...

A sixth factor is: does making the behaviour defined preclude some major optimization? ...

Those are just a few factors that come to mind; there are of course many, many other factors that language design committees debate before making a feature "implementation defined" or "undefined".

Above is only a very brief coverage; full article contains explanations and examples for the points mentioned in this excerpt; it is much worth reading. For example, details given for the "sixth factor" can give one an insight into motivation for many statements in Java Memory Model (JSR 133), helping to understand why some optimizations are allowed, leading to undefined behavior while others are prohibited, leading to limitations like happen-before and causality requirements.

None of the article materials is particularly new to me but I'll be damned if I ever seen it presented in such an elegant, consise and understandable way. Amazing.

share|improve this answer
    
I'll add that the JMM != underlying hardware and the end result of an executing program with regards to concurrency can vary from say an WinIntel vs a Solaris –  Martijn Verburg Jun 22 '12 at 9:33
    
@MartijnVerburg that's a pretty good point. Only reason why I hesitate to tag it as "undefined" is that memory model poses constraints like happen-before and causality on execution of correctly synced program –  gnat Jun 22 '12 at 9:41
    
True, the spec defines how it should behave under the JMM, however, Intel et al don't always agree ;-) –  Martijn Verburg Jun 22 '12 at 9:49
    
@MartijnVerburg I think the main point of JMM is to prevent over-optimizing leaks from "disagreeing" processor makers. As far as I understand Java before 5.0 had this kind of headache with DEC Alpha, when speculative writes done under the hood could leak into program like "out of thin air" - hence, causality requirement went into JSR 133 (JMM) –  gnat Jun 22 '12 at 9:53
4  
@MartinVerburg - it is a JVM implementer's job to make sure that the JVM behaves according to the JLS/JMM spec on any supported hardware platform. If different hardware behaves differently, it is the JVM implementer's job to deal with it ... and make it work. –  Stephen C Jun 22 '12 at 13:11
show 1 more comment

Off the top of my head, I don't think there is any undefined behaviour in Java, at least not in the same sense as in C++.

The reason for this is that there is a different philosophy behind Java than behind C++. A core design goal of Java was to allow programs to run unchanged across platforms, so is specification defines everything very explicitly.

In contrast, a core design goal of C and C++ is efficiency: there should not be any features (including platform independance) that cost performance even if you don't need them. To this end, the specification deliberately does not define some behaviours because defining them would cause extra work on some platforms and thus reduce performance even for people who write programs specifically for one platform and are aware of all its idiosyncracies.

There's even an example where Java was forced to retroactively introduce a limited form of undefined behaviour for exactly that reason: the strictfp keyword was introduced in Java 1.2 to allow floating point calculations to deviate from following exactly the IEEE 754 standard as the spec had previously demanded, because doing so required extra work and made all floating-point calculations slower on some common CPUs, while actually producing worse results in some cases.

share|improve this answer
    
I think it's important to note the other main goal of Java: security and isolation. I think this, too, is a reason for the lack of 'undefined' behaviour (as in C++). –  K.Steff Jun 22 '12 at 10:21
add comment

Java tries quite hard to exterminate undefined behaviour, precisely because of the lessons of earlier languages. For instance, class-level variables are automatically initialized; local variables are not auto-initialized for performance reasons, but there is sophisticated data-flow analysis to prevent anyone from writing a program that would be able to detect this. References are not pointers, so invalid references cannot exist, and dereferencing null causes a specific exception.

Of course there remain some behaviours that are not fully specified, and you can write unreliable programs if you assume that they are. For instance, if you iterate over a normal (non-sorted) Set, the language guarantees that you will see each element exactly once, but not in which order you will see them. The order might be the same on successive runs, or it might change; or it might stay the same as long as no other allocations occur, or as long as you don't update your JDK, etc. It is near-impossible to get rid of all such effects; for instance, you would have to explicitly order or randomize all Collections operations, and that is simply not worth the small additional un-undefined-ness.

share|improve this answer
add comment

You have to understand the "Undefined Behavior" and its origin.

Undefined Behavior means a behavior which is not defined by the standards. C/C++ have too many different compiler implementations and additional features. These additional features tied the code to the compiler. This was because there was no centralized language development. So some of the advanced features from some of the compilers became "undefined behaviors".

Whereas in Java the language specification is controlled by Sun-Oracle and there is nobody else trying to make specifications and thus no undefined behaviors.

Edited Specifically answering the Question

  1. Java is free from undefined behaviors because standards were created before compilers
  2. Modern C/C++ compilers have more/less standardized the implementations, but the features implemented before the standardization still remain tagged as "undefined behavior" because ISO kept mum on these aspects.
share|improve this answer
1  
You may be right that there is no UB in Java, but even when one entity control everything, there may be reasons to have UB, so the reason you give doesn't lead to the conclusion. –  AProgrammer Jun 22 '12 at 14:09
1  
Besides, both C and C++ are standardized by ISO. While there may be multiple compilers, there's just one standard at a time. –  MSalters Jun 22 '12 at 14:48
1  
@SarvexJatasra, I don't agree that it is the only source of UB. For instance, one UB is dereferencing dangling pointer and there are good reasons to leave it an UB in any language which hasn't a GC, even if you start your spec now. And those reasons have nothing to do with existing practice or existing compilers. –  AProgrammer Jun 22 '12 at 16:07
1  
@SarvexJatasra, and if I take the overflow of signed intergers as exemple, is this also a runtime bug? –  AProgrammer Jun 22 '12 at 18:23
1  
@SarvexJatasra, signed overflow is UB because the standard says explicitly so (it is even the example given with the definition of UB). Dereferencing an invalid pointer is also an UB for the same reason, the standard says so. –  AProgrammer Jun 22 '12 at 18:37
show 8 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.