The class Tobias is talking about (which I can't believe no one mentioned yet, thanks Tobias) is Optional: http://docs.guava-libraries.googlecode.com/git-history/v12.0/javadoc/com/google/common/base/Optional.html
I also like the use of JSR 305 annotations, which I think work well for parameters, while using Optional for return types when not returning a value is an expected result (as opposed to an exception case, in which case I prefer to design the API to throw an exception). Dale On Monday, June 11, 2012 10:12:18 PM UTC+2, Tobias Neef wrote: > > Some of you may be interested that Google Guava also contains a Type to > represent optional values > http://docs.guava-libraries.googlecode.com/git-history/v12.0/javadoc/index.html. > > I use this approach a lot in the most recent java projects I have done. In > my own code this is a nice thing, but in contrast to the scala word we have > a lot of places in java which do not follow this pattern. As a result we > still have issues with NPEs from time to time. > > In the most recent version it is also possible to apply a function on the > Optional object using the transform function which is similar to the scala > 'map' behavior which was described by Dick. Because the > guava library is already used in a lot of places, some Java projects will > maybe start using this way of dealing with optional values. Another > advantage of guava is, that it uses the JSR 305 annotations for static type > checking which also helps to avoid nulls. This is especially helpful for > methods those methods of the Guava Collections or the Optional type which > do not allow null parameters. > > On Tuesday, June 5, 2012 1:19:52 PM UTC+2, KWright wrote: >> >> >> >> On 5 June 2012 11:05, Reinier Zwitserloot wrote: >> >>> On Monday, June 4, 2012 5:09:43 PM UTC+2, KWright wrote: >>>> >>>> >>>> This now has alarm bells going off in my head. These (as described) >>>> would only make sense if specified at both declaration AND use site, >>>> that's >>>> an awful lot of boilerplate and ceremony to be added! We already tried >>>> the >>>> same thing with checked exceptions, and you know how well that succeeded... >>>> >>> >>> Yes, you need to specify both at declaration and use. Like _ANY_ type. >>> Why does that have alarm bells going off in your head? >>> >>> String x = "Hello"; //site 1 >>> System.out.println(x); >>> >>> public void println(String in) { ... } //site 2 >>> >>> That's perfectly normal, no need for alarm bells. >>> >>> >> Not quite. In addition to the regular type system, we also have the >> shadow type systems of annotations and checked exceptions. This would be a >> third shadow system and it *would* add complexity. >> >> I suspect that Nullity in this form could be internally implemented >> through annotations to minimise the effort required, yet it would have to >> follow different rules in the presence of subtyping (more later). In >> practice, it would feel a lot more like generics - optional, erased, yet >> still part of the type system. >> >> Nullity is close to variance in this regard. With use-site (Java) or >> declaration-site(C#, Scala) approaches both being possible. If I could >> statically type Map<K!, V!> when *defining* the class, then using a >> guava-esque factory we might have: >> >> public static final Map<String, Integer> example = Map.of("a", 1, "c", 2) >> >> >> declaration-site nullity. No extra ceremony or boilerplate in the client >> code :) >> >> >> >>> >>>> Then there's the issue of subtyping and the LSP to consider. >>>> >>> >>> No, the 4-nulls thing actually solves this. Technically, you could treat >>> [dunno-null] as "? extends String! super String?" if you really wanted to, >>> but you can simplify matters considerably by taking nullity out of the type >>> inheritance system. String is a type, and where inheritance is concerned, >>> String is just String, and the nullity of it does not enter into the >>> equation whatsoever; String, String!, String?, String[raw], it's all the >>> same to the type system. As in, == equals - the exact same. If there's a >>> mismatch between a type's nullity state and the operation you do on it, >>> then the compiler will emit an error (you're treating a could-be-null as if >>> it's never-null, or you're passing a could-be-null to something that wants >>> a never-null) or a warning (you're doing null-checks on a never-null). This >>> errors-and-warnings system is like a compiler plugin, it has no actual >>> effect on the meaning of any of the code nor of how any of the code is >>> compiled, the ONLY thing that it could possibly cause is errors and >>> warnings. It's analogous to @Override in that sense. Just compiler-checked >>> documentation is all. >>> >>> If you want to be technical about it, nullity is its own tiny little >>> non-expandable strictly and statically defined hardcoded type system. The >>> upshot is that it's all very easy to reason about and there's no risk of >>> conflicting with existing specs. For example, you cannot write both: >>> >>> public static void test1(String? foo) {} >>> >>> public static void test1(String! foo) {} >>> >>> in the same file, but that would have been possible if these were >>> actually different types. >>> >> >> Here's a thought experiment, I have: >> >> public class Foo { ... } >> public class Bar extends Foo { ... } >> public void doSomething(List<? super Bar!> xs) >> >> >> What would be a valid argument to doSomething? >> >> List<Bar!> >> List<Bar> >> List<Foo!> >> List<Foo> >> >> >> This is definitely something outside the current spec, so adding it would >> be a mammoth task - possibly the same order of magnitude as both generics >> and annotations. >> >> >> >>> >>> >>>> It's easy enough to say that String is a subtype of both String! and >>>> String?, but it massively changes the Java spec (which only allows >>>> subtyping through inheritance). It looks like we'd be in a similar >>>> position to having Array[Object] being a supertype of Array[T], and the >>>> problems that caused. Then you still have the midas problem if you need >>>> to >>>> pass a String where a String! is demanded. And how does it work inside >>>> collections and generics (especially wildcarded ones)? and through >>>> reflection? >>>> >>>> >>> See above - no changes needed whatsoever. There is also no midas problem >>> here; just because I use this equivalent of Option somewhere does NOT mean >>> my code is going to end up with every type in every parameter replaced with >>> Option<T> everywhere! Generalized APIs such as List will most likely roll >>> with dunno-Ts everywhere but this is completely transparent to ALL >>> nullities: You can pass never-nulls, could-be-nulls, and dunno-nulls to >>> such an API and it would all work. Maybe you don't understand the midas >>> problem? With Option, then I start having List<Option<X>> everywhere, >>> severely complicating my API documentation and requiring me to also start >>> using option. The entire _point_ of the 4-nullity concept is that null >>> safety is transparent yet compile-time checked. Contrast to Option, which >>> is compile-time checked but not transparent, and java's system, which is >>> transparent but not compile-time checked. >>> >>> >>> >> public String! turtleA() { return turtleB(); } >> public String turtleB() { return turtleC(); } >> public String turtleC() { return ...; } >> ... continue until you run out of turtles ... >> >> >> Every method below the top one now has to be changed to return a String! >> (unless you provide some form of nullity cast). Is this not the essence of >> the midas problem? >> >> >> >>> >>> >>>> >>>> I have no solution for this dilemma, other than introducing an IDE >>>>> which exceeds the ascii character set for symbols, and which introduces >>>>> certain keyboard shortcuts to change nullity. But that's an entirely >>>>> different can of worms. >>>>> >>>>> >>>> Not just the IDE. You have javadoc, static analysis tools, code >>>> coverage, etc. etc. >>>> >>> >>> Nope, those can just use the long-form ASCII symbol that is in the >>> actual source file. It's fine in all such tools, but where it gets real >>> tedious is in day-to-day edit work, but if your IDE can let you enter the >>> appropriate nullity state very easily, and render it in an unobtrusive >>> manner, you've gotten your 90% in and it's fine then. >>> >>> >>>> >>>> It's a bold solution, to be sure. But the work and complexity required >>>> to retrofit it look more complicated than Option[T] at this stage. That's >>>> before you even consider composability. >>>> >>> >>> >>> Hah, just... no. It is not possible to retrofit java to Option<T> >>> because that is not transparent; APIs are set in stone, you can't change >>> them. 4-nullities is transparent which means that's actually an option, al >>> though it is very complex. >>> >>> Sure. Retrofitting is *always* harder than getting a clean design in >> the first place. This is why C# forked the collections when they added >> generics. I also consider Scala's collections to be a similar fork - not >> just adding option awareness, but also immutability at the root of the >> hierarchy and all sorts of monadic goodness. Other such examples are >> Google Guava and the totallylazy library. This can happen at the library >> level without requiring sweeping changes to the type system in the language >> spec. >> >> -- You received this message because you are subscribed to the Google Groups "Java Posse" group. To view this discussion on the web visit https://groups.google.com/d/msg/javaposse/-/JKzmRfsviU0J. To post to this group, send email to [email protected]. 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.
