https://kotlinlang.org logo
Title
j

Jonathan Olsson

05/13/2022, 12:45 PM
Is it considered an OK practice to rely on
toString()
for non-debugging/non-logging purposes in a situation like this:
value class AccessToken(private val s: String) {
    override fun toString(): String = s
}

val header = "Bearer $accessToken"
Given that inline classes most often wrap primitive-ish types, in my mind it falls into the same category as
Long.MIN_VALUE.toString()
. Wdyt?
f

Fleshgrinder

05/13/2022, 12:47 PM
There are no rules for this. Kotlin inherits the
toString
logic from Java where there is only one way for objects to auto-format themselves. In Java the function is not used consistently, think
UUID
which prints itself, giving you good reason to do so as well. Other languages (e.g. Rust) have support for different self-formatting strategies, but here we don't. I would go with it.
👍 2
s

Sam

05/13/2022, 12:48 PM
For value types, I like this approach and use it a lot. I probably wouldn't use it for a more complicated data class with more than a couple of fields, though.
👍 2
j

Jonathan Olsson

05/13/2022, 12:58 PM
I have sort of considered instances where the difference between the thing the class represents, and the string representation is just a matter of slapping a couple of
"
around it an acceptable compromise. Agree with – let's say problematic – inconsistency from Java.
LocalDate#toString
anyone? (Outputs this date as a
String
, such as
2007-12-03
)
e

ephemient

05/13/2022, 1:18 PM
toString()
is a mixed bag. • for some types (such as Double) it produces something that looks like a representation of the value in source code or can be parsed back into the same value • for some other types (such as most collections) it produces something which is a human-like representation of the object, but is neither the same as the source representation nor can be parsed mechanically. • for some other types (such as Kotlin lambdas) it produces the type name but nothing to distinguish different values • and the default is type + identity hashcode
yeah, Rust's separation of Debug and Display traits (along with #[derive]) is helpful. it's missing something like Haskell's Show/Read typeclasses though, which are conventionally expected to produce and parse a representation equivalent to how the value would be written in the source. but either way, Kotlin doesn't really have the ability to retrofit that onto Java
I would generally override toString() to whatever the most predictable thing is. for data-like types, that would usually follow Kotlin's data class style; for value classes which are used as strongly-typed aliases, the underlying type's toString() is a fine choice
👍 1
f

Fleshgrinder

05/13/2022, 2:23 PM
I actually think it could be retrofitted. Debug, Display, Show, Read, ... all of these are just interfaces that can be interpreted as needed by anything we feed it into. For retrofitting the question would be: which one maps to
toString
. 🤔
e

ephemient

05/14/2022, 3:27 AM
List<T>
is
Display
only if
T
is `Display`; this isn't something that can be expressed in Kotlin. it only works for
toString()
because every type implements it (ditto
equals
,
hashCode
which belong to traits/typeclasses in other languages that cannot be expressed in Kotlin, not that there any safe and interoperable way to do so on the JVM even if Kotlin came up with something)