Returning Void

279 views
Skip to first unread message

Casper Bang

unread,
Oct 4, 2012, 9:42:08 AM10/4/12
to java...@googlegroups.com
How do you guys handle callbacks with Void, say you really don't want anything returned because you are only consuming, streaming or the like?

Say you have a generified callback for extracting rows from a dataset:

public interface RowMapper[T]{
    T map(Row row);
}

Implementing this for the purpose of StAX streaming rather than returning records required one to satisfy the compiler and return something. In C# I can just omit the return line (consistent with void semantics for classic methods). In Java however, one has to return a derivative of Void (null):

    @Override
    public Void map(Row row){
        staxWriter.writeStartElement(row.getString("id"));
        return null;
    }

That's not very nice looking at all. Cheating the type-system and generating a Void instance through reflection is perhaps slightly cleaner semantically, but very verbose. It's obviously related to type-erasure, but why on earth didn't the Java compiler guys burn in a rule that would add a "return null" if the signature is Void? Is there some idiom I am unaware of here that would be nicer than returning null?

/Casper

Ben Smith-Mannschott

unread,
Oct 4, 2012, 11:02:44 AM10/4/12
to java...@googlegroups.com
That's exactly how I do it, and it seems clear enough to me. The
reasoning is that null is the only valid value for variable of type
Void, since Void is not instantiable (without trickery).

Josh Berry

unread,
Oct 4, 2012, 11:14:14 AM10/4/12
to java...@googlegroups.com
On Thu, Oct 4, 2012 at 9:42 AM, Casper Bang <caspe...@gmail.com> wrote:
> How do you guys handle callbacks with Void, say you really don't want
> anything returned because you are only consuming, streaming or the like?
>
> Say you have a generified callback for extracting rows from a dataset:
>
> public interface RowMapper[T]{
> T map(Row row);
> }

I think the best you can do is an abstract class that hides the
"return null" for you. So:

abstract class VoidRowMapper implements RowMapper<Void> {
Void map(Row row) {
voidMap(row);
return null;
}
abstract void voidMap(Row row);
}

Then, you just do VoidMapper instead of RowMapper. (And voidMap
instead of Map.)

I am interested in better ways.

Casper Bang

unread,
Oct 4, 2012, 12:15:42 PM10/4/12
to java...@googlegroups.com

That's exactly how I do it, and it seems clear enough to me. The
reasoning is that null is the only valid value for variable of type
Void, since Void is not instantiable (without trickery).

Except void is, by definition, not supposed to occupy any slots on the stack-frame, and its semantics is very different from null (any and all types). It feels like another one of those dirty type-system duality corners that makes erasure look like a hack.

Then, you just do VoidMapper instead of RowMapper.  (And voidMap 
instead of Map.) 

That's a decent way of shielding what goes on when you have a lot of callbacks. It also composes better in a nested hierarchy of tight one-liners  (impossible with "return null;" sprinkled all over).

Fabrizio Giudici

unread,
Oct 4, 2012, 12:23:56 PM10/4/12
to java...@googlegroups.com
On Thu, 04 Oct 2012 15:42:08 +0200, Casper Bang <caspe...@gmail.com>
wrote:

It's obviously related to type-erasure,
> but
> why on earth didn't the Java compiler guys burn in a rule that would add
> a
> "return null" if the signature is Void?

Laziness in the design of the compiler. I don't know any other solution
than returns null and yes, it's a bit annoying for me too.

--
Fabrizio Giudici - Java Architect @ Tidalwave s.a.s.
"We make Java work. Everywhere."
http://tidalwave.it/fabrizio/blog - fabrizio...@tidalwave.it

Ricky Clarkson

unread,
Oct 4, 2012, 12:29:17 PM10/4/12
to java...@googlegroups.com
It predates type erasure.  I'd imagine this will be fixed with type system unification in some post-8 version of Java.



--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.


Reinier Zwitserloot

unread,
Oct 6, 2012, 1:19:24 PM10/6/12
to java...@googlegroups.com
Generics is involved, and generics is not capable of representing variable arity, so, if the generics say there is a return type.... there's a return type.

Void and void have basically zero relation. That's all there is to it, really. Returning no thing is just as impossible as returning 2 things.

It's also not 'laziness in the compiler' - Void is not void, end of story. Trying to make the compiler sugarcoat a method that returns j.l.Void and has no return statements implies all sorts of 'under the hood magic' that javac is specifically designed NOT to do. There is an argument to be made that this design principle (the 'don't sugarcoat stuff' principle) is wrong or overzealously applied for javac, and that is an argument I might agree with, but _THAT_ is why you have to be explicit with your 'return null' here; laziness does not factor in to it.

