Return multiple values from function
Asked Answered
B

10

126

Is there a way to return several values in a function return statement (other than returning an object) like we can do in Go (or some other languages)?

For example, in Go we can do:

func vals() (int, int) {
    return 3, 7
}

Can this be done in Dart? Something like this:

int, String foo() {
    return 42, "foobar";
} 
Biotype answered 26/7, 2017 at 11:58 Comment(4)
I don't know if any languages truly return multiple values. Python, which uses the same syntax as you used above, returns a tuple, which is just a simple object. I suspect Go is similar.Spherical
Relevant: groups.google.com/a/dartlang.org/forum/m/#!topic/misc/…Spherical
Lua can also return multiple values.Sidnee
These now exist in Dart 3.0: https://mcmap.net/q/174752/-return-multiple-values-from-functionStatism
B
185

Updated for Dart 3.0

In Dart 3.0 records can be used

(int, String) foo() {
    return (42, "foobar");
} 

void main() {
  var (a,b) = foo();
  print("int: ${a}");
  print("String: ${b}");
}

Original answer

Dart doesn't support multiple return values.

You can return an array,

List foo() {
  return [42, "foobar"];
}

or if you want the values be typed use a Tuple class like the package https://pub.dev/packages/tuple provides.

See also either for a way to return a value or an error.

Bull answered 26/7, 2017 at 13:36 Comment(6)
+1 for tuple which does most closely what Go does with its built-in. It's just not built into Dart, presumably not much needed yet and they keep the language as light as possible.Gustaf
There were other priorities. Features like this were discussed several times. Currently it's about Dart 2.0 with strong mode and generic functions and a lot of preparation for faster iteration after 2.0 (unified front end, kernel). Next hopefully non-nullable types and others. I prefer to not add too many features, but I have full trust in the Dart team to make the right decisions.Dwarf
Also either is dart 2.0 INCOMPATIBLE.Brogue
Change the return type to List<dynamic> or List<Object>Dwarf
@Brogue For a Dart 2.0 compatible Either implementation, see dartz.Lithic
This answer is no longer true now that Dart 3 has records.Trombone
G
27

I'd like to add that one of the main use-cases for multiple return values in Go is error handling which Dart handle's in its own way with Exceptions and failed promises.

Of course this leaves a few other use-cases, so let's see how code looks when using explicit tuples:

import 'package:tuple/tuple.dart';

Tuple2<int, String> demo() {
  return new Tuple2(42, "life is good");
}

void main() {
  final result = demo();
  if (result.item1 > 20) {
    print(result.item2);
  }
}

Not quite as concise, but it's clean and expressive code. What I like most about it is that it doesn't need to change much once your quick experimental project really takes off and you start adding features and need to add more structure to keep on top of things.

class FormatResult {
  bool changed;
  String result;
  FormatResult(this.changed, this.result);
}

FormatResult powerFormatter(String text) {
  bool changed = false;
  String result = text;
  // secret implementation magic
  // ...
  return new FormatResult(changed, result);
}

void main() {
  String draftCode = "print('Hello World.');";
  final reformatted = powerFormatter(draftCode);
  if (reformatted.changed) {
    // some expensive operation involving servers in the cloud.
  }
}

So, yes, it's not much of an improvement over Java, but it works, it is clear, and reasonably efficient for building UIs. And I really like how I can quickly hack things together (sometimes starting on DartPad in a break at work) and then add structure later when I know that the project will live on and grow.

Gustaf answered 22/11, 2017 at 17:45 Comment(2)
A common patter from functional programming for that use case is pub.dartlang.org/packages/eitherDwarf
+1 for not reinventing the wheel, let's use a package, because next thing is that someone wants a 3 element tuple, then there's Tuple3, and so on...Redhanded
W
18

Create a class:

import 'dart:core';

class Tuple<T1, T2> {
  final T1 item1;
  final T2 item2;

  Tuple({
    required this.item1,
    required this.item2,
  });

  factory Tuple.fromJson(Map<String, dynamic> json) {
    return Tuple(
      item1: json['item1'],
      item2: json['item2'],
    );
  }
}

Call it however you want!

Tuple<double, double>(item1: i1,item2: i2);
or
Tuple<double, double>.fromJson(jsonData);
Worriment answered 23/7, 2020 at 18:9 Comment(0)
H
7

You can create a class to return multiple values Ej:

