What is the difference between == and === in Dart? - dart

Does Dart support == and === ? What is the difference between equality and identity?

Dart supports == for equality and identical(a, b) for identity. Dart no longer supports the === syntax.
Use == for equality when you want to check if two objects are "equal". You can implement the == method in your class to define what equality means. For example:
class Person {
String ssn;
String name;
Person(this.ssn, this.name);
// Define that two persons are equal if their SSNs are equal
bool operator ==(other) {
return (other is Person && other.ssn == ssn);
}
}
main() {
var bob = Person('111', 'Bob');
var robert = Person('111', 'Robert');
print(bob == robert); // true
print(identical(bob, robert)); // false, because these are two different instances
}
Note that the semantics of a == b are:
If either a or b are null, return identical(a, b)
Otherwise, return a.==(b)
Use identical(a, b) to check if two variables reference the same instance. The identical function is a top-level function found in dart:core.

It should be noted that the use of the identical function in dart has some caveats as mentioned by this github issue comment:
The specification has been updated to treat identical between doubles
like this:
The identical() function is the predefined dart function that returns
true iff its two arguments are either:
The same object.
Of type int and have the same numeric value.
Of type double, are not NaNs, and have the same numeric value.
What this entails is that even though everything in dart is an object, and f and g are different objects, the following prints true.
int f = 99;
int g = 99;
print(identical(f, g));
because ints are identical by their value, not reference.
So to answer your question, == is used to identify if two objects have the same value, but the identical is used to test for referential equality except in the case of double and int as identified by the excerpt above.
See: equality-and-relational-operators

As DART is said to be related to javascript, where the === exists, I wish not be downvoted very quickly.
Identity as a concept means that 1 equals 1, but 1.0 doesn't equal 1, nor does false equal 0, nor does "2" equal 2, even though each one evaluates to each other and 1==1.0 returns true.

It should be noted that in Dart, identical works similarly to Javascript, where (5.0 == 5) is true, but identical(5.0, 5) is false.

Related

How to `map` an `Iterable` partially in Dart?

