[threeten-dev] lambda + threeten

Brian Goetz brian.goetz at oracle.com
Mon Dec 3 10:36:04 PST 2012


Yes, this was an extensively discussed point in the EG.  It came down to 
consistency in philosophy and user model.

The philosophy argument is: default methods are designed for evolving 
interfaces.  Yes, they can be used as a form of traits-lite, which is 
fine as far as this goes (and it goes pretty far), so long as you don't 
go all wishful-thinking on us and pretend they are full-blown traits. 
The desire to let interface methods provide implementations for Object 
methods is really a way of saying "but I want this to be traits."  As 
long as you think about it as "glass 98% full" rather than "glass 2% 
empty", you're fine :)

The user-model argument is: we have dramatically reduced the pain 
surrounding reasoning about multiple inheritance by adopting some very 
simple rules, the foremost of which is "class methods always win."  If 
there is an implementation on the class hierarchy, we don't even look at 
the interface hierarchy.  Not only does this guarantee compatibility, it 
is very simple to reason about.  This means that anything inherited from 
Object wins.  We could have, of course, changed the rules, but that 
would have made the feature more complicated to address a use case that 
is already sliding down a slippery slope; attempts to define Object 
methods in interfaces assumes that you are using those interfaces as if 
they can only be singly inherited.  The reality is that methods like 
toString, equals, and hashCode are tightly bound to the object's state, 
and the state lives in the class, not the interfaces.  Unless we could 
enforce that only one interface was managing the state, such a feature 
would cause more trouble than it solves.

Default methods may reduce the need for abstract classes, but they don't 
eliminate it.  Fields are one reason we still need them; Object methods 
are another.

Glad to hear the conversion was mostly painless!

On 12/3/2012 1:22 PM, Xueming Shen wrote:
>
> I experimented the lambda repo + threeten repo to see how much we
> might need to do when lambda stuff gets into the master. While it still
> took couple hours to (lots of emacs editing...) sort everything out, it
> appears it can be done smoothly in hours.
>
> The only issue (not straightforward/simply copy/paste) I found is that
> three j.l.Object methods equals/hashCode/toString can NOT be
> default-method-ed in ChronoLocalD/DT/ODT/ZDT. It appears to be not
> allowed. Sorry, if this is a well-known spec that I'm not aware of , I'm
> a lambda newbie:-) they need to be simply  defined as @override
> method and the (default) impl need to go into their corresponding impl
> classes.
>
> I'm not sure if all those utility methods in "jdk8Methods" have been
> in jdk8, so I did not touch them this time. But at least so of them
> are there already. Should we just migrate?
>
> Here is the java doc for the combined threeten_lambda
>
> http://cr.openjdk.java.net/~sherman/jdk8_threeten/api_lambda/
>
> The webrev/diff for the changes, if interested.
>
> http://cr.openjdk.java.net/~sherman/jdk8_threeten/defaultM
>
> And yes, I have my first lambda + threeten test, and trying Stephen's
> fancy functional interfaces With/MinusAdjuster :-)
>
> I might write a blog for our first lambda+threeten repo/binary.
>
> -Sherman
>
> --------------------------------------------------------------------
>          LocalDateTime now = LocalDateTime.now();
>          Random r = new Random();
>
>          DateTimeFormatter fmt =
>              DateTimeFormatters.pattern("yyyy-MM-dd HH:mm:ss [EEEE]");
>
>          int total = 100;
>          int days = 2;     // days to delay
>          int minMon = 2;
>          int maxMon = 6;
>
>          Streams.repeatedly(total, () -> (now.withYear(2012)
>
> .withDayOfYear(r.nextInt(365) + 1)
>                                              .with(SECOND_OF_DAY,
> r.nextInt(86400))))
>                 .sorted((d1, d2) -> d1.compareTo(d2))
> //             .filter(d -> (d.getMonthValue() >= minMon &&
> d.getMonthValue() <= maxMon))
>                 .tee(d -> {System.out.printf(" %-30s ", fmt.print(d));})
>                 .map(d -> (d.with(dd -> (dd.with(EPOCH_DAY,
> dd.getLong(EPOCH_DAY) + days)))))
>                 .tee(d -> {System.out.printf(" -->   %-30s ",
> fmt.print(d));})
>                 .map(d -> (d.minus(dd -> (dd.with(EPOCH_DAY,
> (dd.getLong(EPOCH_DAY)- days))))))
>                 .forEach(d -> {System.out.printf(" -->   %-30s%n",
> fmt.print(d));});
>


More information about the threeten-dev mailing list