_This issue was originally filed by domi...@google.com_
I have methods that I would like to return multiple values from. The two ways I could do this would be to return a tuple, or if output parameters were available I could use those.
I'd prefer output parameters to make it easier to optimize away copies of object references.
For example
class Sphere {
bool Intersect(Ray ray, out double distance);
}
main {
Ray ray;
double distance;
if (Intersect(ray, out distance)) {
....
}
}
or
class Sphere {
tuple<bool, double> Intersect(Ray ray);
}
main {
Ray ray;
tuple<bool, double> result = Intersect(ray);
if (result[0])
double distance = result[1];
....
}
}
_This comment was originally written by [email protected]_
_Removed Type-Defect label._
_Added Type-Enhancement, Area-Language, Triaged labels._
There are some other possibilities for output parameters, using features already in the language. The closest to "out parameters" just uses closures, passing a setter of distance:
double distance
if intersect(ray, (out){distance=out;}) {
... distance ...
}
The closure and variable closed over can be in a higher scope, and outside loops, if avoiding object creation is important:
double distance;
Function distance_out(out) {distance = out;}
while (looping) {
foo(input, distance_out);
... distance ...
}
Or you can pass a handle to a double:
var distance = new Out<double>;
if (intersect(ray, distance)) {
... distance.val ... distance.val ..
}
You could even write distance = distance.val after the function call.
Alternatively, pass in the calculation that needs multiple values as a callback:
sphere.intersect(Ray ray, (Bool intersects, Double distance) {
if (intersects && distance > 1) {
myLocalQueue.add(distance);
any other calculations ...
});
Map or list literals can be passed back. If you want to avoid object creation, you can use a static object, or pass one in.
var result = intersect(ray);
if (result[0]) {
... result[1];
}
var result = intersect(ray);
if (result["intersects"]) {
... result["distance"];
}
var out = new List(2)
if intersect(ray, out) {
... out[0] ... out[1] ...
}
_This comment was originally written by domi...@google.com_
Thanks for the comprehensive feedback. This bug can probably be closed.
It would be interesting to see a blogpost/article on this as there are so many options and I imagine each has pros and cons.
I'm closing this per the submitter's request. I will note that literal lists make it quite easy to return multiple values. Or passing in mutable list or map. I don't think we'll ever add out parameters.
_Added WontFix label._
_This comment was originally written by mtu...@getccna.ru_
I propose reopening this issue. I think all proposed methods have significant disadvantages:
I think there should be a way to pass the tuples of certain dimensions out of the function and ability to destructure them.
For example:
[User, bool] createOrUpdate(String name, id int) {
...
}
User user, bool created = createOrUpdate("admin", 2);
What do you think?
This makes me (and I bet many others) very sad - tuples are one of the most useful sugar present in Python, Ruby, Go, etc.
One super useful case is boolean that also retuns an error code/message on error - go have pretty nice pattern, in ruby I could use:
res, msg = isConditionValid(foo);
print msg if !res
in Dart I need specialized class for each case. There are at least two widely used patterns used as a workaround:
1) output parameters - just pass mutable class (like list of error message) to param
2) returning null for ok, string with message otherwise.
I bet there is way more code that would be much improved if this was allowed.
Re-opening this for consideration.
Fuchsia would very much like this feature.
The new language repository is tracking this feature at https://github.com/dart-lang/language/issues/68; presently 144 up-votes and a more recent and lively discussion; I proposed we close this in favor of that.
Most helpful comment
Re-opening this for consideration.