Creating function with variable number of arguments or parameters in Dart - dart

I am looking for a way to create a function with a variable number of arguments or parameters in Dart. I know I could create an array parameter instead, but I would prefer to not do that because I'm working on a library where syntactic brevity is important.
For example, in plain JavaScript, we could do something like this (borrowed from here):
function superHeroes() {
for (var i = 0; i < arguments.length; i++) {
console.log("There's no stopping " + arguments[i]);
}
}
superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
However, in dart, that code will not run. Is there a way to do the same thing in dart? If not, is this something that is on the roadmap?

You can't do that for now.
I don't really know if varargs will come back - they were there some times ago but have been removed.
However it is possible to emulate varargs with Emulating functions. See the below code snippet.
typedef OnCall = dynamic Function(List arguments);
class VarargsFunction {
VarargsFunction(this._onCall);
final OnCall _onCall;
noSuchMethod(Invocation invocation) {
if (!invocation.isMethod || invocation.namedArguments.isNotEmpty)
super.noSuchMethod(invocation);
final arguments = invocation.positionalArguments;
return _onCall(arguments);
}
}
main() {
final superHeroes = VarargsFunction((arguments) {
for (final superHero in arguments) {
print("There's no stopping ${superHero}");
}
}) as dynamic;
superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
}

Dart does indirectly support var-args as long as you aren't too much into syntactic brevity.
void testFunction([List<dynamic> args=[]])
{
for(dynamic arg:args)
{
// Handle each arg...
}
}
testFunction([0, 1, 2, 3, 4, 5, 6]);
testFunction();
testFunction([0, 1, 2]);
Note: You can do the same thing with named parameters, but you'll have to handle things internally, just in case if the user (of that function; which could be you) decides to not pass any value to that named parameter.
I would like to thank #Ladicek for indirectly letting me know that a word like brevity exists in English.

This version:
Works with both positional and keyword arguments.
Supports typing of the return value.
Works with modern Dart.
typedef VarArgsCallback = void Function(List<dynamic> args, Map<String, dynamic> kwargs);
class VarArgsFunction {
final VarArgsCallback callback;
static var _offset = 'Symbol("'.length;
VarArgsFunction(this.callback);
void call() => callback([], {});
#override
dynamic noSuchMethod(Invocation inv) {
return callback(
inv.positionalArguments,
inv.namedArguments.map(
(_k, v) {
var k = _k.toString();
return MapEntry(k.substring(_offset, k.length - 2), v);
},
),
);
}
}
void main() {
dynamic myFunc = VarArgsFunction((args, kwargs) {
print('Got args: $args, kwargs: $kwargs');
});
myFunc(1, 2, x: true, y: false); // Got args: [1, 2], kwargs: {x: true, y: false}
}
Thanks, Alexandre for your answer!

I played around a little with Alexandre Ardhuin's answer and found that we can tweak a couple of things to make this work in the current version of Dart:
class VarArgsClass {
noSuchMethod(InvocationMirror invocation) {
if (invocation.memberName == 'superheroes') {
this.superheroes(invocation.positionalArguments);
}
}
void superheroes(List<String> heroNames) {
for (final superHero in heroNames) {
print("There's no stopping ${superHero}!");
}
}
}
main() {
new VarArgsClass().superheroes('UberMan', 'Exceptional Woman', 'The Hunk');
}
This has lots of problems, including:
A warning is generated wherever you call superheroes() because the signature doesn't match your parameters.
More manual checking would need to be done to make sure the list of arguments passed to superheroes is really a List<String>.
Needing to check the member name in noSuchMethod() makes it more likely you'll forget to change the 'superheroes' string if you change the method name.
Reflection makes the code path harder to trace.
BUT if you are fine with all of those issues, then this gets the job done.

If you are really into syntactic brevity, just declare a function/method with say 10 optional positional parameters and be done. It's unlikely someone will call that with more than 10 arguments.
If it sounds like a hack, that's because it is a hack. But I've seen the Dart team doing the same :-)
For example:
void someMethod(arg0, [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) {
final args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9];
args.removeWhere((value) => value == null);
/* do something the the args List */
print(args);
}