Assuming I have a List as below:
final numbers = [1, 0, -1, 1, -3, 0];
I'd like to generate another list where 1 results in true and 0 results in false and skip the others. So, in other words, I'd like a method like map where I can also skip some elements. In terms of test, it would assert to:
expect(newList, equals([true, false, true, false]));
In this result, I'd like to skip -1 and -3 in the list.
How can I achieve this?
Environment
Dart 2.18.5
Use the .where() method to get a new iterable with only the elements satisfying a predicate, then use .map() to apply the transformation on the result.
final numbers = [1, 0, -1, 1, -3, 0];
final result = numbers.where((n) => n == 1 || n == 0).map((n) => n == 1);
print(result);
\\ (true, false, true, false)
The most direct version would be:
var result = numbers.expand<bool>((n) =>
n == 0
? const <bool>[false]
: n == 1
? const <bool>[true]
: const <bool>[]);
The expand method can do everything map and where can, plus more,
Not particularly efficient, but not all bad either.
Another approach is to use a sync* function:
var result = () sync* {
for (var number in numbers) {
if (number == 0) {
yield false;
} else if (number == 1) {
yield true;
}
}();
If you don't care about creating a list eagerly, that's a also the approach for a list literal:
var result = [for (var number in numbers)
if (number == 0) false else if (number == 1) true
];
Or:
const _map = {0: [false], 1: [true]};
var result = [for (var number in numbers} ...?_map[number]];
The options are endless. In practice, doing where and map is probably more readable.
Ariel's answer gave me a better idea. In the example of the question, what we'd like to filter out are two values, which are 1 and 0. The real problem I'm dealing with right now is more complicated than this one, it has a wide range of lookup list. I haven't specifically asked "What is a more programmatic way to do this?" or "What if the lookup list has more values?".
So, if the values I'm looking for are more than these two values, a List of lookup values and contains method would be better for my case.
final numbers = [1, 0, -1, 1, -3, 0];
final lookup = {1, 0};
final result = numbers.where((n) => lookup.contains(n)).map((n) => n == 1 ? true : false).toList();
print(result);
This has some drawbacks though, some of which that come to my mind are:
Performance is definitely worse than Ariel's answer. My solution uses contains, which will perform look-ups in lookup rather than a simple byte-comparison with n == 1. So, it isn't great with large lists.
hashCode must be overriden for non-primitives. It is easy to compare int with an int in this simple example, but if you have an instance, you need to override hashCode, otherwise Dart will compare the memory addresses rather than values.
Using another collection type for lookup other than Set might also have performance impact because Set is inherently O(1) while the others might depend on their standard library implementation, but it's safe to assume they're going to be worse than Set. (See Ariel's comment).
BTW, lookup does not have to be a Set. I've done it Set because lookup contains distinct values and the order is not important.
Iterable.map is a 1:1 mapping; if your input has n elements, then the output must have n elements too.
Using numbers.where(...).map(...) works, but alternatively:
Use Iterable.map first to map either to desired values or to an invalid sentinel value. If your sentinel value is null, then you can use Iterable.whereType to filter out them out:
var transformed = numbers.map((n) {
switch (n) {
case 0:
return false;
case 1:
return true;
default:
return null;
}
}).whereType<bool>();
You might prefer this if you want all of your logic in a single callback.
Use collection-for instead of Iterable.map and collection-if instead of Iterable.where:
var transformed = [
for (var n in numbers)
if (isValidValue(n))
transform(n),
];
where you define isValidValue and transform functions with your filtering and transformation logic respectively.

Dart firstWhere orElse: generic function return type

The code below defines a generic myFirstWhereFunction with 3 arguments:
Generic list
Generic value to search in the list
Generic default value to return if the searched value is not in the passed generic list
The code:
void main() {
const List<int> intLst = [1, 2, 3, 4];
print(myFirstWhereFunc(intLst, 4, -1));
print(myFirstWhereFunc(intLst, 5, -1));
const List<String> strLst = ['coucou', 'go', 'bold', 'tooltip'];
print(myFirstWhereFunc(strLst, 'go', 'not exist'));
print(myFirstWhereFunc(strLst, 'ok', 'not exist'));
}
T myFirstWhereFunc<T>(List<T> lst, T searchVal, T defaultVal) {
return lst.firstWhere((element) => element == searchVal, orElse: <T> () {
return defaultVal;
});
}
But this code generates an exception.
One solution is to replace the generic myFirstWhereFunc return type by dynamic (code below):
dynamic myFirstWhereFunc<T>(List<T> lst, T searchVal, T defaultVal) {
return lst.firstWhere((element) => element == searchVal,
orElse: () => defaultVal);
}
But is there another way of solving the problem ?
I believe that the problem is that when you do:
print(myFirstWhereFunc(intLst, 4, -1));
there are two possible ways to infer the type of myFirstWhereFunc:
Bottom-up (inside-out): myFirstWhereFunc is called with a List<int> and with int arguments, so its type could be myFirstWhereFunc<int>. This is what you want.
Top-down (outside-in): print has an Object? parameter, so myFirstWhereFunc could be myFirstWhereFunc<Object?> so that it returns an Object?. This is what actually happens and is what you do not want.
Dart ends up with two possible ways to infer the generic type parameter, both seem equally valid at compilation-time, and it picks the one that you happen to not want. Picking the other approach likely would result in undesirable outcomes for different code examples. Arguably inference could try both ways and pick the narrower type if one approach leads to a subtype of the other. I'm not sure offhand if that would break code, but I wouldn't be surprised. (I also suspect that it's been suggested in https://github.com/dart-lang/language/issues somewhere...)
Changing myFirstWhereFunc's return type to dynamic is a crude workaround to the problem because it makes myFirsyWhereFunc's type no longer inferrable from print's parameter type.
If you split the line up and use a temporary variable, inference can infer myFirstWhereFunc independently of print and then should do what you want:
var intResult = myFirstWhereFunc(intLst, 4, -1);
print(intResult);

Repast: how to get a particular agent set based on the specific conditions?

I am previously working with Netlogo and there are some very good built-in methods that allow me to filter and control the desired agents from the total population. (see: http://ccl.northwestern.edu/netlogo/docs/dictionary.html#agentsetgroup). For instance, I could very easily to command the different class of people agent in a simulation with simple codes like:
ask peoples with [wealth_type = "rich"] [donate money...]
ask peoples with [wealth_type = "poor"] [get money from rich people...]
In Repast, are there list of methods specifically built for easy controlling of agent set?
The equivalent in Repast Simphony Java is to use a Query. Queries apply a predicate to each agent in the Context and returns those that evaluate to true in an iterator. The PropertyEquals query evaluates an agent's property w/r to some value (e.g. "wealth_type" and "rich"). Note that "property" here refers to a Java property, i.e., a getter type method:
String getWealthType() {
return wealthType;
}
where "wealthType" is the name of the property.
As an example, in the JZombies example model, we can query Humans whose energy is equal to 5.
Query<Object> query = new PropertyEquals<Object>(context, "energy", 5);
for (Object o : query.query()) {
Human h = (Human)o;
System.out.println(h.getEnergy());
}
The query() iterator returns all the humans whose energy is equal to 5.
You can get a bit more complicated in the equivalence test by providing your own predicate. For example,
PropertyEqualsPredicate<Integer, Integer> pep = (a, b) -> {
return a * 2 == b;
};
Query<Object> query2 = new PropertyEquals<Object>(context, "energy", 8, pep);
for (Object o : query2.query()) {
Human h = (Human)o;
System.out.println(h.getEnergy());
}
Here, we are checking if the energy * 2 == 8. The predicate is passed the agent's property value in the first parameter and the value to compare against in the second parameter. Given that the predicate returns a boolean, you could also test for inequality, greater than etc.
Simphony has a variety of queries available. See,
https://repast.github.io/docs/api/repast_simphony/repast/simphony/query/package-summary.html
https://repast.github.io/docs/RepastReference/RepastReference.html#_repast_model_design_fundamental_concepts
for more info.
You can also do this in Simphony's ReLogo dialect:
ask (turtles()){
if (wealth_type == "rich") {
donateMoney()
}
if (wealth_type == "poor") {
getMoneyFromRichPeople()
}
}
If you want to just collect the richTurtles you can do (where "it" is the default method to access the individual turtle that is iterated over with findAll):
richTurtles = turtles().findAll{
it.wealth_type == "rich"
}
or with an explicit closure argument:
richTurtles = turtles().findAll{x->
x.wealth_type == "rich"
}

Missing Dart null checking shorthand?

I know that Dart has the null checking shorthands
x = y ?? z;
and
x = y?.z;
But what if I have a statement like
x = (y != null) ? SomeClass(y) : z;
I don't want to pass null to the SomeClass constructor - so in that case I want x to be set to z (in my specific situation z happens to be null).
I can't figure out how/if I can use any of the shorthands in this scenario, or if I'm stuck with the direct null check.
The short answer is: there is no shorthand. Your code is good.
The really short answer is: it depends. ;)
If you think about the surrounding codebase you can come up with a different architecture overall.
You may as well pass null to the constructor
x = SomeClass(y);
and then give a reasonable default in your initializer list:
class SomeClass {
dynamic _value;
SomeClass(value) _value = value ?? '';
}
or throw an exception:
var nullError = Exception('Null value not allowed');
class SomeClass {
dynamic _value;
SomeClass(value) _value = value ?? (throw nullError);
}
though a more idiomatic way would be this:
class SomeClass {
dynamic _value;
SomeClass(value) {
ArgumentError.checkNotNull(value);
_value = value;
}
As I know nothing about the rest of your code, I cannot give you the right answer.
But I suggest you to ask yourself:
Where does this z value come from? What is its meaning?
(If you're in big project, you may use Dependency Injection or Factories.)
Maybe I have a view component, where empty strings are more useful than nulls?
These are some things I would ask myself.
But if you're hacking a quick script, this maybe a long shot.
You may have already finished your task by now, and maybe you really had no need for a shorthand in the first place.

Using __arglist with a varying set of named parameters

in my application I have 2 layers. The first layer is a C legacy exposing cdecl functions that use the "..." syntax for a varying parameter list. The only way I found to call these functions from my .Net layer (the second one) is using the DllImport technics. For example the C function below:
int myFunc(char* name, ...);
looks like that in C#:
[DllImport("MyDll.dll"),
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.Cdecl]
int myFunc(string name, __arglist);
My problem is that sometimes I want to call this function with 2 extra parameters but if one of them is NULL it won't be included in the argument list (my legacy code fails on NULL values). For example I want this call:
int foo(string name, string a, string b)
{
myFunc(name, __arglist(a, b));
}
{
foo("john", "arg1", null);
}
to be interpreted by C as
myFunc("john", "arg1");
Unfortunately doing something like that:
int foo(string name, string a, string b)
{
List<string> args = new List<string>();
if(a != null) args.Add(a);
if(b != null) args.Add(b);
myFunc(name, __arglist(args));
}
{
foo("john", "arg1", null);
}
is interpreted by C like that:
myFunc(name, args);
and not:
myFunc(name, args[0]);
Does anybody have any idea?
How does the C function know which one is the last parameter? It cannot know a priori how many parameters there are. It needs additional information. One common way for functions get the information they need is by parsing the included string parameter to count format specifiers, as in printf. In that case, if the format string only indicates that there is one extra parameter, then the function doesn't know the difference between a call that really had just one extra parameter and a call that had two or a call that had 20. The function should have the self-discipline to only read one parameter, since that's all the format string said there was. Reading more would lead to undefined behavior.
If what I've described is not the way your function works, then there's not much you can do on the calling end to solve it. But if it is how your function works, then there's nothing to do on the calling end, because there's no problem.
Another option, since you indicate that your "legacy code fails on null values," is to fix your legacy code so it doesn't fail anymore.
A third option is to simply write all four possibilities:
if (a != null) {
if (b != null)
return myFunc(name, a, b);
else
return myFunc(name, a);
} else {
if (b != null)
return myFunc(names, b);
else
return myFunc(names);
}
More than two optional parameters, though, and the code starts getting unwieldy.
Try converting your System.List ToArray() before wrapping it in __arglist
myFunc(name, __arglist(args.ToArray()));

Resources