Dart Mixin get super field value - dart

Based on a class and a mixin
class CounterModel extends MVAModel with CounterModelGeneratedCode {
int counter = 2;
}
mixin CounterModelGeneratedCode on MVAModel {
int get counter => store.get("counter", () => (super as CounterModel).counter);
set counter(int value) => store.set("counter", value);
}
The dart analyzer does not complain but on compilation I get an
Error: Can't use 'super' as an expression. To delegate a constructor
to a super constructor, put the super call as an initializer.
How can I access the overshadowed values of the CounterModel class (e.g. 2 for counter)?

You cannot do that, and the analyzer should have caught the syntax error too.
You cannot override the resolution of super-invocations, you can only call the actual superclass member.
Also, the counter is not on the superclass, which is MVAModel, so using super is not the right approach.
You could try (this as CounterModel).counter, which would work, but it isn't optimal. The cast is not necessary, we can do better.
What you probably want in this case is to add a definition of the counter variable to the mixin declaration:
abstract int counter;
That way, it requires classes mixing it in to define such a counter (which the one class doing so then does).
Then you can invoke the counter in the mixin as just this.counter.

Related

Is there a neater way to map member functions in dart?

Dart has a handy map function on iterables, and it accepts a lambda. So I can write something like:
// Stupid example class
class Foo {
int v;
int v2() { return v*v; }
}
List<int> mapFoos(List<Foo> foos) {
return foos.map( (Foo f) => f.v2() );
}
But this feels a little clunky to me. I'm used to being able to tell map to use the member function directly, something that would look more like:
// does not compile
List<int> mapFoos(List<Foo> foos) {
return foos.map(Foo.v2);
}
But this fails to compile with the error:
The argument type '() → int' can't be assigned to the parameter type '(Foo) → int'
Is there some way to turn the member function into a lambda in a succinct way, so that
we can have something closer to the second example.
I could write
int applyV2(Foo f) {
return f.v2();
}
List<int> mapFoos(List<Foo> foos) {
return foos.map(applyV2);
}
but then I'd need to create that for each member function I want to map, which isn't really any better than using the lambda function.
If it makes any difference I'm using dart 1 due to "legacy reasons", if this has changed in recent versions I'd love to know that too.
No.
There is no shorter way to create a function which takes a Foo and calls its v2 method, than (f) => f.v2().
You can omit the Foo type on the parameter, because it can be inferred from the context (a List<X>.map<R> requires an R Function(X) as argument).
You cannot tear off Foo.v2 because v2 is an interface method, not a static method.
Just to elaborate on why Dart doesn't allow that, you can stop reading now if you just want to know what works:
Some languages allow you to tear off instance methods, so Foo.v2 becomes a function which expects its this object as an argument, in Dart a function of type int Function(Foo). Dart does not allow that. Probably for many different reasons, but most importantly because it cannot work. Dart types are interfaces, all class types can be implemented by another class without inheriting any implementation.
If you then tear off Foo.v2, you can call it with an instance of another class which implements Foo, but which won't necessarily find the private fields that Foo has, and which v2 could depend on.
Also, the tear-off would be covariant in its this-parameter.
Take SubFoo which extends Foo and has its own v2 method. If you do Foo foo = SubFoo(); var vtoo = foo.v2; then the static type of vtoo will be int Function(Foo), but the implementation from SubFoo will necessarily have runtime type int Function(SubFoo), which is not a subtype of the static type. That means it's unsound. The torn off function will have to do a run-time type check that its argument is actually a SubFoo, and throw if it's not. (So, that feature is not a good match for Dart.)

Check if a type implements an interface [duplicate]

I've recently found myself in a situation where I wanted to check if a Type is a subtype of another Type this is what I've tried
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord is Record); // return false but why ??
}
The only time it makes sense to check if one type is a subtype of another type is when at least one of the types is a type variable. (Otherwise, you can just look at the source and write a constant true or false into the code).
There is a way to check whether one type is a subtype of another, and it does use the is operator, but you need to have an instance as the first operand and a type as the second. You can't just create an instance of an unknown type, so we instead rely in Dart's covariant generics:
bool isSubtype<S, T>() => <S>[] is List<T>;
(You can use any generic class, or even create your own, instead of using List. All it needs is a way to create the object.)
Then you can write:
print(isSubtype<TimeRecord, Record>()); // true!
The is keyword is used to check if an object instance is an object of type T, and not if a type is another type:
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord() is Record); // returns true!
}
Just to add up to #lrn answer.
You could also do something like:
extension NullableObjectsExtensions<T> on T {
bool isSubtypeOf<S>() => <T>[] is List<S>;
bool isSupertypeOf<S>() => <S>[] is List<T>;
}
So this way you can test any variable anywhere.

Adding the generic type to a comparable type in Dart