For the example you've written, I think you're best off using a list. Sorry about that!
I'm looking at dartbug.com, but I don't see a feature request for this. You're definitely welcome to create one!

Related

What's the equivalent to this[x] in Dart?

For instance, in Javascript I can do something like:
class Foo {
x = 'baz';
bar() {
const someVar = 'x';
console.log(this[someVar]);
// Output: 'baz';
}
}
Hopefully that's relatively clear - it boils down to accessing a member variable by another variable's contents. How is this achieved in Dart?
This is not trivial in Dart. Dart doesn't have a syntax to access class properties with [].
There are a couple of approaches though:
Mirrors:
https://api.dartlang.org/stable/2.6.1/dart-mirrors/dart-mirrors-library.html
Basically you have access to everything and offers the biggest freedom. You can check what properties a class has, access them via names and so on. Big disadvantage is that the generated JS (if targeting web) will be huge. Flutter doesn't support it at all.
Reflectable
To deal with the large generated JS, you can use package:reflectable. Never tried it with Flutter. It's a bit more to set up and start using bit it works.
Dart only solution 1
You can overload [] operator on a class:
class Foo {
final _backing = <String, String>{
'foo': 'bar'
};
operator [](String val) {
return _backing[val];
}
}
void main() {
final inst = Foo();
print(inst['foo']);
}
Dart only solution 2
Just use a map :) Well sort of... If you are dealing with complex types and you want to add some extra functionality to your map, you can do something like this:
import 'dart:collection';
class StringMap extends Object with MapMixin<String, String> {
final _backing = <String, String>{};
#override
String operator [](Object key) {
return _backing[key];
}
#override
void operator []=(String key, String value) {
_backing[key] = value;
}
#override
void clear() {
_backing.clear();
}
#override
Iterable<String> get keys => _backing.keys;
#override
String remove(Object key) {
return _backing.remove(key);
}
}

How to do lazy evaluation in Dart?

