language icon indicating copy to clipboard operation
language copied to clipboard

Constant function literals

Open lrhn opened this issue 13 years ago • 71 comments

Static functions are compile time constants, but function literals are not. It would be great if it was possible to write compile time constant function literals. They would necessarily have static scope (no access to "this") even if written inside a class declaration.

Constant function literals would create only one function object per function expression (no unification of different function expressions, even if they happen to have the same body).

This is particularly useful for default function parameters.

I suggest const <functionLiteral> as syntax. That would allow you to write, e.g.,:

class Map<K,V> {
  V getIfPresent(K key, [V onNotPresent() = const () => null]);
}

The current alternative is to declare the function as static:

class Map<K,V> {
  V getIfPresent(K key, [V onNotPresent() = _returnNull]);
  static _returnNull() => null;
}

You can use it to ensure that you don't create too many closures if you want to create a function inside a loop:

for (var x in xs) {
  x.somethingOrError(const (x) => throw new Failure(x));
}

which would otherwise create a new closure per iteration of the loop. The alternative is again to define a static function somewhere and use that, but it moves the logic away from where it's most readable.

The syntax shouldn't collide with any current use of "const", since we currently don't allow that syntax in expression position. It does collide with a constant constructor declaration, but the uses are different enough that I don't think it's a problem. If we want parity, we could allow const foo() => xx as a top-level declaration too, meaning the same as static, but that would make static redundant.

lrhn avatar Aug 20 '12 06:08 lrhn

This comment was originally written by @seaneagan


That syntax could potentially be useful for something else: declaring a function's return value to be constant (at least when it receives constants as input).

const lengthSquared(dx, dy) => dx*dx + dy*dy;

The calls would need to be marked with "const" as well, just as with "const" constructor calls:

var ls = const lengthSquared(1, 1);

For example, most of the methods in dart:math could use this.

DartBot avatar Aug 21 '12 18:08 DartBot

Added this to the Later milestone. Added Accepted label.

gbracha avatar Nov 06 '12 23:11 gbracha

Hit this today as well and it would be a nice feature. Figured its been > 12 months though and little chance in the near future.

jtmcdole avatar Dec 06 '13 23:12 jtmcdole

This comment was originally written by [email protected]


Big +1 for this to happen.

It would give a lot of new power to annotations, e.g.:   class MyVO {     @­Validator((value) => value is String && value.length > 0)     String name;   }

And why not something like this too:   class MyVO {     @­() => value is String && value.length > 0;     String name;   } (Ok, this goes too far)

This doesn't seem quite straight-forward to implement though. Constant function literals could not perform "variable capture". I guess it brings complications to the parser and I'm sure there are other implications.

This would be big nonetheless (IMO).

DartBot avatar Apr 30 '14 10:04 DartBot

Removed this from the Later milestone. Added Oldschool-Milestone-Later label.

kasperl avatar Jul 10 '14 10:07 kasperl

Removed Oldschool-Milestone-Later label.

kasperl avatar Aug 04 '14 07:08 kasperl

This comment was originally written by [email protected]


Just found out that not even the [length] of a const String literal is a constant. I would really appreciate this to be changed. It would allow to move String based list initializations into fixed length lists. That in case would allow for more optimized code than variable length lists.

DartBot avatar Mar 01 '15 18:03 DartBot

This comment was originally written by @seaneagan


Since function literals are anonymous, the only way to expose a constant one would be via a separate constant declaration of some kind. So there should be no way to "accidentally expose" a constant function literal. The fact an expression uses a an anyonymous function literal versus a constant function declaration is just an implementation detail. So why should the "const " prefix be required when it can just be inferred?

DartBot avatar Mar 02 '15 16:03 DartBot

This comment was originally written by @Emasoft


I agree with seaneagan here. There is no need for this. All methods should get this optimization automatically from the compiler if the user passes a constant as a parameter. This is a non issue for the language, but only a compiler optimization. The compiler should automatically infer when to convert a function literal to a constant. The C# compiler does this very well, for example. Usually I don't need to use the const keyword at all.

DartBot avatar Mar 03 '15 16:03 DartBot

This comment was originally written by @seaneagan


@fmaud: It is useful to mark declarations as "const" to avoid someone referencing the declaration in a const-only context, and then you wanting to change the declaration to something non-const and breaking them.

