p1.jump();
and p1 doesn't have a method named jump then Dart will instead call:
p1.noSuchMethod(..)
The default implementation of noSuchMethod (the one from Object) just throws a NoSuchMethodException, which is typically what you want. But you can override noSuchMethod to some useful things. First, I'll show you a trivial example, to illustrate the basic mechanics then I'll show a slightly more practical use-case.
Here is the simplest possible example:
class Box{
noSuchMethod(InvocationMirror invocation) {
print(invocation.memberName);
}
}
main(){
var b = new Box();
b.foo(); //prints foo, the method name
}
Since b does not have a foo method, it calls our noSuchMethod method. This is obviously not very useful. Below is a more practical example.
A more realistic use-case
Many developers like to access and update database records as objects. This is what Java's Hibernate and Rail's Active Record and Django's Object-relational mapper do. One way to do this is to wrap a generic map or database record with a class as in the example below:
class Person{
DbRecord record;
String get firstName() => record.getFieldValue("firstName");
String get lastName() => record.getFieldValue("lastName");
String get age() => record.getFieldValue("age");
String get fullName() => firstName + " " + lastName;
}
The thing to notice here is that 3 of the 4 getter methods are completely generic. Here is how this could be made easier using noSuchMethod:
class Person{
DbRecord record;
String get fullName() => firstName + " " + lastName;
noSuchMethod(InvocationMirror invocation) => record.getFieldValue(invocation.memberName);
}
By extracting this into a generic base class it become a bit more useful.
Like many of Dart's features, this is not something ground breaking. Dart's nosuchMethod capability is similar to Ruby's method_missing and Python's __setattr__.
1 comment:
Dave, I keep getting "cannot resolve class name 'InvocationMirror' from Model" while trying to run this code, any ideas?
class Model {
Map fields;
Model(Map new_fields) {
new_fields.forEach((k,v) => fields[k] = v);
}
noSuchMethod(InvocationMirror invocation) {
if(fields.containsKey(invocation.memberName)) {
return fields[invocation.memberName];
} else {
super.noSuchMethod(InvocationMirror invocation);
}
}
}
It looks like InvocationMirror is not implemented yet. How so? I downloaded Dart's SDK for Mac from the official site. Is this somewhat an older version, which doesn't have this class?
Post a Comment