I've just started exploring Dart language and I wanted to test an existing code that I wrote in Java as given:
public interface Condition {
Condition FALSE = facts->false;
Boolean evaluate(Fact<?> fact);
default Condition and(Condition other) {
return fact-> this.evaluate(fact) && other.evaluate(fact);
}
default Condition or(Condition other) {
return fact-> this.evaluate(fact) || other.evaluate(fact);
}
}
And the caller calls it as:
#Test
public void testCondition() {
String str = "A String";
Condition a = fact -> !str.isBlank();
Condition b = fact -> str.contains("A");
a.and(b);
}
A complete test class that makes use of this is :
public class AnonymousLoopTest {
#Test
public void test() {
RulesEngine rulesEngine = new InferenceRuleEngine();
List<Name> names = NamesFactory.fetchNames();
Rules rules = new Rules();
Facts facts = new Facts();
AtomicReference<Integer> countRef = new AtomicReference<>(1);
names.forEach(personName -> {
facts.put("name-" + countRef.get(), personName);
countRef.set(countRef.get()+1);
Condition condition = fact -> !personName.name().isEmpty();
//Hack the comparator logic of DefaultRule/BasicRule in order to override its internal logic as below.
//This is needed to register our Rule with Rules which uses a Set<Rule> to register new Rules
//with the comparator logic written in BasicRule.
Rule nameRule = new RuleBuilder((o1, o2) -> personName.name().compareTo(o1.getName()))
.when(condition).then(action -> System.out.println("In Action:" + personName)).build();
rules.register(nameRule);
});
rulesEngine.fire(rules, facts);
}
}
record Name(Integer id, String name){}
class NamesFactory{
static List<Name> fetchNames(){
return List.of(new Name(10, "Sara"), new Name(20, "Zara"), new Name(30, ""),new Name(40, "Lara"));
}
}
The condition is used by when() method.
In the given example the blank name will be filtered out. The other three names will be printed.
I was trying to write and equivalent in Dart but I'm just stuck. What is the way to write this code in Dart?
That looks like something I'd do by:
typedef Condition = bool Function(Fact);
bool falseCondition(Fact _) => false;
extension ConditionComposition on Condition {
Condition operator &(Condition other) => (Fact fact) => this(fact) && other(fact);
Condition operator |(Condition other) => (Fact fact) => this(fact) || other(fact);
Condition operator ~() => (Fact fact) => !this(fact);
}
If you insist on having a wrapper class for the function objects, I'd do it as:
class Condition {
static const Condition falseCondition = Condition(_kFalse);
final bool Function(Fact) _test;
const Condition(bool test(Fact fact)) : _test = test;
bool evaluate(Fact fact) => _test(fact);
Condition operator &(Condition other) => Condition((fact) =>
this.evaluate(fact) && other.evaluate(fact));
Condition operator |(Condition other) => Condition((fact) =>
this.evaluate(fact) || other.evaluate(fact));
static bool _kFalse(_) => false;
}
but a class seems overkill for something which really is just a simple function. Dart has first class functions.
You can use the former version as:
test("test Condition", () {
var str = "A String";
Condition a = (fact) => str.isNotEmpty();
Condition b = (fact) => str.contains("A");
var both = a & b;
expect(both(someDefaultFact), true);
}
Related
This is what I want to implement:
void fun({
bool Function(int i) predicate = (i) => false,
}) {
// do something with 'predicate(something)'
}
But I am getting the error:
The default value of an optional parameter must be constant.dart(non_constant_default_value).
I was able to get arround this error with the following:
bool falsePredicate(int i) => false;
void fun({
bool Function(int i) predicate = falsePredicate,
}) {
// do something with 'predicate(something)'
}
But now the question becomes, why can't I directly create a default function value as in the first set of code? There seems to be no difference between the first and the second cases. How is the function given in the first approach not constant?
As #Noah has pointed to the git discussion, the dart language has this missing piece of compile-time constant functions, which eventually leads to this problem.
Check this post: https://github.com/dart-lang/language/issues/1048
As the post shows, the issue has been raised in mid-2012 and now it's been 8+ years. So the hopes of this being available in the near feature is very less.
However few alternative solutions till then:
Option 1 (separate method):
class ServiceProvider {
static bool falsePredicate(int i) => false;
void fun({
bool Function(int i) predicate = falsePredicate,
}) {
// do something with 'predicate(something)'
}
}
Option 2 (Null checking while using the predicate)
class ServiceProvider {
void fun({
bool Function(int i)? predicate,
}) {
int val = 55; // for demonstration
predicate?.call(val); // Call only if the predicate is non-null
}
}
Option 3 (Only for class constructors)
class ServiceProvider {
final bool Function(int i) _predicate;
ServiceProvider ({bool Function(int i)? predicate})
: _predicate = predicate ?? ((i) => false);
void fun() {
int val = 55;
_predicate(5); // No null check is needed. The predicate is always non-null
}
}
I have a dart list of objects, every of which contains book_id property, and I want to find an element of that list by the book_id field.
Use firstWhere method: https://api.flutter.dev/flutter/dart-core/Iterable/firstWhere.html
void main() {
final list = List<Book>.generate(10, (id) => Book(id));
Book findBook(int id) => list.firstWhere((book) => book.id == id);
print(findBook(2).name);
print(findBook(4).name);
print(findBook(6).name);
}
class Book{
final int id;
String get name => "Book$id";
Book(this.id);
}
/*
Output:
Book2
Book4
Book6
*/
Null-Safe approach (handling no-element error)
If the searched item might or might not be in the array, with null safety I personally prefer to use .where on lists - it filters through the array and returns a list.
var myListFiltered = myList.where((e) => e.id == id);
if (myListFiltered.length > 0) {
// Do stuff with myListFiltered.first
} else {
// Element is not found
}
The benefit of this approach is that you'll always get an array and there won't be an issue with element not being found or trying to return null through orElse callback:
The return type 'Null' isn't a 'FooBar', as required by the closure's context.
Refactoring the finder logic into a helper method
Since the task of finding an element by id in a list of objects is quite a common one, I like to extract that logic into helpers file, for example:
class Helpers {
static findById(list, String id) {
var findById = (obj) => obj.id == id;
var result = list.where(findById);
return result.length > 0 ? result.first : null;
}
}
And use it like this:
var obj = Helpers.findById(myList, id);
if (obj == null) return; //? Exn: element is not found
A lot has been said already, but I want to add my best way to do this. if it's possible that the item doesn't exist in the list, import the iterable extension and use firstWhereOrNull1 on the list.
import 'package:collection/src/iterable_extensions.dart';
myList.firstWhereOrNull((item) => item.id == id))
You should add orElse to avoid exeption:
list.firstWhere(
(book) => book.id == id,
orElse: () => null,
});
To avoid having to add orElse to every use of firstWhere, with Dart 2.7+, you can create a handy little extension to handle this:
extension IterableX<T> on Iterable<T> {
T safeFirstWhere(bool Function(T) test) {
final sublist = where(test);
return sublist.isEmpty ? null : sublist.first;
}
}
Which can then be used as such:
final books = List<Book>.generate(10, (id) => Book(id));
final matchingBooks = books.safeFirstWhere((book) => book.id == id);
void main(){
List lights=[
{"id":1,"color":"yellow"},
{"id":2,"color":"green"},
{"id":3,"color":"red"}
];
int searchId = 2;
var colr = lights.firstWhere((x) => x['id'] == searchId, orElse:() => {"color" : "Color Not found"})['color'];
print(colr);
}
The above code searches the obj list, using firstWhere. If not found returns text 'Color not found'
I trying make the following code but T only can be int, double or a custom class. I couldn't find how to restrict the type in Dart or something that work like where from C#. How can I do that in Dart?
class Array3dG<T> extends ListBase<T> {
List<T> l = List<T>();
Array3dG(List<T> list) {
l = list;
}
set length(int newLength) { l.length = newLength; }
int get length => l.length;
T operator [](int index) => l[index];
void operator []=(int index, T value) { l[index] = value; }
}
There is no way to constrain the type variable at compile-time. You can only have one bound on a type variable, and the only bound satisfying both int and your custom class is Object.
As suggested by #Mattia, you can check at run-time and throw in the constructor if the type parameter is not one of the ones you supprt:
Array3dG(this.list) {
if (this is! Array3dG<int> &&
this is! Array3dG<double> &&
this is! Array3dG<MyClass>) {
throw ArgumentError('Unsupported element type $T');
}
}
This prevents creating an instance of something wrong, but doesn't catch it at compile-time.
Another option is to have factory methods instead of constructors:
class Array3dG<T> {
List<T> list;
Array3dG._(this.list);
static Array3dG<int> fromInt(List<int> list) => Array3dG<int>._(list);
static Array3dG<int> fromDouble(List<double> list) => Array3dG<double>._(list);
static Array3dG<MyClass> fromMyClass(List<MyClass> list) => Array3dG<MyClass>._(list);
...
}
which you then use as Array3dG.fromInt(listOfInt). It looks like a named constructor, but it is just a static factory method (so no using new in front).
You can check at runtime the type with the is keyword:
Array3dG(List<T> list) {
if (list is List<int>) {
//Handle int
}
else if (list is List<double>) {
//Handle double
}
else if (list is List<MyClass>) {
//Handle MyClass
}
else {
throw ArgumentError('Unsupported $T type');
}
}
Note that if you are handling int and double in the same way you can just check for num
You can check the progress of the Union types here: https://github.com/dart-lang/sdk/issues/4938
I am using a Gee.ArrayList with an own class for content. I want to use the "contains" method of the ArrayList, but I really don't know how to set up an equals-method in my class, so ArrayList uses it to find out if the object is in the ArrayList or not.
Example:
class Test : GLib.Object {
public int number;
public Test(int n) {
number = n;
}
public bool equals (Test other) {
if (number == other.number) return true;
return false;
}
}
Then, in another file:
var t = new Gee.ArrayList<Test>();
var n1 = new Test(3);
var n2 = new Test(3);
t.add(n1);
t.contains(n2); // returns false, but I want it to return true
Does anybody know that?
When you create the ArrayList, the constructor takes your equality comparator. You can do:
var t = new Gee.ArrayList<Test>(Test.equals);
and the contains should work as you desire.
Let's say I have this code inside a class:
String _str;
String get str => _str;
void set(String s) {
assert(_str == null);
_str = s;
}
How could I ensure that only the setter and getter have access to _str? This would be to prevent that anything inside the same class would be unable to bypass the condition.
There is no way. In Dart privacy is per library. Everything within one library can read/write everything else within that library.
I would go for
String __str;
String get str => __str;
void set(String s) {
assert(__str == null);
__str = s;
}
and just never access members that start with two underscores except from within the associated getter/setter pairs.
I do this sometimes when I want a private field with private getter setter like
String __str;
String get _str => __str;
void _set(String s) {
assert(_str == null);
__str = s;
}
A weird workaround would be to create a class in another library like
class StringProperty {
String _str;
String get value => _str;
void set value(String s) {
assert(_str == null);
_str = s;
}
}
and then use it in your library like
final StringProperty str = new StringProperty();
You can then access the value then like
str.value = 'abc';
print(str.value);
and in no other way.