This is a followup question after reading this Q&A:
Generic Sorting function accepts T, but want to ensure T is comparable
I have a class like so:
class BinarySearchTree<E extends Comparable> { ... }
so I can create an instance like this:
final tree = BinarySearchTree<int>();
My question is about using Comparable vs Comparable<E>. When I do this:
class BinarySearchTree<E extends Comparable> { ... }
then the type defaults to E extends Comparable<dynamic>. I normally try to avoid dynamic, so in order to be more explicit about the type that is being compared, it seems like I should write it this:
class BinarySearchTree<E extends Comparable<E>> { ... }
But in that case I get an error here:
final tree = BinarySearchTree<int>();
// 'int' doesn't conform to the bound 'Comparable<int>' of the type parameter 'E'.
// Try using a type that is or is a subclass of 'Comparable<int>'.
This demonstrates my lack of understanding of generics. What am I missing?
In Dart, a class cannot implement 2 different concrete instances of a generic interface:
abstract class Foo<T> {}
// error: Foo can only be implemented once
class Bar implements Foo<String>, Foo<int> {}
num implements Comparable<num>, because it would be slightly absurd for the built-in number types to not be comparable. However, since int is a subtype of num (and therefore inherits Comparable<num>, it cannot have Comparable<int>.
This leads to the slightly weird consequence that int does not implement Comparable<int>.
The problem you're facing is that from the language's point of view, there are 2 types involved: the type of the elements being compared, and the type of the elements they are being compared to.
As such, your type will need 2 type parameters:
class Tree<T extends Comparable<S>, S> {
T get foo;
}
final intTree = Tree<int, num>();
final foo = intTree.foo; // returns an int
Admittedly, this isn't a super clean solution, but if you're using Dart 2.13 or higher, you can use typedefs to make it a bit nicer:
typedef IntTree = Tree<int, num>;
typedef RegularTree<T> = Tree<T, T>;
final intTree = IntTree();
final stringTree = RegularTree<String>();
intTree.foo // is an int
stringTree.foo // is a String
There is another option, which is to just drop some type safety and use Comparable<dynamic>, but personally I'd recommend against it. BTW, if you want to avoid accidentally missing type parameters you can disable implicit-dynamic as described here: https://dart.dev/guides/language/analysis-options#enabling-additional-type-checks
This will give an error any time the type dynamic is inferred from context without the programmer actually typing the word dynamic

Should subclasses inherit private mixin variables in Dart?

Should I get the following error:
class.dart:11:11: Error: The getter '_privateID' isn't defined for the class 'Y'.
- 'Y' is from 'class.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named '_privateID'.
From the following code?
mixin.dart:
class Mixin {
static int _nextID = 0;
int publicID = _nextID++; // I only need one of these lines
int _privateID = _nextID++; // but this variable is inaccessible
}
class.dart:
import 'mixin.dart';
class X with Mixin {
void run() {
print(publicID); // no error here
}
}
class Y with Mixin {
void run() {
print(_privateID); // Error: _privateID not defined
}
}
void main() {
Y().run();
}
Or is this a bug? If it's not a bug, I'd like to understand why this behavior is reasonable.
When I instead define the mixin in the same file as the above classes, I get no error.
(Dart SDK 2.4.1.)
It is not a bug.
The private field is inherited, but you cannot access it because its name is private to a different library.
Dart's notion of "privacy" is library private names.
The name _privateID in the mixin.dart library introduces a library private name. This name is special in that it can only be written inside the same library.
If someone writes _privateID in a different library, it is a different name, one unique to that library instead.
It is as if private names includes the library URI of the library it is written in, so what you really declare is a name _privateID#mixin.dart.
When you try to read that field in class.dart, you write ._privateID, but because it is in a different library, what you really write is ._privateID#class.dart, a completely different name, and the classs does not have any declarations with that name.
So, if one class needs to access a private member of another class (or mixin, or anything), then the two needs to be declared in the same library, because otherwise they cannot even write the name of that variable.
That is why the code works if you write the mixin in the same library.
If you want to move the mixin to a separate file, but not necessarily a separate library, you can use a part file.

Using mirrors, how can I get a reference to a class's method?

Say I have an instance of a class Foo, and I want to grab a list of all of its methods that are annotated a certain way. I want to have a reference to the method itself, so I'm not looking to use reflection to invoke the method each time, just to grab a reference to it the first time.
In other words, I want to do the reflection equivalent of this:
class Foo {
a() {print("a");}
}
void main() {
var f = new Foo();
var x = f.a; // Need reflective way of doing this
x(); // prints "a"
}
I have tried using InstanceMirror#getField, but methods are not considered fields so that didn't work. Any ideas?
As far as I understand reflection in Dart, there's no way to get the actual method as you wish to. (I'll very happily delete this answer if someone comes along and shows how to do that.)
The best I can come up with to ameliorate some of what you probably don't like about using reflection to invoke the method is this:
import 'dart:mirrors';
class Foo {
a() {print("a");}
}
void main() {
var f = new Foo();
final fMirror = reflect(f);
final aSym = new Symbol('a');
final x = () => fMirror.invoke(aSym, []);
x(); // prints "a"
}
Again, I know that's not quite what you're looking for, but I believe it's as close as you can get.
Side note: getField invokes the getter and returns the result -- it's actually fine if the getter is implemented as a method. It doesn't work for you here, but for a different reason than you thought.
What you're trying to get would be described as the "closurized" version of the method. That is, you want to get the method as a function, where the receiver is implicit in the function invocation. There isn't a way to get that from the mirror. You could get a methodMirror as
reflect(foo).type.methods[const Symbol("a")]
but you can't invoke the result.

Resources