How to catch `IterableElementError.noElement` in Dart? - dart

I can catch StateError and check for the message string but that looks ugly
abstract class State {}
class FoundState implements State {
final int count;
FoundState(this.count);
}
class NotFoundState implements State {
}
foo() {
final Numlist = [1, 2, 3, 4, 5];
try {
final found = Numlist.firstWhere((x) => x == 1234);
return FoundState(found);
} on StateError catch (ex) {
if (ex.message == 'No element') { // Why string? an enum would have been better
return NotFoundState();
}
}
}
main() {
final x = foo();
print(x);
}
I think about comparing with IterableElementError.noElement but it is in an internal folder.

Related

How to get an enum from a String?

Minimal reproducible code:
abstract class FooEnum extends Enum {
// Some abstract methods...
}
enum One implements FooEnum { a, b }
enum Two implements FooEnum { x, y }
FooEnum getFooEnum(String string) {
// Too much boiler plate code, how to do it in a better way?
if (string == 'One.a') return One.a;
else if (...) // other cases.
}
Right now I'm doing it manually (error prone). So, how can I get an enum from a String?
If you only want to use pure dart without flutter or any packages you could do this:
FooEnum? getFooEnum(String string) {
final classValue = string.split('.');
if (classValue.length != 2) {
return null;
}
try {
switch (classValue[0]) {
case 'One':
return One.values.byName(classValue[1]);
case 'Two':
return Two.values.byName(classValue[1]);
}
} on ArgumentError {
return null;
}
return null;
}
With the collection package you could do this:
FooEnum? getFooEnum(String string) {
return (One.values.firstWhereOrNull((e) => e.toString() == string) ??
Two.values.firstWhereOrNull((e) => e.toString() == string)) as FooEnum?;
}
I haven't looked into why the cast is needed, but it was a quick way to fix the problem that occures without it.

how to get type of identifier dart-analyzer

I am processing method statements in a class and i want to find type of an identifier in those statements.
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:dstore/dstore.dart';
import 'package:dstore_generator/src/utils.dart';
import 'package:source_gen/source_gen.dart';
AstNode getAstNodeFromElement(Element element) {
AnalysisSession session = element.session;
ParsedLibraryResult parsedLibResult =
session.getParsedLibraryByElement(element.library);
ElementDeclarationResult elDeclarationResult =
parsedLibResult.getElementDeclaration(element);
return elDeclarationResult.node;
}
class SelectorsGenerator extends GeneratorForAnnotation<Selectors> {
#override
String generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
if (!(element is ClassElement)) {
throw Exception("Selectors should be applied on class only");
}
final className = element.name;
if (!className.startsWith("_")) {
throw Exception("Selectors functions class should start with _");
}
final modelName = className.substring(1);
final visitor = SelectorsVisitor(modelName);
final astNode = getAstNodeFromElement(element);
astNode.visitChildren(visitor);
return """
// Selector
""";
}
}
class SelectorsVisitor extends SimpleAstVisitor {
final String modelName;
final selectors = <String>[];
SelectorsVisitor(this.modelName);
#override
dynamic visitMethodDeclaration(MethodDeclaration node) {
final fields = convertParamsToFields(node.parameters);
if (fields.isEmpty || fields.length > 1) {
throw Exception(
"Selector functions should be only one param with app state");
}
final field = fields.first;
var name = node.name.toString();
if (node.returnType == null) {
throw Exception("You sould annontate return type of method ${name} ");
}
final rType = node.returnType.toString();
final sType = field.type;
final bvs = SelectorBodyVisitor(field.param!.identifier);
node.body.visitChildren(bvs);
// node.body.visitChildren(visitor)
return super.visitMethodDeclaration(node);
}
}
class SelectorBodyVisitor extends RecursiveAstVisitor {
final Identifier identifier;
final List<List<String>> depsList = [];
SelectorBodyVisitor(this.identifier);
List<String> getListOfPropAccess(PropertyAccess node) {
final result = <String>[];
final prop = node.propertyName.toString();
result.add(prop);
final target = node.target;
print("target type ${target.runtimeType}");
if (target is PropertyAccess) {
result.addAll(getListOfPropAccess(target));
} else if (target is PrefixedIdentifier) {
if (target.prefix.toString() == identifier.toString()) {
// I am trying to get identifier type here
print("IdentifierElement2 ${target.identifier.staticType}");
result.add(target.identifier.toString());
} else {
print("target is not identifier ${target.runtimeType} ${target}");
}
}
return result;
}
#override
dynamic visitPropertyAccess(PropertyAccess node) {
print("***&&& propsAccess ${node}");
final list = getListOfPropAccess(node);
final sa = node.toString().split(".").toList();
if (sa.length - 1 == list.length) {
// property access of state identifier
depsList.add(list.reversed.toList().take(2).toList());
}
print("Property access list ++++=== ++++++ ${list}");
}
#override
dynamic visitPrefixedIdentifier(PrefixedIdentifier node) {
print(
"**##### IdenAccess ${node} id: ${node.identifier} prefix : ${node.prefix} mid :${identifier.toString()}");
if (node.prefix.toString() == identifier.toString()) {
print("IdentifierElement1 ${node.identifier.staticType}");
depsList.add([node.identifier.toString()]);
} else {
print("identifier is not equal ${node.prefix == identifier}");
}
}
}
Example
class User {
final String name;
User(this.name)
}
class Model {
final User user;
Model(this.user)
}
#Selectors()
abstract class MySelectors {
static s1(Model model) {
final n = model.user.name; // i want to know type of name in code generation time , please check this line print("IdentifierElement2 ${target.identifier.staticType}"); in above code , where i am getting null
}
}
Found answer , I have to use getResolvedLibraryByElement instead of getParsedLibraryByElement in getAstNodeFromElement method.
Future<AstNode> getAstNodeFromElement(Element element) async {
AnalysisSession session = element.session;
final s = await session.getResolvedLibraryByElement(element.library);
final s2 = s.getElementDeclaration(element);
return s2.node;
}