Casper Bang

unread,
Oct 6, 2012, 3:12:20 PM10/6/12
to java...@googlegroups.com
Generics is involved, and generics is not capable of representing variable arity, so, if the generics say there is a return type.... there's a return type.
Void and void have basically zero relation. That's all there is to it, really. Returning no thing is just as impossible as returning 2 things.

I can see it both ways, although I really do lean towards it being something that should've been fixed when generics were added. For instance, one can use reflection to get the return type of method returning void, which is bound to Class[?}, suggesting that we ARE indeed dealing with a class instance.

The difference seems to be that when the CLR got generics support, the void keyword was made to act as an alias for the struct System.Void (much like string is an alias for System.String etc.) and so a value type is ALWAYS returned (though I suppose a clever JIT compiler will just optimize this away).

I wonder if this "unification" Ricky Clarkson is referring to, would go the same way - seems like a nice way to solve the problem.

Fabrizio Giudici

unread,
Oct 7, 2012, 7:56:38 AM10/7/12
to java...@googlegroups.com, Reinier Zwitserloot
On Sat, 06 Oct 2012 19:19:24 +0200, Reinier Zwitserloot
<rein...@gmail.com> wrote:


> It's also not 'laziness in the compiler' - Void is not void, end of
> story.
> Trying to make the compiler sugarcoat a method that returns j.l.Void and
> has no return statements implies all sorts of 'under the hood magic' that
> javac is specifically designed NOT to do. There is an argument to be made
> that this design principle (the 'don't sugarcoat stuff' principle) is
> wrong
> or overzealously applied for javac, and that is an argument I might agree
> with, but _THAT_ is why you have to be explicit with your 'return null'
> here; laziness does not factor in to it.

And let's call it overzealous attitude rather than laziness, but in the
end it's the sort of things that the compiler should handle - I just
reckon that returning Void is something that you don't do every day.

Simon Ochsenreither

unread,
Oct 7, 2012, 7:33:06 PM10/7/12
to java...@googlegroups.com
I think it is an interesting example how some "pragmatic" and superficially simpler approach tends to break down and cause complexity in both the spec and the implementation compared to the "academic" solution.

From a language design POV there are multiple issues here:
  • Primitive types vs. wrappers thing, which leads to really ugly interactions
  • Conflation of Void, Unit and Bottom
  • Lack of pricinpal types for things like non-determination or null

A neat thing is how one misfeature (null) is basically saving the functionality of another feature. (See C# for a different, imho less nice solution.)

While I can see how the notion of "it doesn't return anything" for void looks intuitive from a low-level point of view (nothing gets push'ed/pop'ed), it is not intuitive if you view a program purely from an data flow perspective, because there is a difference between "it returns, but with no new information" and "it doesn't return" which Java completely fails to capture.

Additionally, the fact that void is not even a type, but some special, hard-coded language keyword also adds complexity to the whole concept.

(Some newer languages got all of this right from the start.)

Kevin Wright

unread,
Oct 7, 2012, 7:53:10 PM10/7/12
to java...@googlegroups.com
Just to put this into perspective for those who don't know the concepts:

Bottom is the universal subtype, it's a subtype of EVERYTHING else in the type system, including primitives.  It also only makes sense as a type, it's never actually possible to have an instance of Bottom.  There's no way to directly express this in Java, but it's easy to give an example where it makes sense... What's the return type of a `throw new XXX` statement?  Even if this occurs in a method declared as returning a primitive?  The bottom type is also the correct return type of a method that only ever goes into an infinite loop.

Unit is the "I've returned, but without an information except the fact that I've returned" type.  Void comes close, but (crucially) the Unit type is considered to have just the one value.  Think of this as an immutable singleton being returned from every `void` method, if it helps.

Void is what Java calls Unit when dealing with a void-returning method through reflection.  It's not *quite* right though, as Void doesn't have that crucial singleton instance - which gives rise to the hack discussed so far in this thread.


If anyone's interested, the bottom type in Scala is named `Nothing`, Unit is named `Unit`, and the unique instance of Unit is named `()`.  So it *is* possible for these concepts to be represented in a way that compiles nicely down to JVM bytecode.

--
Kevin Wright
mail: kevin....@scalatechnology.com
gtalk / msn : kev.lee...@gmail.com
vibe / skype: kev.lee.wright
steam: kev_lee_wright

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra

Reinier Zwitserloot

unread,
Oct 15, 2012, 7:01:10 AM10/15/12
to java...@googlegroups.com
On Monday, October 8, 2012 1:33:06 AM UTC+2, Simon Ochsenreither wrote:
I think it is an interesting example how some "pragmatic" and superficially simpler approach tends to break down and cause complexity in both the spec and the implementation compared to the "academic" solution.

Yes, java has no type that represents "there is no value that is this type, not even 'null'". It would be cool if this type existed; a method that had this as return type cannot actually return, ever. It has to exit abnormally: Either it runs System.exit(0), which should probably at that point return this special Nothing type (so that you can type: return System.exit(0)), or it has to throw an exception. There are no other ways out.

Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do, and languages like Scala DO do: it's not a matter of superiority, it's a matter of tradeoffs: If this Nothing exists, it cannot actually be a subtype of Object; a List<?> cannot accept an instance of List<Nothing>, because I can still put nulls in List<?>, and nulls are not a valid value for Nothing. Hell, generics in general play havoc with this: Using trickery I can make a List<Nothing> with nulls in it, and then write return thisHackedList.get(0), which means in practice that Nothing needs type checking (i.e. that would lead to a ClassCastException or similar, even if .get(0) returns null).

That's the kind of thing where java has decided that the practical upside of having a 'Nothing' value is not actually that much; it's largely academic, and it definitely "feels bad" that the language is not complete, and that this awesome concept is not actually in your language. However, adding it to the language definitely incurs a cost: The compiler needs to do all sorts of things to treat Nothing specially, and this is going to make the spec much more complicated.

Scala-like design says you accept the complexity hit, and theorizes that if you go whole-hog on this you can actually remove a lot of complexity because the language is much more flexible. So far that seems like it's been working out reasonably well for scala. The java-like design says that these mostly academic features just aren't important enough, and in practice the language will be simpler if you just don't have them. Where people need them, they'll kludge it.

Sounds ugly. Yet, java's popularity and the robustness of java-based apps like google ads and many a server out there suggest it's fine.

(Some newer languages got all of this right from the start.)


Right. I'm saying, well, the jury is still out on this. Is it actually right to burden your language with the Nothing concept?

I'm pretty sure that retrofitting Nothing onto java is a grave mistake at this point.

Kevin Wright

unread,
Oct 15, 2012, 7:37:20 AM10/15/12
to java...@googlegroups.com
On 15 October 2012 12:01, Reinier Zwitserloot <rein...@gmail.com> wrote:
On Monday, October 8, 2012 1:33:06 AM UTC+2, Simon Ochsenreither wrote:
I think it is an interesting example how some "pragmatic" and superficially simpler approach tends to break down and cause complexity in both the spec and the implementation compared to the "academic" solution.

Yes, java has no type that represents "there is no value that is this type, not even 'null'". It would be cool if this type existed; a method that had this as return type cannot actually return, ever. It has to exit abnormally: Either it runs System.exit(0), which should probably at that point return this special Nothing type (so that you can type: return System.exit(0)), or it has to throw an exception. There are no other ways out.

There are other cases too, it also crops up in recursion where there's absolutely no information whatsoever available for type inference.  Just consider:

def method[A](x: A): A = method(x)

Something like this, without tail recursion, would ultimately crash the JVM with a StackOverflowException.

More importantly though... even given a variant that did terminate and didn't stack overflow, what type could reasonably be inferred *except* for Nothing?

 
Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do, and languages like Scala DO do: it's not a matter of superiority, it's a matter of tradeoffs: If this Nothing exists, it cannot actually be a subtype of Object; a List<?> cannot accept an instance of List<Nothing>, because I can still put nulls in List<?>, and nulls are not a valid value for Nothing. Hell, generics in general play havoc with this: Using trickery I can make a List<Nothing> with nulls in it, and then write return thisHackedList.get(0), which means in practice that Nothing needs type checking (i.e. that would lead to a ClassCastException or similar, even if .get(0) returns null).

Fortunately, this is *exactly* you you want to do with an immutable list!

The only way to add an element to an immutable list is to create a new list containing the old one as a subset.  This means that the type of every element in the existing list must subclass the element type of the new list.

To put it another way, this means that the element being added to an immutable list must be a superclass of the element type of all elements already in the list.

And, because such lists are immutable, they must be built up by starting with an empty list.  This empty list must have an element type such that *anything* you might add to it is a superclass.

The element type of such an empty list MUST be the subtype of every other type in existence.

That type is Nothing, and Scala's empty list (called Nil) is, indeed, an instance of List[Nothing]

List[Nothing] not only makes sense, it's actually a necessary requirement to get immutability right.  It also only works if Nothing is very much a subclass of Object, and Null, and anything else you care to mention.

 
That's the kind of thing where java has decided that the practical upside of having a 'Nothing' value is not actually that much; it's largely academic, and it definitely "feels bad" that the language is not complete, and that this awesome concept is not actually in your language. However, adding it to the language definitely incurs a cost: The compiler needs to do all sorts of things to treat Nothing specially, and this is going to make the spec much more complicated.

What of the cognitive cost to having this concept that developers must necessarily encounter, then forcing them to use hacks and workarounds because it cannot be represented in their programming language?

 
Scala-like design says you accept the complexity hit, and theorizes that if you go whole-hog on this you can actually remove a lot of complexity because the language is much more flexible. So far that seems like it's been working out reasonably well for scala. The java-like design says that these mostly academic features just aren't important enough, and in practice the language will be simpler if you just don't have them. Where people need them, they'll kludge it.

Isn't that what they tried with Date?  and then Calendar? 
 
Sounds ugly. Yet, java's popularity and the robustness of java-based apps like google ads and many a server out there suggest it's fine.
 
It's a testament to what a decent developer is able to work around, but the ecosystem developed on the back of Java's strengths and in spite of its flaws - not *because* of its flaws!

(Some newer languages got all of this right from the start.)


Right. I'm saying, well, the jury is still out on this. Is it actually right to burden your language with the Nothing concept?

I'm pretty sure that retrofitting Nothing onto java is a grave mistake at this point.


I fear that the bigger mistake is to add lambdas, and immutable structures, and the whole the-free-lunch-is-over-my-GPU-has-1000-cores-we-desperately-need-to-get-concurrency-right infrastructure, then to cripple it by missing something so fundamental from the type system!

Jess Holle

unread,
Oct 15, 2012, 7:57:03 AM10/15/12
to java...@googlegroups.com
Two words:
ivory tower
Retrofitting concepts into languages where there's little *real* benefit serves only to waste resources that could be better spent elsewhere -- and to risk breaking things, e.g. backward compatibility, that do have real, tangible benefit.

We're in the real world, developing real software.  Nothing is perfect and no one has the luxury to repeatedly up-end everything to rework everything that wasn't 100% perfect.  Sure, when there are serious issues you go back and rework things, but there are time/resource vs. compability/migration-cost vs. perfection vs. .... tradeoffs that one must carefully weigh.  That's one reason it's called software engineering.
--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.

Simon Ochsenreither

unread,
Oct 15, 2012, 8:42:11 AM10/15/12
to java...@googlegroups.com

Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do, and languages like Scala DO do: it's not a matter of superiority, it's a matter of tradeoffs: If this Nothing exists, it cannot actually be a subtype of Object; a List<?> cannot accept an instance of List<Nothing>, because I can still put nulls in List<?>, and nulls are not a valid value for Nothing. Hell, generics in general play havoc with this: Using trickery I can make a List<Nothing> with nulls in it, and then write return thisHackedList.get(0), which means in practice that Nothing needs type checking (i.e. that would lead to a ClassCastException or similar, even if .get(0) returns null).

Is this just theorizing? I'd love to see that code.

 
That's the kind of thing where java has decided that the practical upside of having a 'Nothing' value is not actually that much; it's largely academic, and it definitely "feels bad" that the language is not complete, and that this awesome concept is not actually in your language. However, adding it to the language definitely incurs a cost: The compiler needs to do all sorts of things to treat Nothing specially, and this is going to make the spec much more complicated.

Did you actually check that? Until now, I have only seen a Java-specific issue which doesn't even exist in Scala. I'd love to see some of this complexity caused by Nothing.

 
Scala-like design says you accept the complexity hit, and theorizes that if you go whole-hog on this you can actually remove a lot of complexity because the language is much more flexible. So far that seems like it's been working out reasonably well for scala. The java-like design says that these mostly academic features just aren't important enough, and in practice the language will be simpler if you just don't have them. Where people need them, they'll kludge it.

Did you just make that up?


Sounds ugly. Yet, java's popularity and the robustness of java-based apps like google ads and many a server out there suggest it's fine.

See the other recent debate.
 

Right. I'm saying, well, the jury is still out on this. Is it actually right to burden your language with the Nothing concept?

Sorry to say that, but your comment really reads like hand-waving with little actual facts.

Ricky Clarkson

unread,
Oct 15, 2012, 8:47:40 AM10/15/12
to java...@googlegroups.com

I'd like to see more use cases for Nothing, more ways in which it simplifies without changing the meaning of existing code.

One annoyance in Scala is when it infers a type to be, say, List[Nothing], which so far has never been what I intended.

Casper Bang

unread,
Oct 15, 2012, 8:47:55 AM10/15/12
to java...@googlegroups.com
Yes, java has no type that represents "there is no value that is this type, not even 'null'". It would be cool if this type existed; a method that had this as return type cannot actually return, ever. It has to exit abnormally:

From a programmers perspective, when you return from a method (byte-code 0xb1), you are indeed returning nothing. From the JVM's perspective, you're not returning anything either - the stack is left completely untouched.
 
Either it runs System.exit(0), which should probably at that point return this special Nothing type (so that you can type: return System.exit(0)), or it has to throw an exception. There are no other ways out.

Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do

Except when it DOES do so, such as when you omit an explicit return and rely on javac to implicitly paste this in for you at while desugaring.
 
That's the kind of thing where java has decided that the practical upside of having a 'Nothing' value is not actually that much; it's largely academic, and it definitely "feels bad" that the language is not complete, and that this awesome concept is not actually in your language. However, adding it to the language definitely incurs a cost: The compiler needs to do all sorts of things to treat Nothing specially, and this is going to make the spec much more complicated.

Complications usually arise from the convoluted interactions of accumulated features (const vs non-const i C comes to mind), not from being consistent about the programming model up-front. Frankly, I couldn't care less about how the compiles does things internally, but I am often forced into this. Another example where this applies, is with generics and the (for the uninitiated) odd inability to implement Comparable&lt;Fruit&gt, Comparable&lt;Veggie&gt;
 
Sounds ugly. Yet, java's popularity and the robustness of java-based apps like google ads and many a server out there suggest it's fine.

You're grasping for straws here. I think we can agree it's not quite that simple.
 
Right. I'm saying, well, the jury is still out on this. Is it actually right to burden your language with the Nothing concept?

I'm pretty sure that retrofitting Nothing onto java is a grave mistake at this point.

But we already have Void, the compiler probably already uses plenty of places internally. Promote it to work in tandem with javac's existing desugaring rules, such that a return Callable&lt;Void&gt; results in a non- stack-modifying return which satisfies developer, compiler and JVM.

Ricky Clarkson

unread,
Oct 15, 2012, 8:50:14 AM10/15/12
to java...@googlegroups.com

Having Nil not need a type parameter is absolutely not necessary for immutability.  It just makes code involving Nil a tad more readable.  Also cons lists are not our only option in immutable code, just as the mutable world is richer than just having ArrayList everywhere.

On Oct 15, 2012 8:37 AM, "Kevin Wright" <kev.lee...@gmail.com> wrote:

Simon Ochsenreither

unread,
Oct 15, 2012, 8:55:48 AM10/15/12
to java...@googlegroups.com

One annoyance in Scala is when it infers a type to be, say, List[Nothing], which so far has never been what I intended.

While I remember some “interesting” type inference results, List[Nothing] is a bad example. There is only one, single, unique value of List[Nothing] and it is the empty list. And in fact, that's the only possible element type of an empty list.

Kevin Wright

unread,
Oct 15, 2012, 9:27:14 AM10/15/12
to java...@googlegroups.com
Void isn't quite right though.  It corresponds to "return, but with no useful information", which isn't the same thing as not returning at all.

It's the difference between an empty tuple and a thrown exception.

Casper Bang

unread,
Oct 15, 2012, 11:04:44 AM10/15/12
to java...@googlegroups.com

On Monday, October 15, 2012 3:27:20 PM UTC+2, KWright wrote:
Void isn't quite right though.  It corresponds to "return, but with no useful information", which isn't the same thing as not returning at all.

Why the interest in modeling "not returning at all"? Isn't that mostly interesting to people studying the halting problem? I'm strictly interested in modelling "return with nothing" and "return with something", what else is there but blocking the thread or looping indefinitely?

A compiler seeing generic capture of Void, could allow an implicit return clause (as is the case with the void keyword) and furthermore optimize stack push/pop away (rather than boxing null). It seems like the issue is going to come up much more, when/if closures are introduced.

Kevin Wright

unread,
Oct 15, 2012, 11:38:36 AM10/15/12
to java...@googlegroups.com
On 15 October 2012 16:04, Casper Bang <caspe...@gmail.com> wrote:

On Monday, October 15, 2012 3:27:20 PM UTC+2, KWright wrote:
Void isn't quite right though.  It corresponds to "return, but with no useful information", which isn't the same thing as not returning at all.

Why the interest in modeling "not returning at all"? Isn't that mostly interesting to people studying the halting problem? I'm strictly interested in modelling "return with nothing" and "return with something", what else is there but blocking the thread or looping indefinitely?

Then there's throwing an exception... Where control is NOT returned to the caller, but instead to the nearest matching catch{} block.  From the perspective of the caller, a method that throws an exception has not returned in any way, shape or form:

int someMethod(int question) {
    final int retval =
        question.equals("What is the answer?")
        ? 42
        : throw new Exception("that's not the question");
    return retval;
}

So what's the type of throw new Exception(...)?
It HAS to be a subclass of int, or the definition of retval is invalid.

The only possible answer is Nothing (or Bottom, or _|_ if you prefer).  Void is an empty return, it's not a subclass of int.

 
A compiler seeing generic capture of Void, could allow an implicit return clause (as is the case with the void keyword) and furthermore optimize stack push/pop away (rather than boxing null). It seems like the issue is going to come up much more, when/if closures are introduced.

Yes, this will become a whole lot more important once folk begin using lambdas.

Josh Berry

unread,
Oct 15, 2012, 12:01:26 PM10/15/12
to java...@googlegroups.com
On Mon, Oct 15, 2012 at 11:38 AM, Kevin Wright <kev.lee...@gmail.com> wrote:
> So what's the type of throw new Exception(...)?
> It HAS to be a subclass of int, or the definition of retval is invalid.

Or.... it threw an exception. We are already hitting a keyword here.
Not exactly a tough one to conceive and we are already outside of the
types as expressed in the method signature. Why bother letting that
detail leak to the users?

That is, people are comfortable with "this method returns an int, or
throws an exception, or exits the system." Why try and force people
to understand that "throws an exception and exits the system" can be
made compatible with "returns an int" through the type system?

Alexey

unread,
Oct 16, 2012, 11:14:13 PM10/16/12
to java...@googlegroups.com
There's a difference between throw X and throws X.  One is a control flow statement and the other is part of a method signaturethrow and return don't necessarily have a type because they're not rval expressions.  If we wanna discuss mixing control flow statements with rval expressions, that feels like a totally different conversation.  And by the way, throwing an exception does return control to the caller.  Consider the following:

void dangerZone() throws UhOhException {
  throw new UhOhException();
}

void callMe() throws UhOhException {
  try {
    System.out.println("Here we go...");
    dangerZone();
    System.out.println("We did it!");
  }
  finally {
    System.out.println("Good or bad, we're outta here!");
  }
}

Reinier Zwitserloot

unread,
Oct 21, 2012, 6:48:36 PM10/21/12
to java...@googlegroups.com
On Monday, October 15, 2012 2:42:11 PM UTC+2, Simon Ochsenreither wrote:

Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do, and languages like Scala DO do: it's not a matter of superiority, it's a matter of tradeoffs: If this Nothing exists, it cannot actually be a subtype of Object; a List<?> cannot accept an instance of List<Nothing>, because I can still put nulls in List<?>, and nulls are not a valid value for Nothing. Hell, generics in general play havoc with this: Using trickery I can make a List<Nothing> with nulls in it, and then write return thisHackedList.get(0), which means in practice that Nothing needs type checking (i.e. that would lead to a ClassCastException or similar, even if .get(0) returns null).

Is this just theorizing? I'd love to see that code.


What code? It's trivial:

List<Nothing> list = new ArrayList<Nothing>();
list.add(null); //Barring compiler magic, this will compile and run without error.

or:

List<Object> list = new ArrayList<Object>();
list.add(null);
List<Nothing> list2 = (List<Nothing>)list;
Nothing aNothingVariableThatContainsValue = list2.get(0); // compiler or VM magic required to throw the needed runtime exception here.

or even:

Nothing y = null; // Compiler magic required to make this invalid.


 
That's the kind of thing where java has decided that the practical upside of having a 'Nothing' value is not actually that much; it's largely academic, and it definitely "feels bad" that the language is not complete, and that this awesome concept is not actually in your language. However, adding it to the language definitely incurs a cost: The compiler needs to do all sorts of things to treat Nothing specially, and this is going to make the spec much more complicated.

Did you actually check that? Until now, I have only seen a Java-specific issue which doesn't even exist in Scala. I'd love to see some of this complexity caused by Nothing.


Uh, no, it is common sense. See the above snippets. The compiler / runtime magic required to make nothing actually have its peculiar properties is not 'free' - it is a spec burden on the spec writers, it has real code and test that need to be written and maintained for the compiler and tool authors, and the programmers that write java need to know what it is (the mental burden).
 
 
Scala-like design says you accept the complexity hit, and theorizes that if you go whole-hog on this you can actually remove a lot of complexity because the language is much more flexible. So far that seems like it's been working out reasonably well for scala. The java-like design says that these mostly academic features just aren't important enough, and in practice the language will be simpler if you just don't have them. Where people need them, they'll kludge it.

Did you just make that up?

Mu; arguments are what they are. Your insinuation is a cheap tactic, though.
 


Sounds ugly. Yet, java's popularity and the robustness of java-based apps like google ads and many a server out there suggest it's fine.

See the other recent debate.

'the other recent debate'? - this forum has lots of threads. This thread has lots of posts. You're going to have to be more specific.

Reinier Zwitserloot

unread,
Oct 21, 2012, 7:03:23 PM10/21/12
to java...@googlegroups.com
On Monday, October 15, 2012 2:47:55 PM UTC+2, Casper Bang wrote:
Yes, java has no type that represents "there is no value that is this type, not even 'null'". It would be cool if this type existed; a method that had this as return type cannot actually return, ever. It has to exit abnormally:

From a programmers perspective, when you return from a method (byte-code 0xb1), you are indeed returning nothing. From the JVM's perspective, you're not returning anything either - the stack is left completely untouched.

The compiler will refuse to compile 'return;' in any method with a non-void return type, and the verifier will refuse to run a class if you hack that into the bytecode. "From the JVM's perspective" is therefore misleading; at best you can speak 'from the verifier's perspective', here, which will simply note that there is a discrepancy between return type and variant of the return opcode used and deny the class. I don't think this is particularly relevant to this discussion.
 
 
Either it runs System.exit(0), which should probably at that point return this special Nothing type (so that you can type: return System.exit(0)), or it has to throw an exception. There are no other ways out.

Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do

Except when it DOES do so, such as when you omit an explicit return and rely on javac to implicitly paste this in for you at while desugaring.

You're comparing apples and kitchen sinks.
 
Complications usually arise from the convoluted interactions of accumulated features (const vs non-const i C comes to mind), not from being consistent about the programming model up-front. Frankly, I couldn't care less about how the compiles does things internally, but I am often forced into this.

You're 'often' forced into having to hand-hack some Nothing into your code? I call baloney.
 
Another example where this applies, is with generics and the (for the uninitiated) odd inability to implement Comparable&lt;Fruit&gt, Comparable&lt;Veggie&gt;

Another: Yup, that's annoying... once in 5 years case.
 
 
Sounds ugly. Yet, java's popularity and the robustness of java-based apps like google ads and many a server out there suggest it's fine.

You're grasping for straws here. I think we can agree it's not quite that simple.

You just mentioned Comparable<Fruit> and Comparable<Veggie>. Who is grasping at straws here?

Sure, this isn't simple. That was kind of my point, too: Yes, 'nothing' is a real concept and it is one that java simply does not have. It would be simple to say: "... well, then, let's add it!", but I was trying to highlight how its (probably) not worth doing, and either way it is a tradeoff: There are also signficant (At least, relative to the mediocre upside of adding this to the language) downsides to adding it.
 
 
But we already have Void, the compiler probably already uses plenty of places internally.

java.lang.Void and the Nothing concept do not intersect much. There's a big difference between 'non-magic class that is, by consensus, accepted as a placeholder for "forget about the return type, it doesn't mattter"' and actual room in the spec, compiler, toolchain, and programmer's head for the nothing concept.
 
Promote it to work in tandem with javac's existing desugaring rules, such that a return Callable&lt;Void&gt; results in a non- stack-modifying return which satisfies developer, compiler and JVM.

... Leads down the path of the disadvantages. I'm with Ricky on this one: More serious use cases please.

Reinier Zwitserloot

unread,
Oct 21, 2012, 7:05:44 PM10/21/12
to java...@googlegroups.com


On Monday, October 15, 2012 2:55:49 PM UTC+2, Simon Ochsenreither wrote:

One annoyance in Scala is when it infers a type to be, say, List[Nothing], which so far has never been what I intended.

While I remember some “interesting” type inference results, List[Nothing] is a bad example. There is only one, single, unique value of List[Nothing] and it is the empty list. And in fact, that's the only possible element type of an empty list.



That's false; a List[String] can happen to be empty. If you have a scala method which accepts 1 List[String] as argument, you cannot presume that this list will necessarily contain at least 1 element.

It is very strange to have an _immutable_ empty List[String] but still perfectly valid: If I need to call a method that takes a List[String], for example for additional arguments to pass to an external process (think j.l.ProcessBuilder), then I probably just want to use a nil list and pass that in, at which point I'll have a List[String] reference that is pointing at an immutable empty list.
 

Kevin Wright

unread,
Oct 21, 2012, 7:20:58 PM10/21/12
to java...@googlegroups.com
That's kind of the point...

A List[Nothing] *is* a List[String], or indeed a List[Anything you care for], on account of `Nothing` being a universal subtype.

Simon Ochsenreither

unread,
Oct 21, 2012, 7:25:54 PM10/21/12
to java...@googlegroups.com

that's false; a List[String] can happen to be empty.
List[String] is a supertype of List[Nothing], just like Object. That's surely not the point I was trying to make.

Reinier Zwitserloot

unread,
Oct 21, 2012, 7:26:40 PM10/21/12
to java...@googlegroups.com


On Monday, October 22, 2012 1:25:54 AM UTC+2, Simon Ochsenreither wrote:

that's false; a List[String] can happen to be empty.
List[String] is a supertype of List[Nothing], just like Object. That's surely not the point I was trying to make.

What point _were_ you making then?
 

Kevin Wright

unread,
Oct 21, 2012, 7:26:58 PM10/21/12
to java...@googlegroups.com
On 21 October 2012 23:48, Reinier Zwitserloot <rein...@gmail.com> wrote:
On Monday, October 15, 2012 2:42:11 PM UTC+2, Simon Ochsenreither wrote:

Unfortunately, introducing this kind of concept is exactly the kind of thing java does NOT do, and languages like Scala DO do: it's not a matter of superiority, it's a matter of tradeoffs: If this Nothing exists, it cannot actually be a subtype of Object; a List<?> cannot accept an instance of List<Nothing>, because I can still put nulls in List<?>, and nulls are not a valid value for Nothing. Hell, generics in general play havoc with this: Using trickery I can make a List<Nothing> with nulls in it, and then write return thisHackedList.get(0), which means in practice that Nothing needs type checking (i.e. that would lead to a ClassCastException or similar, even if .get(0) returns null).

Is this just theorizing? I'd love to see that code.


What code? It's trivial:

List<Nothing> list = new ArrayList<Nothing>();
list.add(null); //Barring compiler magic, this will compile and run without error.

or:

List<Object> list = new ArrayList<Object>();
list.add(null);
List<Nothing> list2 = (List<Nothing>)list;
Nothing aNothingVariableThatContainsValue = list2.get(0); // compiler or VM magic required to throw the needed runtime exception here.

or even:

Nothing y = null; // Compiler magic required to make this invalid.


No more than the pre-existing compiler "magic".  It's no more possible to declare a variable of type `Nothing` than it is to declare it to be of type `void` - even though both are valid method return types.

It's also not possible to add a variable of type 'Car' to a List<Ferrari>, not unless it's immutable in which case you'd get back a List<Car>.  Exactly the same logic applies in adding a variable of type Null to a List<Nothing>

Simon Ochsenreither

unread,
Oct 21, 2012, 7:36:31 PM10/21/12
to java...@googlegroups.com

Using trickery I can make a List<Nothing> with nulls in it, and then write return thisHackedList.get(0), which means in practice that Nothing needs type checking (i.e. that would lead to a ClassCastException or similar, even if .get(0) returns null).
Is this just theorizing? I'd love to see that code.
What code? It's trivial:

List<Nothing> list = new ArrayList<Nothing>();
list.add(null); //Barring compiler magic, this will compile and run without error.
 
Real code:
val list: List[Nothing] = null :: Nil //Oh wait ... that doesn't compile, because null is not of type Nothing.
 
Nothing y = null; // Compiler magic required to make this invalid.
That's as much as
Integer foo = new Object();
needs "compiler magic".
 
See the other recent debate.
'the other recent debate'? - this forum has lots of threads. This thread has lots of posts. You're going to have to be more specific.
The debate about people pulling a "Java is the most popular thing ever, therefore everything it does is right" response as soon as they run out of arguments.

Simon Ochsenreither

unread,
Oct 21, 2012, 7:41:42 PM10/21/12
to java...@googlegroups.com


What point _were_ you making then?

Maybe you should consider figuring that out *before* clicking reply.

Simon Ochsenreither

unread,
Nov 16, 2012, 1:57:00 PM11/16/12
to java...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages