I really hopped that Kotlin will have elegant support for multiple return type functions. Tupples (now deprecated) and data classes seem more like workarounds/hacks, similar to using wrapper class in java.
Pair and Triple are very usefull classes that can be used for this, but in esence thats just built in kind of wrapper class, isn't it? It's still single return value.
Would’n it be nice to have something like this:
fun calculateValues(input:Integer) : String, Long {
// do some calculation
return “some string”, 5;
}
val name:String, id:Long = calculateValues(input);
Is there any reason why this can’t be easy implemented, or is there some other argument against syntax like the one I suggested?
Couldn’t kotlin automatically convert the returned tuple into a data class with component1, component2, etc and return that? This would work so great together with Destructuring Declarations and solve such an age old problem in programming.
fun foo(): String, Long{
return "bar", 5;
}```
```mean this:
fun foo(): Pair<String,Long>{
return Pair("bar",5);
}```
I recently faced this problem in Java where a new point with x,y has to be returned by a function executed inside a draw() method. The disaster in Java is that returning a new Point object that only contains x and y numbers allocates quite some memory that is discarded after the method returns and there are many of these points created on each frame. A lot of memory allocations not needed for simply returning two values of the same type.
It will be much more efficient if Kotlin could recognize a tuple of the same type and create the most optimal data structure (plain old array?) to pass the values, so no extra memory than needed is allocated for the return values.
Is the current boxing/unboxing of return values in Kotlin memory efficient?
Why would a Tuple or an Array be more memory efficient than a java.awt.Point? A point is a specialised form of a generic Tuple, so I don’t see why that would be more efficient.
Besides, I think the clarity of the API is far more important, also from the Java perspective, than these kind of optimisations. An array as return type would completely hide that clarity.
I don’t think a tuple is more efficient than an Array but I though an Array would be more efficient than an object, apparently, that’s not the case. Why I’m pointing out is that all of them are less efficient than returning the values because, in addition to the size of the values you return from a method, the wrapper object always has some memory overhead.
Readability is very important, but simple syntax sugar can optimize how return values are packed and unpacked in the most memory efficient way by the language and the compiler.
Yes not having a wrapper object is more efficient but such operations must first be supported by bytecode, which I don’t think it is. Project Valhalla might help there. There isn’t a good representation in Java either so that will always lead to incompatible code.
So if you really need performance now you can either cache and reuse your objects/tuples or in case of your point example pack two ints in one long.
You’re right bytecode does not support return of more than one value (there are type specific return instructions - Chapter 2. The Structure of the Java Virtual Machine). Value types may provide (limited) relief. At the same time, there is nothing stopping the JVM from deciding to allocate your temporary on the stack and just returning it that way - the JVM can do whatever it wants as long as it preserves the semantics of the code. In fact, for a temporary the analysis needed to be able to do it would be rather simple, so something likely to be optimized (you’d have to look at the generated machine code to be sure).
Multiple return values is the one feature of Groovy that I really miss when I switch from working in Groovy for a bit back to Java. It allows returning arbitrary types in a List and then provides syntactic sugar for assigning the List values to variables
Thanks for the pointer to that page. I could have swore I read the entire reference manual, but for some reason I hadn’t seen the destructuring declarations page. I must have accidentally skipped it.
I have been using something like Pair<T,U> in the past already… It saved me from creating just a class for that… Obviously, when there wasn’t a lost in the semantic of the API (Better having Point than Pair<double,double> when having the Point concept makes sense in the whole API).
But I missed the ability to at least assign new names to the members. “VariableName.a” sometimes is obscure when reading the code.
Swift language, from Apple, already has this capacity and it’s quite helpful…
func getTime() -> (hour: Int, minute: Int,second: Int) {
let hour = 1
let minute = 2
let second = 3
return ( hour, minute, second)
}
let time = getTime()
time.hour
You can always use data classes, they have destructuring declarations, naming and even default parameters. The syntax for data class is short and it much more transparent than the one from swift.
Yes, but that would the case of creating a Type (with its associated [data] class) because it makes sense for the clarity of your API (not even talking about performance).
And if you already had a Data Class maybe deconstructing the instance wouldn’t add much…
I was referring to those cases where using Pair, Tuple… And not Data Class, made sense. For those, Swift approach is much better IMHO.
That’s halfway there, but it’d also be nice for (x: Int, y: String, z: Thing) to be an alias for an anonymous data class in certain contexts. Sometimes (especially in the case of multiple returns) a data class is defined entirely by the data it contains just as lambdas are defined entirely by the structure of what they do (their input and output) and creating an explicit class for it not only is unwanted boilerplate, but having decentralized data classes the same as decentralized Lambdas (in that data class A(x:Int) is not the same as data class B(x:Int) but (Int)->Unit means the same thing everywhere without anything having to define it first) might actually have some use cases beyond just multiple return syntax.