Hey,
I was just taking a shower when it came to me…
What if we could use to-functions in Kotlin like Boxing in Java?
So what do I mean by to-functions? I’m one of those persons who doesn’t like to use the toDouble() of toFloat() functions every time when I’m working with floats and the Java.lang.Math class.
My suggestion to the problem:
Using a similar approach like the toString, if an object is given but a string expected. The toString gets called automatically.
Small example:
data class Test(val id: Int, val name: String)
val test = Test(1, "Max")
println(test)
I would like to see a ‘Smart boxing’ feature or something called like this in the next version of Kotlin, where the compiler is automatically calling the fitting to-function to convert the given object into the appropriate type
Example:
val supplier = IDSupplier()
data class User(val id: Int = supplier.nextInt(), val displayName: String, val username: String)
data class Person(val firstname: String, val lastname: String) {
fun toUser() = User(displayName = firstname, username = "${firstname}_${lastname}")
}
fun login(user: User) { /* do Something */ }
val john = Person("John", "Doe")
login(john) // Converting to 'User' using the 'toUser'
println(john) // Converting to 'String' using the 'toString' (Is possible in current build)
I would like to hear what you think about my idea and would like to see this feature in future Kotlin builds.
Great idea!
Nice, but it’s not really Kotlin like…
IntelliJs autokorrection is enough
Maybe not so great…
0voters
Thanks, @KotlinTeam for creating such a beautiful language
Alexander Piglmann
Firstly, I think you are confusing terminology. Boxing refers to turning a primitive to an object wrapper version (e.g. Java int to java.lang.Integer), unboxing is the opposite, and autoboxing is when it happens automatically (e.g. when Java needs a primitive in a place for only objects). Kotlin does autobox as needed internally.
Secondly, what you are talking about with, e.g. having to use toLong on an Int, is widening and Java supports it automatically while Kotlin does not. Other non-widening conversions (e.g. toInt on a Long) are lossy and require explicit casting/converting in basically any language.
Finally, what you seem to be suggesting is very similar to what Scala calls implicit conversions. Rust has a similar concept with the From/Into traits, but at least they’re not (usually) implicit. It is widely accepted, even by languages that have implemented it, that implicitly converting between types has more costs than benefits. Compared to the many costs concerning reading, surprising behavior, ambiguity etc, the only benefit is saving someone from explicitly invoking a conversion function. You could even argue requiring explicit invocation of the conversion function is ideal to signal intent at the call site.
toString is a special case often for convenience, or in Kotlin’s case, likely due to their JVM interop commitment.
The way I see it is that you indeed want automatic conversions basically the way C++ operatorType() works. It has many many drawbacks (but when judiciously used can improve code quality - or make it dramatically worse when not done correctly).
After @cretz commentary, I looked more into the implementation Rust provides and I have to say, even if I would like the possibilities this feature gives, I don’t really know how to implement it in a completely type-safe way.
I guess I will keep using read-only properties with the conversion contained in its getter
To save typing two chars ( and )? No biggie of course, but in general as a caller, I would expect instantiation of a new type to be a function and I would also expect conversion to be a function. People might expect properties to be mostly return the same value on successive requests (even if lazily memoized after the first invocation).
What you are proposing is called implicit casts and is already done in Scala and Groovy. I suggest to look for Groovy implementation for clarity. It defines a specific method (it would be operator in kotlin), which is used when one wants to try to cast object of one type to another type and could be overwritten. The problem is that while it looks good in dynamic groovy, it is terrible for static kotlin. The idea of static typing is that you always know what is the type of the expression without random guesses.