Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constant function literals #4596

Open
lrhn opened this issue Aug 20, 2012 · 24 comments
Open

Constant function literals #4596

lrhn opened this issue Aug 20, 2012 · 24 comments

Comments

@lrhn
Copy link
Member

@lrhn lrhn commented Aug 20, 2012

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.

@DartBot

This comment has been minimized.

Copy link

@DartBot DartBot commented Aug 21, 2012

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) => dxdx + dydy;

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.

@gbracha

This comment has been minimized.

Copy link
Contributor

@gbracha gbracha commented Nov 6, 2012

Added this to the Later milestone.
Added Accepted label.

@jtmcdole

This comment has been minimized.

Copy link
Contributor

@jtmcdole jtmcdole commented Dec 6, 2013

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.

@DartBot

This comment has been minimized.

Copy link

@DartBot DartBot commented Apr 30, 2014

This comment was originally written by pi...@gmail.com


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).

@kasperl

This comment has been minimized.

Copy link
Contributor

@kasperl kasperl commented Jul 10, 2014

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

@kasperl

This comment has been minimized.

Copy link
Contributor

@kasperl kasperl commented Aug 4, 2014

Removed Oldschool-Milestone-Later label.

@DartBot

This comment has been minimized.

Copy link

@DartBot DartBot commented Mar 1, 2015

This comment was originally written by steffen.haup...@gmail.com


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

This comment has been minimized.

Copy link

@DartBot DartBot commented Mar 2, 2015

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

This comment has been minimized.

Copy link

@DartBot DartBot commented Mar 3, 2015

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

This comment has been minimized.

Copy link

@DartBot DartBot commented Mar 3, 2015

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

This comment has been minimized.

Copy link

@DartBot DartBot commented Mar 3, 2015

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.

@isaias-b

This comment has been minimized.

Copy link

@isaias-b isaias-b commented Feb 22, 2016

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

@kevmoo kevmoo added P2 type-enhancement and removed accepted labels Feb 29, 2016
@stijnvanbael

This comment has been minimized.

Copy link

@stijnvanbael stijnvanbael commented Jul 1, 2016

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

@zoechi

This comment has been minimized.

Copy link
Contributor

@zoechi zoechi commented Jul 1, 2016

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

@stijnvanbael

This comment has been minimized.

Copy link

@stijnvanbael stijnvanbael commented Jul 4, 2016

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

@munificent munificent changed the title Constant function literals. Constant function literals Dec 17, 2016
@trinarytree

This comment has been minimized.

Copy link

@trinarytree trinarytree commented Jan 20, 2017

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.

@matanlurey

This comment has been minimized.

Copy link
Contributor

@matanlurey matanlurey commented Jan 20, 2017

+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

This comment has been minimized.

Copy link
Contributor

@matanlurey matanlurey commented Jan 20, 2017

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

@lrhn

This comment has been minimized.

Copy link
Member Author

@lrhn lrhn commented Jan 20, 2017

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

@chalin

This comment has been minimized.

Copy link
Contributor

@chalin chalin commented Mar 4, 2018

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

@tvolkert

This comment has been minimized.

Copy link
Contributor

@tvolkert tvolkert commented Oct 3, 2018

Any update on this?

@eernstg

This comment has been minimized.

Copy link
Member

@eernstg eernstg commented Oct 3, 2018

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

@ConsoleTVs

This comment has been minimized.

Copy link

@ConsoleTVs ConsoleTVs commented Aug 18, 2019

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

@AirborneEagle

This comment has been minimized.

Copy link

@AirborneEagle AirborneEagle commented Dec 5, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Language Enhancement Categories
Non-Breaking and Complex
You can’t perform that action at this time.