50

Does / why does Java need to have void methods? Reference:

Any method declared void doesn't return a value.

As far as I can think, every use of void would be better served by returning a status flag, the object being invoked, or null.

This would make every call a statement that is assignable, and would facilitate builder patterns and method chaining. Methods that are only invoked for their effects would usually return a boolean or a generic Success type or throw an exception on failure.

2
  • So that we don't need a special syntax to write subroutines. We can use the same one functions use. Apr 27, 2017 at 9:44
  • Relevant
    – jpmc26
    Apr 28, 2017 at 6:28

9 Answers 9

156

Because there is a a difference between "This function can succeed or fail and is self-aware enough that it can tell the difference" and "There is no feedback about the effect of this function." Without void, you'd endlessly check success codes and believe that you are writing robust software, when in fact you are doing nothing of the sort.

23
  • 11
    But whether it succeeded or failed is something to express by throwing or not throwing an exception, not returning a flag. And returning void does not say anything about whether the method or function is self-aware enough to throw as appropriate. Apr 24, 2017 at 18:33
  • 12
    @VolkerSiegel: The context of the answer is the question. The OP suggested that in all cases where void is used the function should instead return a status flag indicating success of failure. In that context returning void DOES indeed say that the function literally has nothing to return. Forcing such a function to always return 0 to indicate success will give users of the function false confidence that they're error-checking when in reality the return value is always 0 regardless of success or failure.
    – slebetman
    Apr 24, 2017 at 21:10
  • 19
    @VolkerSiegel There's a large number of situations where exceptions are not the correct way to do things. In fact I'd say its rarer for an exception to be right than wrong- an exception means something horrible happened that needs to be accounted for. An expected failure case should never use an exception. Apr 24, 2017 at 21:54
  • 36
    @GabeSechan No, exceptions should be thrown if the method is unable to fulfill its contract. If the method requires a nonnull reference but it gets one, thats an expected failure and it should throw.
    – Andy
    Apr 25, 2017 at 1:58
  • 5
    There are many alternative syntaxes to fix that. The reason they chose this (awkward) solution is because C employs it. Apr 25, 2017 at 8:25
94
  1. Because C has a void type, and Java was designed to follow many of the conventions of the C language family.
  2. There are many functions that you don't want to have return a value. What are you going to do with "a generic Success type" anyway? In fact, return values to indicate success are even less important in Java than in C, because Java has exceptions to indicate failure and C doesn't.
6
  • 8
    > "What are you going to do with "a generic Success type" anyway?" — when writing generic code, a single value type (it's called Unit type btw) is very useful because it eliminates special case of functions that "just return" but don't return anything in particular. But when Java was first created, it has even less expressive type system (without type parameters), so there were not much practical difference. And now it's too late to change. More modern languages actually eschew void "type" (actually it's not even a type, just a special marker for methods) and use Unit type instead. Apr 24, 2017 at 18:10
  • 9
    @SargeBorsch Java's Void type acts as a Unit type (e.g. for Generics), though sadly, it is different from void (side note: a cuddly kitten dies every time you invent a new type to fix the type you messed up in the previous version). If anyone is not familiar with Unit types, this is a decent intro: en.wikipedia.org/wiki/Unit_type Apr 24, 2017 at 19:09
  • 1
    @OgrePsalm33 it doesn't really act as a Unit type (at least in practical means — one still has to write "return null;" to return from method which has Void return type, and AFAIK compiler does allocate space on stack for Void references, not taking advantage of the fact that it's pointless to ever read these values), it's merely a convention to use it where "proper" Unit type would be more appropriate. Apr 24, 2017 at 19:19
  • 3
    @immibis because Unit type by definition must have exactly one value, and Void doesn't have values. Yes, it's possible to use null (in fact this is the only choice), but null is a special thing, any value of reference type in Java may be null (this is another blunder in language design). And, as I said earlier, if you are using Void return type instead of void mark, Java compiler is not your friend. Apr 26, 2017 at 5:15
  • 5
    @SargeBorsch Void has exactly one value, which is null. The fact that null is a member of most type is irrelevant to whether Void is a unit type.
    – user253751
    Apr 26, 2017 at 5:29
65

The original reason why the language has a void type is because like in C, the creators of the language did not want to unnecessarily complicate the syntax of the language with procedures and functions the way Pascal did.

That was the original reason.

Your suggestions:

returning a status flag

That's a no-no. We do not use status flags. If something goes wrong, we report it via exceptions.

the object being invoked

The fluent style of invocations is a recent development. Many of the programmers who are very happily using fluent today and roll their eyes if they ever have to use an interface that does not support it were not even born when Java was created.

returning null

That would force you to declare a method as returning something, when in fact it is not returning anything, so it would be very confusing to someone who is looking at an interface trying to figure out what it does. People would inevitably invent some otherwise useless class that stands for "no return value" so that all functions that do not have anything to return can return a null reference to such a class. That would be clunky. Luckily, there is a solution to this, it is called void. And that's the answer to your question.

