Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Dart, is it possible to have a const map of closures?

Tags:

dart

I created a literal map of closures, something like:

Map<String, Function> mapOfFuncs = {
  'foo': (a, b, c) => ... ,
  'bar': (a, b, c) => ... ,
   ...
}

All good so far. Then I wanted to make this map const, as it is global within my program and should never be modified.

const Map<String, Function> MAP_OF_FUNCS = const {
  'foo': (a, b, c) => ... ,
  'bar': (a, b, c) => ... ,
   ...
}

Dart chokes on this as the literal closures in the map are not const.

On Dartpad: https://dartpad.dartlang.org/817d2cfd141b0a56fc7d

I would have thought that literal closures are const. Is there a way to make them so?

like image 792
Argenti Apparatus Avatar asked Feb 21 '16 14:02

Argenti Apparatus


1 Answers

I suspect this might not be possible, take a look at this code:

int test1(int a, int b, int c) {
  return a;
}
int test2(final int a, final int b, final int c) {
  return a;
}

const Function f1 = test1;
const Function f2 = (final a,b,c) => a;

const Map<String, Function> MAP_OF_FUNCS = const {
  'foo': test1,
  'fam': test2,
  'bam': f1,
  'bar': f2
};

Only the first two versions referencing the static method references test1 and test2 work in this constellation. Even f1 produces a compilation error, UPDATE but compiles using dartJS as @irn from the comments pointed out. Then it is unclear why the version with f2 doesn't work.

So probably it is the assignment operator which is not able to produce a statically compiled reference for a given constant lambda expression or a static method reference for its RHS (right hand side) argument.

The documentation pointed me in testing the static const combination, but this generally only works on non top level elements like class members. Thus adding a new class makes it possible to test this.

class A {
  static const Function a1 = test1;
  static const Function a2 = (final a, final b, final c) => a;
}
const Map<String, Function> MAP_OF_FUNCS = const {
  'foo': A.a1,
  'bar': A.a2
};

However, these function definitions are valid but assigning it to the map fails as before. The documentation about maps under the built in types section shows how to create a compile time constant map using the final keyword.

final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

Unfortunately, this approach has the same drawback. It might corellate with the minification limitations of symbols:

A Symbol object represents an operator or identifier declared in a Dart program. You might never need to use symbols, but they’re invaluable for APIs that refer to identifiers by name, because minification changes identifier names but not identifier symbols. ... Symbol literals are compile-time constants.

For more information on symbols, see dart:mirrors - reflection.

Maybe someone else has a better idea, but for me this seems not possible for the moment.

like image 116
isaias-b Avatar answered Nov 13 '22 10:11

isaias-b