A little bit confused by the d(); notation...
Is it a kind of semantic shugar? The meaning of d(); should be call() as it described in ReactionDisposer class. I.e. there should be d.call(); will it have the same meaning?
void dispose() {
for (final d in _disposers) { // a list of type ReactionDisposer
d(); // what is it?
}
}
class ReactionDisposer {
ReactionDisposer(this.reaction);
final Reaction reaction;
/// Invoking it will dispose the underlying [reaction]
void call() => reaction.dispose();
}
In Dart, you can use an object as if it is a method/function if the object implements the method call().
So d(); will execute the call() method defined in ReactionDisposer.
You can read about this in the Dart Langauge Tour: https://dart.dev/guides/language/language-tour#callable-classes
Related
I'm trying to call a static method from a generic type I receive.
Is that even possible?
Furthermore, I apply a Type constraint in order to only manipulate the object from its parent class.
Here is a short example of what I'm trying to achieve:
class A {
static func() {
print("A");
}
}
class B extends A {
static func() {
print("B");
}
}
concret<T extends A>() {
T.func(); // I expected a print('B')
}
main() {
concret<B>();
}
No, it's not possible.
Dart static method invocations are resolved at compile-time, so it's not possible to call them on type variables which only have a value at run-time.
If it was possible, it would be completely unsafe. Anyone can create a class C extending A which does not have a static func member and invoke concret<C>();. Since static members are not inherited, it would have to give you a run-time error, and there is nothing you can do to detect that at compile-time. That is the primary reason why it is not allowed.
Is it possible to call a second ancestor method in dart? something like super.super.hello()? If it's possible, how can it be written?
class A {
void hello() {
print('A');
}
}
class B extends A {
#override
void hello() {
print('B');
}
}
class C extends B {
#override
void hello() {
// How to call the hello() implemented in the class A here?
}
}
void main() {
var c = C();
c.hello();
}
It's not possible.
The reason it's not possible is that it breaks abstraction.
When you look at class C extend B, all you need to know about B is which signatures its members has and which interfaces it implements. As long as that stays effectively the same, your valid code will keep working.
Consider what would happen if the author of B decided to make themselves a helper base-class:
abstract class _BaseB extends A {
String get _myName;
#override
void hello() {
print(_myName);
}
}
class B extends _BaseB {
#override
String get _myName => "B";
}
That's a perfectly valid refactoring. The resulting class B has all the same members and implements all the same interfaces (and also _BaseB, but it's private so nobody can see that).
The C class above would keep working if all it does is to call super.hello(). If it had a way to ask for super.super.hello(), that might no longer be valid.
Similarly if the B class was changed to:
class B implements A {
#override
void hello() {
print("B");
}
}
(changing extends to implements), then all methods of B works the same as before and it implements the same interfaces. Again, there is no visible differences to the users of the B class.
But if you could call something like A.super.hello() to reach the A class's hello method, then that would now break because that method isn't in the B class at all.
So, by restricting super.hello() to only call methods on the precise class you write as the superclass, you are prevented from introducing dependencies on the implementation of B, dependencies which would make otherwise valid refactorings into breaking changes.
class Parent<T> {
void method(T t) {}
}
class Child extends Parent {
#override
void method(int i) {} // error: mentioned_below
void takesDynamic(dynamic d) {
takesType(d); // no error
}
void takesType(int i) {
takesDynamic(i); // no error
}
}
Error:
void Function(int) isn't a valid override of void Function(dynamic)
When I can easily pass int to dynamic and vice-versa in a method parameter, why do I see the error when I override method.
PS:
I am not looking for a solution which is to use extends Parent<int> and get it working, I want to know the reason why things are treated differently when I am overriding a method vs calling regular methods.
void Function(int x) normally isn't a valid override of void Function(dynamic x) because the int version is not substitutable for the dynamic version.
What are the allowed inputs to Parent<dynamic>.method? Anything.
What are the allowed inputs to Child.method? Just ints.
Such an override therefore could violate the contract of Parent<dynamic>'s interface. (For example, what if you had an instance of Child and passed it to something that expected Parent<dynamic>, which then invoked method('not an int') on it?)
(Note that this is not specific to method overrides. In general, a function that takes a narrower type cannot be used where a function that takes a wider type is expected, even if the narrower type derives from the wider type.)
Dart does allow you to use the covariant keyword to suppress the static type error and explicitly allow the override, but be aware that doing so isn't necessarily type-safe, and you would be responsible for ensuring that you don't get type errors at runtime.
Further reading: Covariance and contravariance (computer science) from Wikipedia
I have some class like this:
abstract class Parent {
void doSomething({dynamic number});
}
class Child01 extends Parent {
#override
void doSomething({dynamic number}) {
...
}
}
class Child02 extends Parent {
#override
void doSomething() {
...
}
}
How can I override doSomething() method in class Child02 without an optional parameter, like above?
You cannot do that and the reason can be seen in the following code:
List<Parent> list = [Child01(), Child02()];
list.forEach((e) => e.doSomething(number: 5));
This is allowed since Parent tells us there is an optional parameter to doSomething called number. But what happens when we end up calling a Child02 object with this parameter it does not expect? You are not allowed in Dart to send arbitrary arguments (named or not) to a method and see if it is going to be used or not.
Consider the following generic class:
class Foo<T extends Bar<dynamic>> {}
How can I obtain the generic argument of Bar at compile time?
I would expect the following code to print int, but it prints dynamic:
class Bar<T> {}
class Foo<T extends Bar<dynamic>> {
Foo(this.value) {
_debugBarType(value);
}
final T value;
void _debugBarType<A>(Bar<A> value) {
print(A);
}
}
void main() {
Foo<Bar<int>>(Bar());
}
I know I could do:
class Foo<A, Bar<A>> {}
But I would like to define the Foo class using a single generic parameter instead of two.
This is currently not possible to do on any class.
There's currently a pending feature request on Dart to support such use-case: https://github.com/dart-lang/language/issues/620
It's worth noting that there's a workaround if you can add a method on the class concerned.
For example, say you have a generic class Model<T>:
class Model<T> {
T value;
}
Then you can add a "capture" method as such:
class Model<T> {
T value;
R capture<T>(void cb<P>(P value)) => cb<T>(value);
}
This then allows you to write:
void someFunction<T extends Model<dynamic>>(T model) {
model.capture(<P>(value) {
// `P` will be the captured type instead of `dynamic`
});
}