Pergunta

Quero implementar o cache de chamadas (memoização) de forma não intrusiva com as anotações de metadados.

Esperançosamente, funcionará assim:

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

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

Isso pode ser alcançado apenas com dart:mirrors ?

Foi útil?

Solução

Escrevi uma postagem inteira no blog sobre esse assunto há algum tempo.É muito longo para copiar aqui, então aqui está o link:

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

O resultado é que você pode escrever funções de memorização de ordem superior, mas elas são limitadas em geral pela falta de funções args flexíveis do Dart.Além disso, se você quiser usar programação dinâmica com funções recursivas, você precisa escrever sua função tendo em mente a memoização - ela precisa se considerar um argumento, para que você possa passar a versão memoizada.

Outras dicas

Minha solução atual permite:

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();
}

Saída:

primeira chamada com:21
42
42
primeira chamada para baz
primeira chamada com:22
44

Imperfeições:
- não é possível armazenar métodos em cache com seus nomes reais.
- pode estender a visualização da coleção, mas não pode armazenar em cache operadores existentes como operator []
- não é possível armazenar funções em cache.

Fonte completa:

@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();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top