Nope, my goal is to make intent clearer in the type signature.
However I'm interested to know what candidates would you suggest to improve
developer experience?
On Friday, July 6, 2012 1:08:02 PM UTC+2, KWright wrote:
>
> For example, converting said list to a list of strings:
>
> myList map { _ map {_.toString} getOrElse "(null)" }
>
>
> compared to a version using nulls
>
> myList map { x => if (null == x) x else x.toString }
>
>
> or if you just want to drop all the Nones:
>
> myList.flatten
>
>
> same again, using nulls:
>
> myList filter { _ != null }
>
>
>
> There's no hoopiness from using Options here, not so long as you have
> lambdas. Now compare a lambda-free version. I'm using Google guava here
> to maintain immutability characteristics and so keep it a like-for-like
> comparison. Also using both the enhanced-for notation and the tertiary
> operator to reduce the boilerplate as much as possible:
>
> ImmutableList.Builder<String> out = ImmutableList.builder<String>
> for(T x : myList) {
> out.add((null==x) ? "null" : x.toString)
> }
> out.build()
>
>
> Conclusion: If your goal is to avoid jumping through hoops, then picking
> on Option isn't exactly fertile ground. There are *much* better candidates
> for improving the developer experience.
>
>
> On 6 July 2012 11:41, Reinier Zwitserloot wrote:
>
>> I'd use annotations for this. If you give me an Option<T>, that's not TOO
>> bad, but if you give me i.e. a List<Option<T>>, you're pretty much forcing
>> me to jump through awkward hoops.
>>
>>
>> On Tuesday, July 3, 2012 10:27:57 AM UTC+2, Dale Wijnand wrote:
>>>
>>> I've found it very useful to design my API, making the intent evident
>>> from the type signature ("this method might not have a return value
>>> for you").
>>>
>>> Unfortunately it's a bit verbose and of limited use in Java than in Scala
>>> but it still beats ambiguity and having to resort to reading the Javadoc
>>> (or, even worst, making assumptions)..
>>>
>>> Dale
>>>
>>> On 2 July 2012 23:34, Reinier Zwitserloot wrote:
>>>
>>>> On Tuesday, June 12, 2012 8:52:30 AM UTC+2, Dale Wijnand wrote:
>>>>>
>>>>> The class Tobias is talking about (which I can't believe no
>>>>> one mentioned yet, thanks Tobias) is Optional: http://docs.guava-**li*
>>>>> *braries.googlecode.com/git-**his**tory/v12.0/javadoc/com/**google/**
>>>>> common/base/Optional.**html<http://docs.guava-libraries.googlecode.com/git-history/v12.0/javadoc/com/google/common/base/Optional.html>
>>>>
>>>>
>>>>
>>>> Nobody mentioned it, probably because it's frankly unusable in java. As
>>>> has been covered before, if you use Option, you _NEED_ closures all over
>>>> the place; there needs to be a way to map your type for ANY operation that
>>>> runs on a collection of said type, such that you can easily pass a
>>>> collection of Option<type> along with a mapping.
>>>>
>>>>
>>>>>
>>>>> 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-**libra**
>>>>>> ries.googlecode.com/git-**histor**y/v12.0/javadoc/index.**html<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/-/I7RrAp2aXQoJ.
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.