Is there a native (language supported) lazy evaluation syntax? Something like lazy val in Scala.
I've gone through the docs, and could not find anything. There is only a chapter about "lazily loading a library", but it's not what I am asking.
Based on this research I incline to believe (please correct me if I'm wrong) that currently there is no such thing. But maybe you know of any plans or feature requests which will provide the functionality? Or maybe it was considered and rejected by the Dart team?
If indeed there is no native support for this, then what is the best practice (best syntax) for implementing lazy evaluation? An example would be appreciated.
Edit:
The benefits of the feature that I am looking for are mostly the same as in implementation in other languages: Scala's lazy val or C#'s Lazy<T> or Hack's __Memorize attribute:
concise syntax
delayed computation until the value is needed
cache the result (the by-need laziness)
don't break pure functional paradigm (explanation below)
A simple example:
class Fibonacci {
final int n;
int _res = null;
int get result {
if (null == _res) {
_res = _compute(this.n);
}
return _res;
}
Fibonacci(this.n);
int _compute(n) {
// ...
}
}
main(List<String> args) async {
print(new Fibonacci(5).result);
print(new Fibonacci(9).result);
}
The getter is very verbose and has a repetitive code. Moreover I can't make the constructor const because the caching variable _res has to be computed on demand. I imagine that if I had a Scala-like lazy feature then I would also have language support for having a constant constructor. That's thanks to the fact, that the lazy evaluated _res is referentially transparent, and would not be in the way.
class Fibonacci {
final int n;
int lazy result => _compute(this.n);
const Fibonacci(this.n); // notice the `const`
int _compute(n) {
// ...
}
}
main(List<String> args) async {
// now these makes more sense:
print(const Fibonacci(5).result);
print(const Fibonacci(9).result);
}
Update 2021
Lazy initialization is now part of dart from the release 2.12.
Simply add late modifier to the variable declaration
late MyClass obj = MyClass();
And this object will be initialized only when it is first used.
From the docs:
Dart 2.12 added the late modifier, which has two use cases:
Declaring a non-nullable variable that’s initialized after its
declaration.
Lazily initializing a variable.
Checkout the example here:
https://dartpad.dev/?id=50f143391193a2d0b8dc74a5b85e79e3&null_safety=true
class A {
String text = "Hello";
A() {
print("Lazily initialized");
}
sayHello() {
print(text);
}
}
class Runner {
late A a = A();
run() async {
await Future.delayed(Duration(seconds: 3));
print("First message");
a.sayHello();
}
}
Here class A will be initialized only after "First message" has been displayed.
update2
From #lrn s comment - using an Expando for caching makes it work with const:
class Lazy<T> {
static final _cache = new Expando();
final Function _func;
const Lazy(this._func);
T call() {
var result = _cache[this];
if (identical(this, result)) return null;
if (result != null) return result;
result = _func();
_cache[this] = (result == null) ? this : result;
return result;
}
}
defaultFunc() {
print("Default Function Called");
return 42;
}
main([args, function = const Lazy(defaultFunc)]) {
print(function());
print(function());
}
Try it in DartPad
update
A reusable Lazy<T> could look like below in Dart but that also doesn't work with const and can't be used in field initializers if the calculation needs to refer instance members (this.xxx).
void main() {
var sc = new SomeClass();
print('new');
print(sc.v);
}
class SomeClass {
var _v = new Lazy<int>(() {
print('x');
return 10;
});
int get v => _v();
}
class Lazy<T> {
final Function _func;
bool _isEvaluated = false;
Lazy(this._func);
T _value;
T call() {
if(!_isEvaluated) {
if(_func != null) {
_value = _func();
}
_isEvaluated = true;
}
return _value;
}
}
Try it in DartPad
original
Dart version of http://matt.might.net/articles/implementing-laziness/ using a closure to lazy evaluate:
void main() {
var x = () {
print ("foo");
return 10;
}();
print("bar");
print(x);
// will print foo, then bar then 10.
print('===');
// But, the following Scala program:
x = () {
print("foo");
return 10;
};
print ("bar");
print (x());
// will print bar, then foo, then 10, since it delays the computation of x until it’s actually needed.
}
Try it in DartPad
Update
int _val;
int get val => _val ??= 9;
Thanks #Nightscape
Old
I think this little snippet might help you...
int _val;
int get val => _val ?? _val = 9;

How return Future from Future? Or this is prohibited in async library?

How I can return Future value from Future object?
This code does not work.
import 'dart:async';
void main() {
var temp = foo();
temp.then((Future<int> future) {
future.then((int result) {
print(result);
});
});
}
Future<Future<int>> foo() {
return new Future<Future<int>>(() {
return new Future<int>(() => 5);
});
}
How to prevent unnecessary unwrapping?
In this case in async library 'Future' declared as generic class.
abstract class Future<T> {
}
If I create expression as the following
new Future<Future<int>>();
Then with type T specified as Future<int> which result expected from generic class Future?
I thing that result must be as specified in type argument T.
I.e. Future<int>.
But result is not as expected.
There is no information found about this abnormal behavior on Dart API site.
If this is a "feature" (but I think that abnormal behavior wrongly to call "feature') then why it not documented in Dart API?
How can be explained this discrepancy?
Why this code not generated errors and warnings?
Another IDENTICAL example but w/o using Future.
void main() {
var temp = foo();
temp.baz((Foo<int> foo) {
foo.baz((int result) {
print(result);
});
});
}
Foo<Foo<int>> foo() {
return new Foo<Foo<int>>(() {
return new Foo<int>(() => 5);
});
}
If in this case result will be as when using Future (i.e. unexpected) then how we can call this code?
Normal or abnormal?
Or maybe the Future in Dart some special (magic)?
Look at the api documentation
http://api.dartlang.org/docs/releases/latest/dart_async/Future.html
It says there:
If the returned value is itself a Future, completion of the created future will wait until
the returned future completes, and will then complete with the same result.
I guess that means you can't return a Future from a Future.
But you could return a list of futures.
void main() {
var temp = foo();
temp.then((List<Future<int>> list) {
list[0].then((int result) {
print(result);
});
});
}
Future<List<Future<int>>> foo() {
return new Future<List<Future<int>>>(() {
return [new Future<int>(() => 5)];
});
}
There is no need for any of that extra wrapping. According to the Future documentation:
If the returned value is itself a [Future], completion of the created
future will wait until the returned future completes, and will then
complete with the same result.
This means you can rewrite your code as:
import 'dart:async';
void main() {
var temp = foo();
temp.then((int result) {
print(result);
});
}
Future<int> foo() {
return new Future<int>(() {
return new Future<int>(() => 5);
});
}
This is a lot cleaner to work with and provides the expected result.

should returning const value from const object be const?

I'm using the style class below to mimick enums (from Does Dart support enumerations?)
It is working fine in that this snippet produces expected results.
void main() {
InterpolationType it = InterpolationType.LINEAR;
print("it is $it and stringified ${stringify(it)}");
print(InterpolationType.fromJson(it.toJson()));
}
But the DartEditor is complaining about "Expected constant expression" in the case statements of fromJson method. Is there a const I can throw in somewhere to get rid of this complaint?
class InterpolationType {
static const LINEAR = const InterpolationType._(0);
static const STEP = const InterpolationType._(1);
static const CUBIC = const InterpolationType._(2);
static get values => [
LINEAR,
STEP,
CUBIC
];
final int value;
const InterpolationType._(this.value);
String toString() {
switch(this) {
case LINEAR: return "LINEAR";
case STEP: return "STEP";
case CUBIC: return "CUBIC";
}
}
int toJson() {
return this.value;
}
static InterpolationType fromJson(int v) {
switch(v) {
case LINEAR.value: return LINEAR;
case STEP.value: return STEP;
case CUBIC.value: return CUBIC;
}
}
static InterpolationType fromString(String s) {
switch(s) {
case "LINEAR": return LINEAR;
case "STEP": return STEP;
case "CUBIC": return CUBIC;
}
}
}
As you discovered: accessing fields from a const object is not a constant operation. So the editor (as well as the VM and dart2js) are right.
With the current syntax there is no way to express a (informal) contract that a field of a class will always be a final field. For example, I could change the value-field to be a getter instead of a field. The interface-contract of the class definitely allows me to do that, because I never told anybody that I would keep "value" as a field. However if I did that it would break every program that relied on the existence of this final field.
As a consequence the current behavior is very unlikely to change.
However: in theory it would be possible to improve the Dart language so that you could use "const" instead of "final" for local fields, and initialize them with initializer lists. And in this case accessing the field could be considered a constant operation. I currently don't see any downsides to this behavior and it would be backwards-compatible.
// WARNING: What follows DOES NOT WORK, just a potential example
class InterpolationType {
const value; // Note the "const" instead of "final".
const InterpolationType._(this.value);
}
The language is already pretty stable but you can open a bug at http://dartbug.com/ and suggest this behavior. It's not very likely that the feature-request would be accepted, but it's definitely worth a try.

Unit test hanging when using lexical scoping and generics with extends

The behavior seems to be related to the presence of 'extends' as shown with unit test below:
typedef dynamic GetFromThing<T extends Thing>(T target);
typedef GetFromThing<T> DefGetFromThing<T extends Thing>(dynamic def);
typedef dynamic GetFromT<T>(T target);
typedef GetFromT<T> DefGetFromT<T>(dynamic def);
class Thing {
int value;
}
class Test {
static final GetFromThing<Thing> fromThingSimple = (Thing target) {
return target.value;
};
static final DefGetFromThing<Thing> fromThing = (dynamic def) {
return (target) => null;
};
static final DefGetFromT<int> fromInt = (dynamic def) {
return (target) => null;
};
}
main() {
test('this works', () {
var temp1 = Test.fromThingSimple(new Thing());
});
test('this works too', () {
var temp = Test.fromInt(10);
});
test('should let me call lexically closed functions', () {
var temp = Test.fromThing(10); // <-- causes test to hang
});
}
The fact that the VM hangs is clearly a bug. The code is legal. The fact that typedefs describe function types and can be generic whereas function types themselves are never generic is not an issue in principle (though it might be for the implementation).
I find it very interesting that type parameters in typedefs work without some kind of warning or error, since Dart doesn't have generic methods.
You very well may have come across two bugs here, the first that there's no errors, and the second that the VM hangs.

Resources