20
  • 3
    Please provide a source for "The original reason...". To my knowledge the real reason is because C was designed to be portable assembler. Apr 25, 2017 at 6:43
  • 6
    @ThorbjørnRavnAndersen are you really, actually, asking me to provide a source for the claim that java's syntax is derived from C syntax?
    – Mike Nakis
    Apr 25, 2017 at 7:58
  • 3
    @ThorbjørnRavnAndersen oh, I see, I misunderstood. So, you want a source for my claim about C, not about Java. Okay, I sorry, I have no source for that. But I think it is rather obvious. (I used to program in Pascal in 1987, when I switched to C. My goodness, that's 30 years ago.)
    – Mike Nakis
    Apr 25, 2017 at 12:41
  • 6
    It is not obvious. C was developed at roughly the same time as pascal by people who most likely did not even know it existed. Please do not state assumptions as facts. Apr 25, 2017 at 15:15
  • 12
    The real original reason was that by default C functions returned int, so a keyword was added subsequent to K&R to indicate 'no return type'.
    – user207421
    Apr 26, 2017 at 0:45
21

Some methods, like System.out.println does not return anything useful, but is called purely for this side effect. void is a helpful indicator for the compiler and for the reader of code that no useful value is returned.

Returning null instead of void means you would just get a NullPointerException the moment you use this value for anything. So you trade a compile time error for a runtime error which is way worse. Furthermore, you would have to define the return type as Object, which would be misleading and confusing. (And chaining would still not work.)

Status codes are usually used to indicate error conditions, but Java has exceptions for this purpose.

Returning this is not possible from static methods.

Returning a generic Success object would have no useful purpose.

1
  • 1
    Totally agree with you, the most simplest and concise answer.
    – webo80
    Apr 27, 2017 at 13:34
11

One reason is that it can be misleading to ever return anything other than, say, null. Example:

What should Arrays.sort(a) return?

If you argue that a should be returned so that the call can be chained (which seems to be your response judging from your question), then it is no longer clear whether the return value is a copy of the original object, or the original object itself. Both are possible. And yes, you could put it in the documentation, but it's sufficiently ambiguous that you shouldn't create the ambiguity in the first place.

On the other hand, if you argue that null should be returned, that begs the question of what information the return value is possibly providing the caller, and why the programmer should be forced to write return null when it conveys no information.

And if you return something else totally absurd (like the length of a) then it just makes using that return value really confusing -- just think how much more confusing it is to say int len = Arrays.sort(a) instead of int len = A.length!

8
  • 1
    In all fairness, the programmer wouldn't necessarily be required to write return null; -- the JVM could just as well mandate that if control falls off the end of a function by way other than an explicit return or throw statement, null is implicitly returned to the caller. IIRC C does that, except that the return value is undefined in that case (it will be whatever value happens to be in the location used for the return value at the time).
    – user
    Apr 26, 2017 at 12:14
  • 2
    The correct answer to your bolded question is, "a sorted array". Apr 26, 2017 at 16:11
  • 2
    @BryanBoettcher: Did you not read the rest of it?
    – user541686
    Apr 26, 2017 at 20:13
  • 1
    @Michael Kjörling: it’s a fundamental property of the Java language to prevent such errors, i.e. not to have “undefined behavior” if you forget a return statement. Instead, you get a compiler error telling you about your mistake. Inserting an implicit return null; would be better than “undefined behavior”, but not much. That would be useful only when the return type has no meaning, but where does the compiler draw the conclusion from, that the return value has no meaning, when it is not void?
    – Holger
    Apr 27, 2017 at 8:49
  • 2
    @MichaelKjörling: “If the return truly doesn't add any value…”, well, as said, there is no indicator for the compiler that a return wouldn’t add any value, if there is no void type. It’s actually the opposite, the first assumption is that a method declaring a return type wants to return something useful of the that type. And we didn’t talk about primitive types yet, which don’t have a null value, hence, any default value injected by the compiler would conflict with the range of potentially useful return values.
    – Holger
    Apr 27, 2017 at 9:50
7

Returning a boolean which is always equal to true which you suggest, is not only pointless (the return value carries no information), but would actually be misleading. Most of the time, it's best to use return types which only carry as much information as is actually available - that's why in Java you have boolean for true/false rather than returning an int with 4 billion possible values. Likewise, returning a boolean with two possible values where there is only one possible value ("generic success"), would be misleading.

It would also add unnecessary performance overhead.

If a method is used only for its side effect, there is nothing to return, and the return type void reflects exactly that. Potential rare errors can be signalled via exceptions.

One thing that could be improved, would be making void an actual type, such as Scala's Unit. This would solve some issues such as handling generics.

1
  • Fun fact: List.add does always return true, but that’s for being compatible with the broader contract of Collection.add, so Set.add may return true or false.
    – Holger
    Apr 27, 2017 at 9:52
4

Java is a relatively old language. And in 1995 (When it was created) and shortly thereafter programmers were very concerned about the amount of time a process took control of the processor as well as the consumption of memory. Returning void would eliminate a few clock cycles and a bit of memory consumption from a function call because you would not have to put the return value on the stack, and you would not subsequently have to remove it.

Efficient code does not give you back something you would never use, and therefore putting void into something that has a meaningless return value is a much better practice to be in than returning a success value.

8
  • 14
    programmers who were very concerned about speed would not use Java in these days anyway, because first implementations of Java were notoriously slow. So slow that many people who are currently not working with it are still under that impression that Java is synonym for fat and slow. Apr 24, 2017 at 18:16
  • 8
    @SargeBorsch reminds me of an old programming joke from 20 years ago. "Knock, Knock." "Who's there?" ... ... ... ... very long pause ... ... ... "Java" Apr 24, 2017 at 18:43
  • 4
    @DanNeely and some time after, an AI-driven car crashes in a wall with full speed, not even trying to use brakes. It was written in Java. So, Java doesn't brake now! (it was a pun in Russian language, can't translate it to English very well) Apr 24, 2017 at 18:51
  • 2
    @SargeBorsch What you have works as an English pun, even if it lost some nuance in translation. And translating puns is probably harder than poetry. Apr 24, 2017 at 20:03
  • 3
    Good programmers are still concerned with performance and consumption of memory, which makes unnecessarily asking people to return garbage relevant even today.
    – Sklivvz
    Apr 26, 2017 at 21:29