But function literals are just expressions, so there is no danger of that.

DartBot avatar Mar 03 '15 17:03 DartBot

This comment was originally written by @seaneagan


I guess the only strange thing about auto-determining the constness would be that canonicalization would be dependent on whether a function literal happened to be a constant. I can't think of any obvious negative consequences of that, but nonetheless I imagine it would need to be considered a breaking change and wait for dart 2.0.

DartBot avatar Mar 03 '15 17:03 DartBot

On stackoverflow.com apeared a question concerning this issue. I just wanted to place a callback, so that the question's answers can be updated when this is done. CYA

isaias-b avatar Feb 22 '16 20:02 isaias-b

+1 on this feature, would be great for adding behaviour to metadata

stijnvanbael avatar Jul 01 '16 15:07 stijnvanbael

@stijnvanbael you can reference functions in metadata (top-level functions and static methods) , you can just not define them inline

zoechi avatar Jul 01 '16 19:07 zoechi

@zoechi I noticed, it would still be nice though to define one-liners inline.

stijnvanbael avatar Jul 04 '16 07:07 stijnvanbael

This proposal could save devs from creating boilerplate functions when using Angular dependency injection:

// Wouldn't this be nice?
final myProvider = const Provider(
    Foo, useFactory: const (Dep dep) => new Foo(dep.bar), deps: const [Dep]);

Instead we must do this:

final myProvider = const Provider(Foo, useFactory: _fooFactory);

@Injectable()
Foo _fooFactory(Dep dep) => new Foo(dep.bar); // Ughh..

Admittedly, in the 1st version you have to repeat deps, but often there aren't any deps or writing the few deps twice is an acceptable tradeoff vs inventing the name _fooFactory and writing it twice in 2 places that are far from each other.

trinarytree avatar Jan 20 '17 03:01 trinarytree

+1

We also wouldn't need @Injectable at all for a class, as the only reason it will exists (soon) is to generate a factory function once per library versus once per use-site. If we could use const then we'd know the functions will be canoncalized by the compiler and remove the need entirely.

matanlurey avatar Jan 20 '17 05:01 matanlurey

Or it would be nice if you could just infer, but I understand if we cannot

matanlurey avatar Jan 20 '17 05:01 matanlurey

About inferring that a function needs to be const, it would be handled by dart-lang/sdk#4046 as well (well, as long as the default value expression needs to be const).

lrhn avatar Jan 20 '17 06:01 lrhn

Any progress on this? With the new guidelines for writing providers in Angular 5, it would be great to be able to write:

final mockRouter = new MockRouter();
...
    const FactoryProvider(Router, () => mockRouter)
...

cc @matanlurey @kwalrath

chalin avatar Mar 04 '18 13:03 chalin

Any update on this?

tvolkert avatar Oct 03 '18 16:10 tvolkert

No. Not a bad idea, but also not near the top of the list at this point. Could happen!

eernstg avatar Oct 03 '18 16:10 eernstg

7 years old issue over here and I still need this :c

ConsoleTVs avatar Aug 18 '19 17:08 ConsoleTVs

+1 could very much use this. or at least a decent work around.

AirborneEagle avatar Dec 05 '19 17:12 AirborneEagle

Any updates on it ?

akarabach avatar Dec 26 '19 00:12 akarabach

In flutter's UiKitView and AndroidView, their parameter onPlatformViewCreated can be const method, but because of the current state, UiKitView and AndroidView can't define as const.

jerryzhoujw avatar Mar 17 '20 03:03 jerryzhoujw

but because of the current state, UiKitView and AndroidView can't define as const.

This issue should not be blocking - there is always the workaround of making a top level method instead. This issue is about better ergonomics.

natebosch avatar Mar 17 '20 17:03 natebosch

I was 13 when this issue first appeared. It was here for my whole conscious life lol. Should I now join flutter team to finally close it😛?

orsenkucher avatar Apr 28 '20 12:04 orsenkucher

I often need to give empty callbacks to constructors that would otherwise be const in Flutter. After intensive research, contacting several experts, and coming close to rupturing the space-time continuum, I'm proud to present my solution:

void emptyFunc() {}

hacker1024 avatar Jun 03 '20 06:06 hacker1024

@leafpetersen @munificent @lrhn – should this be in the language repo?

kevmoo avatar Jun 25 '20 21:06 kevmoo