Is it possble to change the whay the logical or || statement is executed in dart.
For example. I have the functions foo() and boo() which have a return type of bool. If i write
(foo() || boo()) ? /* A */ : /* B */;
and foo() returns true boo() would not be executed. I would like to be able to change that, but couldn't find a way to do so.
I was surprised to see that this will not help:
bool helper = false;
helper = helper || foo();
helper = helper || boo();
(helper) ? /* A */ : /* B */
boo() is only executed when foo() returns true, because the result would be false anyway (short-circuit). You have to force explicit execution like:
var f = foo();
var b = boo();
(f || b) ? print('false') : print('true');
If you want to use it inline you can use a custom method like mentioned by #AlexandreArdhuin or
[foo(), boo()].reduce((v1, v2) => v1 || v2)
? print('false') : print('true');
Try it in DartPad.
You can not use | in dart but you can write an helper function like or and have a syntax quite close:
main() {
if (or([foo(), boo()])) {
print('ok');
}
}
bool or(List<bool> values) => values.fold(false, (t, e) => t || e);
bool foo() {
print("foo");
return true;
}
bool boo() {
print("boo");
return true;
}
Try it in DartPad.
non-short-circuit boolean operators is the phrase you are looking for, and it is not possible at the moment, see https://github.com/dart-lang/sdk/issues/1080
Related
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);
}
I want to check, if my variable k has a type calles T.
My approach was
int k=1;
Type T=int;
if(k is T) print('same type');
But it is not working. It works, if I write
if(k is int)
but I want to change the type in a variable.
Thank you for an answer
You could store the type in a string, and then use runtimeType and toString() to compare the variable's type with the type stored in the string:
int k = 1;
String type = "int";
if (k.runtimeType.toString() == type){
print("k is an integer");
}
You can't do type checks using Type objects in Dart.
A Type object is not the type, it's just a token representing the type which can be used with the dart:mirrorsreflection library. It cannot, really, be used for anything else.
If you need to do type checking, you need to store the type as a type variable, which means you need something generic, or store it in plain code as a closure.
The closure approach is simpler, but less readable:
int k = 1;
var typeChecker = (o) => o is int;
if (typeChecker(o)) print("k has the right type");
Using a generic helper class is more general:
class Typer<T> {
bool isType(Object o) => o is T;
bool operator >=(Typer other) => other is Typer<T>;
bool operator <=(Typer other) => other >= this;
}
...
var k = 1;
var type = Typer<int>();
if (type.isType(k)) print("k is integer");
In short, don't use Type for anything except dart:mirrors because it isn't really useful for anything else.
Some Type in the Dart returns a different kind of Type when using .runtimeType.
For example:
void main() async {
List value = [];
print(value.runtimeType); // print -> JSArray<dynamic>
}
I am using:
void main() async {
List value = [];
print(isSameType(target: value, reference: <Object>[])); // print -> false
value = [Object()];
print(isSameType(target: value, reference: <Object>[])); // print -> false
value = <Object>[];
print(isSameType(target: value, reference: <Object>[])); // print -> true
}
bool isSameType({required target, required reference}) =>
target.runtimeType == reference.runtimeType;
class Object {}
But I saw many comments saying the .runtimeType is for debugging and some comments said it will be not available in the future. So I am using this instead of the code above:
void main() async {
var value;
value = [];
print(value.runtimeType); // print -> JSArray<dynamic>
print(isSameType<List>(value)); // print -> true
value = [Test];
print(value.runtimeType); // print -> JSArray<Type>
print(isSameType<List<Test>>(value)); // print -> false
print(isSameType<List>(value)); // print -> true
value = [Test()];
print(value.runtimeType); // print -> JSArray<Test>
print(isSameType<List<Test>>(value)); // print -> true
print(isSameType<List>(value)); // print -> true
value = <Test>[];
print(value.runtimeType); // print -> JSArray<Test>
print(isSameType<List<Test>>(value)); // print -> true
print(isSameType<List>(value)); // print -> true
}
bool isSameType<type>(target) => target is type;
class Test {}
Basic example for using:
void main() async {
MyObject phoneNumber = MyObject<int>();
phoneNumber = await getDataFromUser();
if (phoneNumber.isSameType()) await uploadData(phoneNumber);
}
class MyObject<type> {
MyObject({this.data});
dynamic data;
bool isSameType() => data is type;
}
Future<dynamic> getDataFromUser() async {
return null;
}
Future<bool> uploadData(data) async {
return false;
}
I have a dynamic x and I would like to assign x to T s if x is T, and otherwise assign null to s. Specifically, I would like to avoid having to type x twice, and to avoid creating a temporary. (For example, I don't want to have to write String s = map['key'] is String ? map['key'] : null; over and over, because I will have many such expressions.) I don't want there to be any possibility of a runtime error.
The following works:
class Cast<T> {
T f(x) {
if (x is T) {
return x;
} else {
return null;
}
}
}
// ...
dynamic x = something();
String s = Cast<String>().f(x);
Is there a syntactically nicer way to do this?
Dart 2 has generic functions which allows
T? cast<T>(x) => x is T ? x : null;
dynamic x = something();
String s = cast<String>(x);
you can also use
var /* or final */ s = cast<String>(x);
and get String inferred for s
I use the following utility function, which allows for an optional fallback value and error logging.
T tryCast<T>(dynamic x, {T fallback}){
try{
return (x as T);
}
on CastError catch(e){
print('CastError when trying to cast $x to $T!');
return fallback;
}
}
var x = something();
String s = tryCast(x, fallback: 'nothing');
Just use the as keyword
final tweet = tweets[index] as Tweet;
I'm using those with Dart null safety (Dart SDK >= 2.12):
T? castOrNull<T>(dynamic x) => x is T ? x : null;
T castOrFallback<T>(dynamic x, T fallback) => x is T ? x : fallback;
A combination of both prior two posts, without the logging.
Fallback defaults to null when not provided.
T cast<T>(dynamic x, {T fallback}) => x is T ? x : fallback;
This hidden gem was provided by one of Dart-Lang's maintainers:
extension AsExtension on Object? {
X as<X>() => this as X;
X? asOrNull<X>() {
var self = this;
return self is X ? self : null;
}
}
extension AsSubtypeExtension<X> on X {
Y asSubtype<Y extends X>() => this as Y;
}
extension AsNotNullExtension<X> on X? {
X asNotNull() => this as X;
}
// example
void main() {
num? n = 1 as dynamic;
n.as<int>().isEven;
n.asSubtype<int>().isEven; // `n.asSubtype<String>()` is an error.
n.asNotNull().floor();
n.asOrNull<int>()?.isEven; // Corresponds to `(n as? int)?.isEven`.
}
NOTE: If your object is of type dynamic, you have to cast it Object? first. The explanation for this can be found here: first one by Erik, a dart maintainer #Google and the second by a community member. Basically it boils down to dart not calling extension methods on receives of one of the following three types: dynamic, Never, or void as stated here.
CastError is deprecated, Instead use TypeError.
With null safety, you can try the below snippet. Where fallback is optional/nullable.
T? tryCast<T>(dynamic value, {T? fallback}) {
try {
return (value as T);
} on TypeError catch (_) {
return fallback;
}
}
Or without fallback -
T? tryCast<T>(dynamic value) {
try {
return (value as T);
} on TypeError catch (_) {
return null;
}
}
Usage -
final val = tryCast<String>(1) ?? "";
On Dart 1.0.0, I just tried:
class MyClass {
int x;
bool b;
MyClass(int x, [bool b = true]) {
if(?b) {
// ...
}
}
}
And am getting a compiler error on the ?b part:
The argument definition test ('?' operator) has been deprecated
So what's the "new" way of testing for whether or not an argument was supplied?
There is no way to test if an argument was provided or not. The main-reason for its removal was, that it was very complex to forward calls this way.
The generally preferred way is to use null as "not given". This doesn't always work (for example if null is a valid value), and won't catch bad arguments. If null is used, then the parameter must not have a default-value. Otherwise the parameter is not null but takes the default-value:
foo([x = true, y]) => print("$x, $y");
foo(); // prints "true, null"
So in your case you should probably do:
class MyClass {
int x;
bool b;
MyClass(int x, [bool b]) {
if(b == null) { // treat as if not given.
// ...
}
}
}
This makes new MyClass(5, null) and new MyClass(5) identical. If you really need to catch the first case, you have to work around the type-system:
class _Sentinel { const _Sentinel(); }
...
MyClass(int x, [b = const _Sentinel()]) {
if (b == const _Sentinel()) b = true;
...
}
This way you can check if an argument has been provided. In return you lose the type on b.
The argument definition test operator was deprecated because it was redundant with checking for null; an optional parameter that was omitted would get the value null, and the caller could've passed null explicitly anyway. So instead use == null:
class MyClass {
int x;
bool b;
MyClass(int x, [bool b]) {
if (b == null) {
// throw exception or assign default value for b
}
}
}
Does Dart support the concept of variable functions/methods? So to call a method by its name stored in a variable.
For example in PHP this can be done not only for methods:
// With functions...
function foo()
{
echo 'Running foo...';
}
$function = 'foo';
$function();
// With classes...
public static function factory($view)
{
$class = 'View_' . ucfirst($view);
return new $class();
}
I did not found it in the language tour or API. Are others ways to do something like this?
To store the name of a function in variable and call it later you will have to wait until reflection arrives in Dart (or get creative with noSuchMethod). You can however store functions directly in variables like in JavaScript
main() {
var f = (String s) => print(s);
f("hello world");
}
and even inline them, which come in handy if you are doing recusion:
main() {
g(int i) {
if(i > 0) {
print("$i is larger than zero");
g(i-1);
} else {
print("zero or negative");
}
}
g(10);
}
The functions stored can then be passed around to other functions
main() {
var function;
function = (String s) => print(s);
doWork(function);
}
doWork(f(String s)) {
f("hello world");
}
I may not be the best explainer but you may consider this example to have a wider scope of the assigning functions to a variable and also using a closure function as a parameter of a function.
void main() {
// a closure function assigned to a variable.
var fun = (int) => (int * 2);
// a variable which is assigned with the function which is written below
var newFuncResult = newFunc(9, fun);
print(x); // Output: 27
}
//Below is a function with two parameter (1st one as int) (2nd as a closure function)
int newFunc(int a, fun) {
int x = a;
int y = fun(x);
return x + y;
}