-
Notifications
You must be signed in to change notification settings - Fork 208
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 #1048
Comments
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).
The calls would need to be marked with "const" as well, just as with "const" constructor calls:
For example, most of the methods in dart:math could use this. |
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. |
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.: And why not something like this too: This doesn't seem quite straight-forward to implement though. This would be big nonetheless (IMO). |
Removed this from the Later milestone. |
Removed Oldschool-Milestone-Later label. |
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. |
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? |
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. |
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. |
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. |
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. |
+1 on this feature, would be great for adding behaviour to metadata |
@stijnvanbael you can reference functions in metadata (top-level functions and static methods) , you can just not define them inline |
@zoechi I noticed, it would still be nice though to define one-liners inline. |
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 |
+1 We also wouldn't need |
Or it would be nice if you could just infer, but I understand if we cannot |
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). |
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)
... |
Any update on this? |
No. Not a bad idea, but also not near the top of the list at this point. Could happen! |
7 years old issue over here and I still need this :c |
+1 could very much use this. or at least a decent work around. |
Any updates on it ? |
In flutter's |
This issue should not be blocking - there is always the workaround of making a top level method instead. This issue is about better ergonomics. |
Ran up against this attempting to pass anonymous functions as arguments to an |
This said, how will Thanks for your hard work, Dart team 💙 |
@lucavenir, thanks for the kind words to the team!
That's not quite true. For instance: typedef F = int Function();
F g(int x) => () => x;
void main() {
F f1 = g(2);
F f2 = g(3);
print(f1()); // '2'.
print(f2()); // '3'.
} In this example, we couldn't make That's the reason why proposals about constant function literals always have to put some constraints on the body of that function (e.g., that the body must not contain any references to any non-global declarations). |
isn't that how final foo = 'foo';
final bar = '$foo bar';
print(bar); compiles to something like console.log('foo bar'); same with numbers: final foo = 5;
final bar = 3 + foo;
print(bar); // compiles to console.log(8); |
It would be possible to run the const-related checks on every function literal, and then consider each of them a constant expression if it satisfies the constraints. However, it might be easier to read the code, and to maintain it, if a function literal is only a constant expression when (1) there is a |
That's embarassing, I totally forgot about higher order functions 😅
So it's doable, as long as no parameters are giving, nor references to non-const global declarations are involved, right? |
It's certainly doable. I think the main reason why it hasn't been given a very high priority is that when a function literal is const-able, it can also be lifted: void main() {
const f1 = (String s) => 2; // Could be allowed, if constant function literals were supported.
const fs1 = [f1]; // Could then use `f1` in other constant expressions.
const fs2 = [f2]; // But we can do this today---same thing.
}
int f2() => 2; |
Would this feature also support compile-time evaluation/execution of these constant function literals at compile time (like Rust's It'd be nice to be able to use a const pure function to instantiate |
@GregoryConrad what you are asking for is a larger feature which expands the set of expression / statements which compiler can evaluate in constant context. See all other issues tagged with |
could it be possible to place const func in annotation? |
*Edited*. The original example wasn't clear. I often find myself wanting to write this pattern: // flutter_library.dart
class FlutterButton {
const FlutterButton({this.onPressed});
final void Function()? onPressed;
}
// my_code.dart
class MyButton {
const MyButton(void Function()? f)
: button = const FlutterButton(
onPressed: f == null
? null
: () {
// Do something here such as logging
f();
}); // Error: Invalid constant value
final FlutterButton button;
} Unfortunately, the above is invalid. I'm not sure if there's a practical workaround that doesn't burden the user who instantiates The above pattern isn't just blocked by this issue, but also another. The language disallows the following: const MyButton(void Function()? f)
: button = const FlutterButton(onPressed: f); // f is not a valid constant? Below, TekExplorer posted the issue tracking this: #2000 |
The workaround for that is to just have a method or getter in your widget that does the wrapping. let the onPressed be passed in directly. class SomeWidget ... {
const SomeWidget({this.onPressed})
final VoidCallback? onPressed;
VoidCallback? get _onPressed {
if (onPressed == null) return null;
// do whatever
return () {
onPressed();
}
}
Widget build() {...}
} wrapping a function like that in the constructor doesnt really provide much benefit at all. |
The point is to allow using the constructor argument import 'package:flutter/material.dart';
class LoggingInkWell extends InkWell {
const LoggingInkWell({
super.key,
required Function()? onTap,
super.child,
super.borderRadius,
}) : super(onTap: onTap == null ? null : () {
// Do something such as logging here.
onTap();
}); // Error: Invalid constant value
} |
That still wouldnt work, because |
It would be nice to be able to take a const reference to a const's method: class MyConst {
const MyConst();
int foo() => 1;
}
const myFoo = const MyConst().foo;
main() {
print(myFoo());
} This fails with I think this may be the same issue as this one? |
How would this work when applying hot-reload? Say a user defines: const a = () => 'hello'; And changes the function to Would:
If the latter, what about: const a = () => 'hello';
const b = () => a(); If we change the source of |
I think that const methods should only refer to final fields on the declaring class, if the class was created as const. Also, they can refer to other const methods, and other constants, but cannot use any assignment operators |
@Number-3434 It's just not that kind of |
Does that mean that you could (in theory) stick the Would this be rather simple to achieve? |
12 years… At this point the total time that people have wasted learning how to work around this must exceed the time it would have taken to implement by several magnitudes. |
Constant closures would be great. Seriously, with metaprogramming coming around the corner, and existing annotations/builders, it would greatly enhance usage. |
Constant closures aren't necessary for metaprogramming afaik. Macros come with a separate feature designed just for them. They wouldn't be your typical annotation, and would have super-powers in terms of what their parameters can be. There's value in this, but macros isn't one of the reasons :) |
You say that, but not all annotations relevant to macros will themselves be macros. |
Instead of using const or some other modifier, how about just making this function a private function at the top level of the current file? I just don't want to name it. |
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.,:The current alternative is to declare the function as static:
You can use it to ensure that you don't create too many closures if you want to create a function inside a loop:
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 asstatic
, but that would makestatic
redundant.The text was updated successfully, but these errors were encountered: