Okay, most of those aren't low hanging fruit. I've spent the past week working out specifically how to translate from source to source and its just too difficult for many of the changes I had in mind. CICE, rewiring == to use .equals, and value classes are really the only big ones that 'work'.
I'll explain the insane complexity of non-nullness just as a single example to show how extraordinarily difficult being compatible with java (even on the class file level) is: non-nullness seems like a simple thing to add. For arguments sake, lets say that a standard type is nullable, and a suffix ! indicates never null. (I know the prevailing attitude is that non-null should be the default, and I sort of agree with this, but its easier to explain the difficulty this way, so bear with me. Its easy to see that if you can make '!' work, then going the extra step and making that the default, and '?' as a marker to indicate nullity, is trivial, so it doesn't really matter which one of the two gets proved to be nearly impossible to implement). So, here's the ! marker in action: List!<String!> list = new ArrayList<String!>(); list.add(null); //compiler error; list contains 'String!', so null is not allowed. list = null; //compiler error; list is of type List!, so may not be null. String! foo = list.get(0); //okay String bar = list.get(0); //okay; returns a String! but that is assign-compatible with String. String x ="foo"; list.add(x); //not okay. x might be null. list.add((!)x); //okay. (!) is shorthand for 'throw NPE if expression is null'. Because the ! suffixes are everywhere, including in method return types, you won't be using (!) all that much. Also, compiler analysis will be smart enough to recognize 'if ( foo == null ) { /* code */ } else { /* code where 'foo' is treated as non-null */ }. This is great for e.g.: Map!<Integer!, String!> map = {1 -> "one", 2 -> "two"}; //pseudocode List!<String!> list = new ArrayList<String!>(); String! foo = map.get(0); //NOT OKAY - .get() returns null to indicate not found. String x = map.get(0); //this is okay. if ( x == null ) { sysout("not found"); } else { list.add(x); } // okay - compiler analysis. Bit more complicated, but we can make this work. Now we get into the nasty bits: generics. List<String!> list = new ArrayList<String!>(); //okay List<String> list2 = list; //is this okay? list2.add(null); String! x = list.get(0); //Ah. So, that's NOT OKAY. But then... List<String> a = new ArrayList<String!>(); //ALSO NOT OKAY List<String!> b = new ArrayList<String>(); //NOT OKAY EITHER In the above code snippet, 'x' would contain null, eventhough its of type 'String!'. Between obvious speed issues and a massive set of existing libraries that can't just be recompiled, its not possible to runtime-check everything, so the type system needs to ensure correctness. This is just like generics, which also isn't runtime checked. And so we have the same issues. Just like List<Number> c = new ArrayList<Integer>(); is NOT LEGAL in current java, List<String> d = new ArrayList<String!>() can't legal either, because you can use it to break the forced non-nullity. Assigning a List<String> to a variable of List<String!> is also not okay, for perhaps more obvious reasons. Just like generics, if we somehow had a guarantee that we're only going to read from the list, you COULD assign a List<String!> to a variable of type List<String>; the fact that we have to do null-checks on items retrieved from the list eventhough they aren't ever null is not a problem. Similarly, if we somehow knew that we're only going to write into the list, then assigning a List<String> to a List<String!> variable is okay; we'd be forced to only write non-null into the list, which is of course always okay, regardless of whether the list allows nulls or not. This is like generics '? extends String' and '? super String'. You can read Strings from the first (but not write them), and you can write strings (but not read them) into the second. Co/ contravariance, in other words. And so, non-nullness has the same complexity as generics. We need a way to say that we don't know the forced non-nullity status of a generics bound. Let's make up a syntax for this: List<String?> list = new ArrayList<String!>(); The ? doesn't indicate 'might be null', but instead indicates 'might or might not be forced non-null'. As a result, when adding to this list, you must pass in String!, and when reading, you get String (so, adding stuff must not be null, but when reading you must be prepared for nulls). Just like with ? extends String, when reading you get a String, but you can't write to it. Imagine we used non-null as a default and '?' as a marker that it might be null, what symbol do you use to indicate this now? Interrobang? Something like List<?!> list? We'll get back to that; lets continue with 'null is default, ! indicates non-null, ? indicates unknown state' for a moment. We need the ? for return types as well. ArrayList can of course hold null if it wants to, but its get() method returns null only if its generics parameter is a nullable type. However, for the V part of a Map, this isn't true; its get method can always return null. For another class, lets say a hypothetical NullMarkedLinkedList, you MUST always pass in non-null types, so it would make sense to throw a compiler error right at the construction phase and disallow: new NullMarkedLinkedList<String>(); - only allow passing <String!>. We need ways to mark this. Let's go with: public class NullMarkedLinkedList<T!> implements List<T> {} The T! there indicates that the generics bound MUST be non-null. and for the map class which needs to explain that its get method can always return null: public V? get(K key) {} This means: Regardless of the allows-null status of 'V', this method can always return null. Okay, so far so good, sort of. It's already miles more complicated than any of you originally thought. I was certainly bummed when I got this far. But we're by no means done, unfortunately. Lets now add full generics in the mix. List<? extends Number> list = new ArrayList<Double!>(); That's seems illegal, for the same reason List<String> = new ArrayList<String!>() is not legal. Except that this one IS legal, because, due to the 'extends', we've already limited ourselves to only reading from 'list' (try it; you can't add things to that list unless you do an unsafe generics cast which produces a generics warning). However, this is even more complicated than generics: List<T> = someList<T!> is illegal, but List<? extends T> = someList<T!> isn't. Whoa. But we need a way to indicate that 'list' is still definitely non- null, so that when we read from it, we get 'Number!' out, instead of 'Number'. Let's use the interrobang for this one: List<?! extends Number> list = new ArrayList<Double!>(); Unfortunately the ?! syntax looks a bit like cartoon swearing but it seems like the most sensical thing. Putting the ! on Number seems nicer, but that doesn't really make any sense. The Number is just a bound, its not a complete type. The actual thing which isn't going to be null is the type itself, not the bound, which in this case is represented by the ?. Ugh. We now have: T - no non-null bound T! - definitely not null T? - may or may not be forced non-null ?! - nameless generics variable with forced non-null and we're still not done - there's 'super' as well: List<? super Integer> list = new ArrayList<Number!>(); //not okay List<?! super Integer> list = new ArrayList<Number!>(); //okay List<?! super Integer> list = new ArrayList<Number>(); //NOT OKAY! Now the reverse happens; the ?! notation will accept either forced non- null or not-forced-non-null because due to the 'super' we've already limited ourselves to just writing things into the list. ?! forces us to write non-null Integers, which is obviously also okay to do to a list that contains nullable Numbers (a non-null Integer is obviously a Number which may or may not be null). Unfortunately, unlike the '? extends Number' case, where it's impossible to write to the list, you *CAN* still read from this list. You'll just get Object back, which is annoying, because Object also has nullable/non-nullable status. Either the List<?! super Integer> returns "Object" for its get method, instead of "Object!", which seems completely screwed up, and makes it impossible to pass non-nullity status to stuff with generics 'super' bounds (as even the ! doesn't actually say: Never null). So, we need yet another syntax, the double question mark: List<?? super Integer> list = someList(); Object x = list.get(0); //okay list.add(null); //not okay list.add(10); //okay I think we're done, but at this point I'm cleaning my exploded brains off the walls, so who knows if this is where the insanity ends. (I checked what IDEA does, but IDEA just doesn't allow the annotations they use inside generics bounds, which seems like making the entire null checking stuff pointless. I'd ask IDEA people how useful the very limited nullability checking is, but I'm afraid of fanboyism, so, please be elaborate and use examples) Even if you compiled straight to class files a la scala, you can't fix this one without making life very very difficult for yourself. By the way, viktor, you're still not getting it. For example, you can't add tailcalls to the JVM without *CHANGING THE JVM*. Not even scala goes this far! Here's your scoreboard (source-source is source rewriting, source- class is compiling directly to class files, which wasn't the idea, and JVM-change means changing the JVM, which is completely off the board). duplicity test = because of the translation back and forth, only 1 version is allowed. So with type aliases, for example, if you aliased 'StringList' to 'List<String>', then anytime you typed 'List<String>', the source would forcibly be changed. This would get annoying, I bet. 1) Remove checked exceptions: FAIL: source-class 2) Add type aliases: PASS: source-source, but duplicity concern. 3) add value classes: PASS: source-source 4) add non-null: FAIL: complexity (see above) 5) add methods to interfaces: If you meant s tatic methods, PASS: source-source (stuff methods into a $Methods inner class). If you meant traits, FAIL: extensive source-class also of code that implements it. (note how you can't implement scala traits in java code, for example) 6) add CICE: PASS. source-source. 7) tailcails. FAIL: JVM rewrite 8) permgenspace goes away: FAIL: JVM rewrite 9) message-based concurrency: N/A: That's library stuff; the only thing you can do is add closures and a few other primitives so you can write for it in a sane way, which 'add CICE' mostly covers. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "The Java Posse" group. To post to this group, send email to javaposse@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/javaposse?hl=en -~----------~----~----~----~------~----~------~--~---