Question

Je souhaite implémenter le cache d'appels (mémoisation) de manière non intrusive avec les annotations de métadonnées.

Espérons que cela fonctionnera comme ceci :

class A{
  @Cached
  foo(msg) {
    return msg;
  }
}

void main() {
  @Cached
  var foo = ()=>"hello";
}

Peut-on y parvenir avec seulement dart:mirrors ?

Était-ce utile?

La solution

J'ai écrit un article de blog complet sur ce sujet il y a quelque temps.C'est trop long à copier ici, alors voici le lien :

http://dartery.blogspot.com/2012/09/memoizing-functions-in-dart.html

Le résultat est que vous pouvez écrire des fonctions de mémorisation d'ordre supérieur, mais elles sont généralement limitées par le manque de fonctions d'arguments flexibles de Dart.De plus, si vous souhaitez utiliser la programmation dynamique avec des fonctions récursives, vous devez écrire votre fonction en gardant à l'esprit la mémorisation - elle doit se prendre comme argument, afin que vous puissiez transmettre la version mémorisée.

Autres conseils

Ma solution actuelle permet :

class B {
  @CachedCallName(#cachedBaz)
  baz() => print("first call to baz");
}
class A extends B with CacheableCalls {
  @CachedCallName(#foo)
  _foo(msg) {
    print("first call with: $msg");
    return msg + msg;
  }
}
void main() {
  A a = new A();
  print(a.foo(21));
  print(a.foo(21));
  a.cachedBaz();
  print(a.foo(22));
  a.cachedBaz();
}

Sortir:

premier appel avec :21
42
42
premier appel à baz
premier appel avec :22
44

Défauts:
- impossible de mettre en cache les méthodes avec leurs noms réels.
- peut étendre la vue de la collection mais ne peut pas mettre en cache les opérateurs existants comme operator []
- impossible de mettre en cache les fonctions.

Source complète :

@MirrorsUsed(metaTargets: CachedCallName)
import 'dart:mirrors';

class CachedCallName {
  final Symbol name;
  const CachedCallName(this.name);
}
@proxy
class CacheableCalls {
  Map _cache = new Map();
  dynamic _chacheInvoke(InstanceMirror thisMirror, Symbol
      methodName, Invocation invocation) {
    String key = "$methodName${invocation.positionalArguments}"
        "${invocation.namedArguments}";
    if (_cache.containsKey(key)) {
      return _cache[key];
    } else {
      InstanceMirror resultMirror = thisMirror.invoke(methodName,
          invocation.positionalArguments, invocation.namedArguments);
      _cache[key] = resultMirror.reflectee;
      return resultMirror.reflectee;
    }
  }
  dynamic noSuchMethod(Invocation invocation) {
    bool isFound = false;
    var result;
    Symbol called = invocation.memberName;
    InstanceMirror instanceMirror = reflect(this);
    ClassMirror classMirror = instanceMirror.type;
    classMirror.instanceMembers.forEach((Symbol name, MethodMirror mm) {
      mm.metadata.forEach((InstanceMirror im) {
        if (im.reflectee is CachedCallName) {
          if (im.reflectee.name == called) {
            isFound = true;
            result = _chacheInvoke(instanceMirror, name, invocation);
          }
        }
      });
    });

    if (isFound) {
      return result;
    } else {
      throw new NoSuchMethodError(this, called,
          invocation.positionalArguments, invocation.namedArguments);
    }
  }
}
class B {
  @CachedCallName(#cachedBaz)
  baz() => print("first call to baz");
}
class A extends B with CacheableCalls {
  @CachedCallName(#foo)
  _foo(msg) {
    print("first call with: $msg");
    return msg + msg;
  }
}
void main() {
  A a = new A();
  print(a.foo(21));
  print(a.foo(21));
  a.cachedBaz();
  print(a.foo(22));
  a.cachedBaz();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top