2

I've read arguments that suggest that the second option (return this) should be the approach instead of void. This is a pretty good idea but it the builder-style approach was not popular at the time Java was created. If it was as popular at that time as it is now, that might have been the approach taken. Returning null is a really bad idea IMO. I wish null was not even in the language at all.

The problem now is that if a method returns an instance of it's own type, it's not clear whether that is a new object or the same one. Often it doesn't (or shouldn't) matter but other times it does matter. I suppose the language could be changed to implicitly return this on void methods. The only issue I can think of with that at the moment is that if the method was later changed to return a new object of the same type, there would be no compilation warnings but that's maybe no a big deal. The current type system doesn't care about these types of changes now. How this interacts with inheritance/interfaces would need some consideration but it would allow old APIs without a builder style to easily be called as if they did.

10
  • 2
    @Cody Good point, this wouldn't apply to static methods.
    – JimmyJames
    Apr 24, 2017 at 17:29
  • 14
    @marisbest2 Which argument?
    – 8bittree
    Apr 24, 2017 at 19:14
  • 3
    Well, if null were not part of the language, people would be using all sorts of sentinel values that mean "please ignore this argument/return value, it does not contain any sensible value". The problem with null is not the thing itself, only that it tends to be used incorrectly. I'd wager that this problem would only be exaggerated if the standardized null would be replaced with a myriad of custom solutions, where each implementation would behave differently like silently ignoring usage, or throwing special exceptions instead of a standart null pointer exception, etc. Apr 25, 2017 at 10:50
  • 2
    @cmaster an obvious replacement for null is a proper optional type (like, Maybe in Haskell). The problem with nulls in Java is that there's no sane way to immediately decide if a value is nullable in practice or not. This leads to both of: unnecessarily defensive programming (checking for nulls where it's pointless, thereby increasing percentage of poop in the code), and accidental NPEs in production (if forgot to check where it was needed). Yeah, it's partially solved by annotations but they are optional, not always checked, etc. So they won't save you at boundaries with third party code. Apr 26, 2017 at 5:24
  • 2
    @SargeBorsch I agree with that :-) My objection is against a language without a standard way to express a "please ignore this value". null works fine for this (fine = simple), but standardized optional values with solid semantics are definitely another fine option (fine = safe). Apr 26, 2017 at 7:23
2

Another aspect:

Java is a static language with quite strict features. This means that many things that would be quite open or dynamic in other languages (c/f Ruby, Lisp etc.) are strictly determined.

This is a general design decision. The "why" is hard to answer (well, because the designers of the language thought it would be good!). The "what for" is pretty clear: it lets the compiler detect a lot of errors, which is generally a pretty good feature for any language. Secondly, it makes it comparatively easy to reason about the language. For example, it is relatively easy to create formal correctness proves in (subsets of) the Java language; as comparison, that would be virtually impossible in a dynamic language like Ruby et al.

This thinking permeates the language, for example, the enforced declaration of possible exceptions that a method can throw, the separate type of interface vs. class to avoid ambiguous multiple inheritance, and so on. For what it is (a static imperative OOP real-world language with strong focus on compile time error handling) those things are actually quite elegant and powerful. They come closer to theoretical (science'y) languages which are purposefully made just to explore some of these issues than any other real-world language before (at that time, mind you).

So. Having a strict void type is a clear message: this method does not return anything, period. It is what it is. Replacing it by the enforcement to always return something would lead to either much more dynamic behaviour (like in Ruby where every def has an explicit or implicit return value, always), which would be bad for provability and reasoning; or to massive bloat by using some other mechanism here.

(And N.B., Ruby (for example) handles this differently, and its solution is still exactly as acceptable as Java's, because it has a completely different philosophy. For example it throws provability and reasonability completely out of the window while putting a large focus on extremely high expressiveness of the language.)

0

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