The question came into my mind when I've declared a final callback in a class, and the constructor can be declared as const, and trying to make a constant value of a function like so:
class MyClass {
final void Function() callback;
const MyClass(this.callback);
}
void example1() {
const foo = MyClass(() {});
}
This gives the error:
Why can I delcare a constant constructor in the first place? What would make an object of MyClass compile-time constant if no function value can be constant?
A simpler example:
typedef MyVoidCallback = void Function();
void example2() {
const MyVoidCallback bar = () {};
}
This gives the error:
Thank you in advance
It is because () {} is not a constant value, it is rather creating a new instance every time. All functions in dart inherit Function class which doesn't have const constructor.
However, since functions are top-level members in dart, you can pass them by name (like a variable). So if you define your function outside of any class such that it is a global function, you can pass it as a parameter value in a const constructor.
UPDATE from #randal-schwartz comment: Static functions inside a class can also be passed into these const constructors as parameters.
Below code should work:
class MyClass {
final void Function() callback;
const MyClass(this.callback);
}
void example1() {
const foo = MyClass(doWork);
}
void doWork() {
// TODO: do work
}
Related
Docs says
You can use static methods as compile-time constants. For example, you can pass a static method as a parameter to a constant constructor.
But when I tried doing that, I get an error:
Minimal reproducible code:
class Foo {
const Foo(int x);
}
class Bar {
static int get x => 0;
void m() => const Foo(Bar.x); // Error
}
You need to take the documentation more literally:
You can use static methods as compile-time constants. For example, you can pass a static method as a parameter to a constant constructor.
Emphasis mine. What that means is:
class Foo {
const Foo(void Function() func);
}
class Bar {
static void barMethod() {}
}
void main() {
final foo = Foo(Bar.barMethod);
}
Thanks to #Nagual for pointing out the mistake. I was actually calling the method (and passing int) instead of passing the method itself.
This is what I should have done:
class Foo {
const Foo(int Function() cb);
}
class Bar {
static int getX() => 0;
void m() => const Foo(Bar.getX);
}
It is a pattern which makes sure we create only one instance of the class.
Most of the time singleton pattern is shown:
class Settings {
static final Settings _instance = Settings._internal();
factory Settings() {
return _instance;
}
Settings._internal() {}
}
disadvantages: difficult to test and violates single responsibility
What about:
class Singleton{
const Singleton();
}
Singleton s1= const Singleton();
Singleton s2= const Singleton();
void main() {
print(s1==s2); //true
}
Easy to test. Only one 1 responsibility of the object.
My question is why people make life more difficult and never implement Singleton with const constructor. Did I miss anything?
In addition to Christopher Moore's comments about a const, immutable singleton being unlikely to be useful, a non-factory const constructor does not guarantee a single instance, which would violate the singleton pattern. Callers would need to explicitly invoke the constructor in a const context:
class Foo {
const Foo();
}
void main() async {
const foo1 = Foo();
const foo2 = Foo();
var foo3 = Foo();
print(foo1 == foo2); // Prints: true
print(foo1 == foo3); // Prints: false
}
In contrast, a factory constructor can guarantee that only a single instance is created with no additional burden on the callers.
With the below code as an example I can not figure out how to make the generic typed Function work with out casting as shown. Every other way I try I get some variation of
The argument type 'Null Function(Gift)' can't be assigned to the
parameter type 'dynamic Function(T)'
var present = Present<Gift>(Gift('Fancy Gift'), <T>(Gift t) {
print('${(t as Gift).name} was opened.');
});
or
The getter 'name' isn't defined for the type 'Object'
var present = Present<Gift>(Gift('Fancy Gift'), <Gift>(t) {
print('${t.name} was opened.');
});
Here is the working example with a cast.
void main() {
var present = Present<Gift>(Gift('Fancy Gift'), <T>(t) {
print('${(t as Gift).name} was opened.');
});
present.open();
}
class Present<T> {
final T _item;
final Function<T>(T t) openedCallback;
T open() {
openedCallback.call(_item);
return _item;
}
Present(this._item, this.openedCallback);
}
class Gift {
final String name;
Gift(this.name);
}
There should be a way to do this without a cast right?
Your class definition does not do what you intend:
class Present<T> {
final T _item;
final Function<T>(T t) openedCallback;
...
openedCallback is separately parameterized; its T type parameter is separate and independent from that of Present<T>. There is no need to parameterize openedCallback since you presumably want:
class Present<T> {
final T _item;
final Function(T t) openedCallback;
...
After that, you can do:
var present = Present<Gift>(Gift('Fancy Gift'), (t) {
print('${t.name} was opened.');
});
Note that doing <T>(t) { ... } or <Gift>(t) { ... } is counterproductive. That declares an anonymous function that itself is generic and is has a type parameter named T or Gift respectively.
In the following class I want to type the onPress method as a function which returns void. Is there a way to do that?
class Human {
var onPress;
Human({
this.onPress,
});
}
class Human {
void Function() onPress;
Human({
this.onPress,
});
}
or
typedef VoidFunction = void Function();
class Human {
VoidFunction onPress;
Human({
this.onPress,
});
}
Identical to Remi’s declaration, there is a VoidCallback typedef already declared in Flutter.
So you could just declare it as:
VoidCallback onPress;
However, if you want to pass in parameters, you should setup your own typedefs.
VoidCallback onPress works but you can also use Function onPress too like this
class Human {
Function onPress;
Human({
this.onPress,
});
}
Is it possible in Dart to store a callback function with return and argument type information? It appears I can do the following:
class MyClass {
void addCallback( callback( int ) )
{
_callback = callback;
}
var _callback;
}
But I thought it would be nice if _callback wasn't declared as var, and instead had information about its return and argument types. I couldn't find info on this in the docs, anyone know?
Dart 2 supports a function type syntax:
class MyClass {
void addCallback( callback( int ) )
{
_callback = callback;
}
void Function(int) _callback;
}
The Effective Dart Design Guide states that this form is preferred over typedefs.
You can typedef a Function signature like this:
typedef bool Filter(num x);
List<num> filterNumbers(List<num> numbers, Filter filter) {
return numbers.where(filter).toList();
}
For more great information like this, check out this article: https://www.dartlang.org/articles/idiomatic-dart/