Here's something I've been pondering, and I'm curi...
# language-proposals
b
Here's something I've been pondering, and I'm curious what thoughts you guys might have. (I'm looking at this from a JVM perspective) What if
equals()
,
hashCode()
, and
toString()
were removed from the
Any
class? (And maybe moved into an interface like
Data
, or just left to be added as operator functions) For a majority of the classes I write, these methods aren't implemented, and it would never make sense for them to be used. The default implementation of
equals()
only checks for identity, so === should be used instead in all cases, and
toString()
returns a practically useless String like
"MyClass@6ea12c19"
. I couldn't think of a good reason for them to be included in
Any
, and Googling around I couldn't find anything on the thought process behind including them. (I am still curious to know if there was a reason) For interop with the JVM, they could be treated the same as the
java.lang.Object
class's
::finalize
,
::clone
, etc. methods, which weren't carried over to Kotlin's
Any
. (but can still be implemented without being marked with
override
) I don't think bytecode compatibility would be a problem, since the methods still exist on the JVM. Existing usages of
Any.equals(...)
on classes that don't implement
equals
could still compile, but with a warning that
===
should be used. The same for
Any.toString()
, with a warning saying that the value might not be useful. For code compatibility of existing usages, extension functions could be added to the standard library, similar to this for `toString()`:
Copy code
fun Data?.toString() = this?.toString() ?: "null"

@Deprecated("Does not have a useful String representation")
fun Any.toString() = (this as java.lang.Object).toString()

@Deprecated("Does not have a useful String representation")
fun Any?.toString() = this?.toString() ?: "null"
The only incompatible thing I can think of is the override modifier on these functions in existing classes. Allowing
override
on them but giving a warning that it's not needed could suffice.
i
Generic data structures, like
List
,
HashMap
, or at least some of their operations rely on these methods being available in any generic type.
l
Would also break `Sequence`s and `Flow`s operators like
distinctUntilChanged
. You need to take that into account. Please, reply in this thread if you find a solution to not break things while making Kotlin better in a way. BTW, did you take the inspiration from Swift?
b
Those certainly highlight a big issue with this idea... especially for backwards compatibility. I think I may have taken some inspiration from Swift without realizing it, since I did use it in an iOS class a while ago. Swift does show how those classes could have been implemented differently if Any didn't have `equals()`/`hashCode()`. The member function
List.contains()
could be implemented as the extension function
List<T : Equatable>.contains(element: T)
that uses
.equals()
, with an overload
List<T>.contains(element: T)
that uses
===
. (And similarly for the other methods/classes that assume
Any
has
equals()
and
hashCode()
I do think this approach has some benefits, but I'm starting to think that it takes away from the pragmatism and conciseness that comes with every type having `equals()`/`hashCode()`/`toString()` (which I think is a problem that Swift suffers from in general, with implementing language features in an ideal way instead of a pragmatic way) tI think I may have taken some inspiration from Swift without realizing it, since I used it in an iOS class a while ago. Swift's approach does show how
e
👍 That’s a good summary in design philosophy differences between Swift and Kotlin