class NewClass {
  final int number;
  final String text;

  NewClass(this.number, this.text);
}

Function that generates the values:

 NewClass buildValues() {
        return NewClass(42, 'foobar');
      }

Print:

void printValues() {
    print('${this.buildValues().number} ${this.buildValues().text}');
    // 42 foobar
  }
Honeyhoneybee answered 12/5, 2021 at 15:27 Comment(0)
C
4

Dart is finalizing records, a fancier tuple essentially.
Should be in a stable release with Dart 3.
It's already available with experiments flags.

Claim answered 20/11, 2022 at 19:50 Comment(2)
A month, you say?Salk
@Salk Seems executives pushed it back for Google IO which was a couple days ago so it's now available on stable. Making a package with examples soon. Might see this pattern with macros too.Claim
T
2

As other answers have noted, Dart 3.0 adds records, which can be used to return multiple values in a type-safe way.

For earlier versions of Dart, the proper way to return multiple values would be to store those values in a class, whether your own custom class or a Tuple. However, defining a separate class for every function is very inconvenient, and using Tuples can be error-prone since the members won't have meaningful names.

Another (admittedly gross and not very Dart-istic) approach is try to mimic the output-parameter approach typically used by C and C++. For example:

class OutputParameter<T> {
  T value;

  OutputParameter(this.value);
}

void foo(
  OutputParameter<int> intOut,
  OutputParameter<String>? optionalStringOut,
) {
  intOut.value = 42;
  optionalStringOut?.value = 'foobar';
}

void main() {
  var theInt = OutputParameter(0);
  var theString = OutputParameter('');
  foo(theInt, theString);
  print(theInt.value); // Prints: 42
  print(theString.value); // Prints: foobar
}

It certainly can be a bit inconvenient for callers to have to use variable.value everywhere, but in some cases it might be worth the trade-off.

Trombone answered 19/4, 2022 at 1:10 Comment(0)
S
0

you can use Set<Object> for returning multiple values,

Set<object> foo() {
     return {'my string',0}
}

print(foo().first) //prints 'my string'

print(foo().last) //prints 0
Sostenuto answered 22/7, 2021 at 2:57 Comment(3)
I don't think Sets are ordered so using first/last is incorrect imhoNerta
sets are ordered as I believe , so you will get the items in the order that you returnSostenuto
Apparently, the default Set is indeed ordered (see api.dart.dev/stable/2.19.6/dart-core/Set-class.html). Note however that not all Sets are ordered in Dart. (unfortunately, I can't remove my downvote)Nerta
A
0

you can use dartz package for Returning multiple data types

https://www.youtube.com/watch?v=8yMXUC4W1cc&t=110s

Atheistic answered 24/8, 2022 at 11:46 Comment(2)
Answers on Stack Overflow should provide enough detail to answer the question on their own. External links should only be used to provide supplemental information or used as a citation to your answer.Kilauea
Instead of providing a video you can provide enough detail answer.Longwise
S
0

This is now available in Dart 3.0 (Flutter 3.10.0). They are called "Records" (full doc here).

Here are some of my favorite examples:

Return types

(int x, double y) geoLocation(String name) =>
    return (-1, 36.8219);

Accessing them:

var record = ('first', a: 2, b: true, 'last');

print(record.$1); // Prints 'first'
print(record.a); // Prints 2
print(record.b); // Prints true
print(record.$2); // Prints 'last'

Variables

// Record type annotation in a variable declaration:
(String, int) record;

// Initialize it with a record expression:
record = ('A string', 123);

Named args!

// Record type annotation in a variable declaration:
({int a, bool b}) record;

// Initialize it with a record expression:
record = (a: 123, b: true);
Statism answered 15/5, 2023 at 20:32 Comment(0)
D
-1

In this type of situation in Dart, an easy solution could return a list then accessing the returned list as per your requirement. You can access the specific value by the index or the whole list by a simple for loop.

List func() {
  return [false, 30, "Ashraful"];
}

void main() {
  final list = func();
  
  // to access specific list item
  var item = list[2];
  
  // to check runtime type
  print(item.runtimeType);
  
  // to access the whole list
  for(int i=0; i<list.length; i++) {
    print(list[i]);
  }
}
Disturbed answered 22/11, 2020 at 8:43 Comment(1)
dart.dev/tools/dart-formatDarbie

© 2022 - 2024 — McMap. All rights reserved.