How to implement call caching (Memoization)

I want to implement call cache(memoization) in non-intrusive way with the metadata annotations.
Hopefully, it will work like this:
class A{
#Cached
foo(msg) {
return msg;
}
}
void main() {
#Cached
var foo = ()=>"hello";
}
Can it be achieved with only dart:mirrors ?
I wrote a whole blog post on this topic a while ago. It's too long to copy here, so here's the link:
http://dartery.blogspot.com/2012/09/memoizing-functions-in-dart.html
The upshot is that you can write higher-order memoizing functions, but they're limited in generality by Dart's lack of flexible args functions. Also, if you want to use dynamic programming with recursive functions, you need to write your function with memoization in mind - it needs to take itself as an argument, so you can pass in the memoized version.
My current solution allows:
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();
}
Output:
first call with: 21
42
42
first call to baz
first call with: 22
44
Flaws:
- can't cache methods with their actual names.
- can extend collection view but can't cache existing operators like operator []
- can't cache functions.
Full source:
#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();
}

What can i do with a stored type?

Dart allows variables of types: Type type = SomeType; But for what purpose?
For example, foo bar baz are misapplications:
class A {
Type type = List;
foo() => new type();
type bar() {
return new List();
}
type baz = new List();
}
void main() {
Type type = String;
var str = "Hello Dart";
print(type == str.runtimeType);//true
print(str is String);//true
print(str is type); //type error.
}
I think this one is pretty neat:
void main() {
foo(Type t) {
switch (t){
case int: return 5;
case List: return [1,2,3]; // This one gets me every time :(
case String: return "Hello Dart!";
default: return "default";
}}
print(foo(10.runtimeType)); //5
print(foo([2,4,6].runtimeType)); //default
print(foo("lalala".runtimeType)); //Hello Dart!
print(foo(foo.runtimeType)); //default
}
Is its sole purpose to be the return type for methods like runtimeType and type matching ?
I don't think you can use it for generics. There you need type literals. But you can use it for reflection.
Just one simple example:
import 'dart:mirrors' as mirr;
class A {
String s;
A(this.s);
#override
String toString() => s;
}
void main() {
Type type = A;
var str = "Hello Dart";
mirr.ClassMirror cm = mirr.reflectType(type);
var s = cm.newInstance(new Symbol(''), [str]).reflectee;
print(s);
}
You could also create a Map with registered factories for different types to avoid the need for reflection.
(not tested)
class A {
String s;
int a = 0;
int b = 0;
int c = 0;
A(this.s);
A.extended(this.s, this.a, this.b, this.c);
#override
String toString() => '${super.toString()}: $s, $a, $b, $c';
}
void main(args) {
Type t = A;
registerType(t, (List args) => new A.extended(args[0], args[1], args[2], args[3]));
...
var a = getInstance(t, ['hallo', 1, 2, 3]);
}
Map<Type,Function> _factories = {};
void registerType(Type t, Function factory) {
_factories[t] = factory;
}
void getNewInstance(Type t, List args) {
return _factories[t](args);
}

Code equivalent of out or reference parameters in Dart

In Dart, how would I best code the equivalent of an (immutable/value/non-object) out or reference parameter?
For example in C#-ish I might code:
function void example()
{
int result = 0;
if (tryFindResult(anObject, ref result))
processResult(result);
else
processForNoResult();
}
function bool tryFindResult(Object obj, ref int result)
{
if (obj.Contains("what I'm looking for"))
{
result = aValue;
return true;
}
return false;
}
This is not possible in Dart. Support for struct value types, ref or val keywords were discussed on the Dart mailing list just like week. Here is a link to the discussion where you should let your desire be known:
https://groups.google.com/a/dartlang.org/d/topic/misc/iP5TiJMW1F8/discussion
The Dart-way would be:
void example() {
List result = tryFindResult(anObject);
if (result[0]) {
processResult(result[1]);
} else {
processForNoResult();
}
}
List tryFindResult(Object obj) {
if (obj.contains("What I'm looking for")) {
return [true, aValue];
}
return [false, null];
}
you can also use a tuple package like tuple-2.0.0
add tuple: ^2.0.0
to your pubspec.yaml
then any function can return many typed objects like this:
import 'package:tuple/tuple.dart';
Tuple3<int, String, bool?>? returnMany() {
return ok ? Tuple3(5, "OK", null) : null;
}
var str = returnMany().item2;
In your case:
void example() {
var result = tryFindResult(anObject);
if (result.item1) {
processResult(result.item2!);
} else {
processForNoResult();
}
}
Tuple2<bool, int?> tryFindResult(Object obj) {
if (obj.contains("What I'm looking for")) {
return Tuple2(true, aValue);
}
return Tuple2(false, null);
}
you can throw an exception too when no result.
void example() {
var result = tryFindResult(anObject);
try {
processResult(result);
} on NullException catch(e){
processForNoResult();
}
}
int tryFindResult(Object obj) { // throws NullException
if (obj.contains("What I'm looking for")) {
return aValue;
}
throw NullException();
}

Resources