Allow interface default toString implementation

Brandon Mintern mintern at everlaw.com
Thu Jun 12 00:09:25 UTC 2014


On Wed, Jun 11, 2014 at 8:57 AM, Brian Goetz <brian.goetz at oracle.com> wrote:

> This recently came up on StackOverflow too:
>
> http://stackoverflow.com/questions/24016962/java8-why-
> is-it-forbidden-to-define-a-default-method-for-a-method-
> from-java-lan/24026292#24026292
>

To be fair, that was me. It seemed like a discussion more appropriate for
the mailing list, so I moved it here.

What you're saying is "OK, I accept that its outright dangerous to inherit
> hashCode and equals from interfaces, but we should do something different
> for toString."
>

Well now you're putting words into my mouth. I didn't say anything like
"outright dangerous." I just noticed that the strongest argument in the
original discussion was against hashCode/equals, and I'm happy to avoid
arguing a point that has been clearly decided. I was hoping that I might be
able to give a good case for treating toString differently.

So this would be, basically, designing a special-purpose language feature
> for giving special inheritance behavior to one method.  Seems a poor
> return-on-complexity.
>

When you say special-purpose, are you referring to the idea of a toplevel
interface, or something else?

Additionally, while this approach might magically make toString inheritance
> work well in *your* library, the reality is that toString shares the
> essential feature with equals and toString that it is primarily about
> state, and state resides with the class, not the interface.  You happen to
> have built a library where you've sufficiently virtualized the state, but
> your library is the exception, not the rule.  Making for an even worse
> return-on-complexity.
>

I'm sorry, but I don't understand the animosity here. I was trying to open
up a discussion, and point out a specific use case that I thought
illustrated the point of my suggestion reasonably well. I'm not trying to
look for the solution to all of my problems. This is a much colder
reception than I expected; I'm not trying to step on anyone's toes here.


> So far, the simple rule is looking pretty good to me.


What simple rule would that be?


If something like this is not open to discussion, then why is this an open
mailing list that is still accepting new subscribers? As an interested
community member, one who has been following Java 8 developments for a year
and is driving adoption at my company, it's pretty disheartening. You may
as well take the discussion behind closed doors and stick to press releases.


On 6/10/2014 6:43 PM, Brandon Mintern wrote:
>
>> I know that I'm late to the party, but I want to revisit an idea that was
>> proposed over a year ago:
>>
>> http://mail.openjdk.java.net/pipermail/lambda-dev/2013-March/008435.html
>>
>> I read the thread and I appreciate the concerns in regards to
>> equals/hashCode. I sympathize especially with Brian's 4th point:
>>
>> It's brittle.  Methods like equals are really fundamental; you don't
>>
>>> want a classes equals() behavior changing out from under you when a
>>> library is rev'ed and someone adds an equals() implementation to some
>>> interface that you indirectly inherit from nine levels away.  But this
>>> is exactly what would happen if someone added an equals() method to an
>>> existing interface, if its subtypes didn't provide their own equals().
>>>
>>
>>
>> As I begin converting our codebase to take advantage of JDK 8's excellent
>> features, the one I miss most so far is the ability to provide an
>> interface
>> default implementation of toString.
>>
>> For a concrete example, we use a JSON-formatted Lisp-like query language
>> for converting a complicated frontend search across various properties of
>> searchable objects into a backend tree structure that eventually performs
>> the search in Lucene, SQL, etc.
>>
>> Each unique searchable property has a concrete class that specifies things
>> such as where and how to search for the property. Of course, there is a
>> toplevel interface -- called Property -- that defines the core
>> functionality. The relevant method for this discussion is String toJson();
>> we require that every property can be converted back to its JSON
>> representation.
>>
>> Of course, now that we have a meaningful String representation of each
>> object, we should use it for toString(). In fact, it would be extremely
>> convenient to be able to add this to Property:
>>
>>      @Override
>>      default String toString() {
>>          return toJson();
>>      }
>>
>> Our alternatives, instead, are to either add the toString method to every
>> single property, or to create some base class:
>>
>> abstract class PropertyToString implements Property {
>>      @Override
>>      public String toString() {
>>          return toJson();
>>      }
>> }
>>
>> We opted to go this PropertyToString route, as the boilerplate of adding
>> those 4 lines to every single property was a bit painful. This is an ugly
>> solution, though, as some of the properties have other base classes; this
>> abstract class has to be injected into the top of each such
>> mini-hierarchy,
>> and now we're changing our class hierarchy just to get some
>> debugging/logging conveniences.
>>
>> An alternative, which I think is still possible going forward, is to move
>> toString() out of Object so that it *can* be a default method. I realize
>> that it makes use of getClass and hashCode, so it would need to involve a
>> hierarchy like this:
>>
>> public interface Objects {
>>      ...
>>      Class<?> getClass();
>>      int hashCode();
>>      boolean equals(Object obj);
>>      default String toString() {
>>          return getClass().getName() + "@" +
>> Integer.toHexString(hashCode());
>>      }
>>      ...
>> }
>>
>> public class Object implements Objects {
>>      ...
>>      @Override
>>      public final native Class<?> getClass();
>>      @Override
>>      public native int hashCode();
>>      @Override
>>      public boolean equals(Object obj) {
>>          return (this == obj);
>>      }
>>      ...
>> }
>>
>> All interfaces would implicitly extend Objects. Because Object overrides
>> hashCode and equals, default interface implementations of those methods
>> would be moot. But because Object does not override toString(), it gives
>> interfaces a chance to provide a default implementation in those cases
>> where it makes sense to do so.
>>
>> Was there any discussion of an approach like this?
>>
>> Thanks,
>> Brandon
>>
>>


More information about the lambda-dev mailing list