So I have this code:
import 'package:quiver/core.dart';
class ZipItem<I1, I2>{
I1 item1;
I2 item2;
ZipItem(this.item1, this.item2);
#override
bool operator ==(Object other) =>
identical(this, other) ||
(other is ZipItem &&
item1 == other.item1 &&
item2 == other.item2);
#override
int get hashCode => hash2(item1.hashCode, item2.hashCode);
and when I run a test like expect(ZipItem('a', 1), ZipItem('a', 1));, it passes. However if I try to run a test like this:
expect(ZipItem([1,2,3], ['a','b','c']),
equals(ZipItem([1,2,3], ['a','b','c'])));
it fails, and I can't figure out why. I think it has to do with the items being iterable but I am not sure. If anybody can help me out I'd appreciate it :).
The collection package has many utilities for calculating collection equality (and hash codes).
When dealing with generic types as you are, DeepCollectionEquality is most appropriate, as it uses the right equality checking behavior based on the types of the objects provided to it.
Alternatively, you may find the equatable package useful. It aims to simplify the process of implementing == and hashCode, and implements collection equality out-of-the-box.
Related
Consider code below:
mixin M {}
abstract class I {}
class A = I with M;
class B = I with M;
void main() {
final A? a = A();
final B? b = B();
final I? i1 = a ?? b; // compilation error saying "A value of type 'Object?' can't be assigned to a variable of type 'I?'"
}
Could you please help me to understand why I am having compilation error using "??" operator.
Dart 2.19.0
The a ?? b expression needs to figure out a single type which represents the two possible resulting values, one of type A or one of type B?.
Rather than checking that both A and B? are assignable to I?, it tries to figure out the type of the result of a ?? b as a single type combining both A and B?, which means finding a supertype of both A and B.
To do that, it computes an upper bound using the language-specified "least upper bound" algorithm. (I quote the name, because it finds an upper bound, which is sometimes a least upper bound, but not always.)
The two types are:
A with immediate supertypes I and M, both of which have immediate supertype Object, which has supertype Object? (and all other top types).
B? with supertypes I?, M? and their supertype Object?.
The problem here is that while it can see that I and I? occur in those types, and it can therefore decide that I? is an upper bound,
it also finds M and M? and decides that M? is an upper bound,
and those two types are otherwise completely equivalent, they have the same length of the super-class chain up to Object and are not related to each other. Neither is a least upper bound. So the algorithm ignores them and look for something that's both shared and does not have another type of equal "depth from Object". And it finds Object?.
Which is not assignable to I.
This is a known shortcoming (among several) of the least upper bound algorithm in Dart, but it's a hard problem to solve optimally, because it's very, very easy for a class to introduce some internal private superclass, and sometimes that type then becomes the least upper bound of two public subclasses, leaving users scratching their head.
There are requests to do better, for example by not ignoring the context type, but changing the type inference has to be done very carefully. It can break existing code which has been fine-tuned to the current behavior.
There are no great workarounds here, but there are functional ones.
You will have to rewrite the code to ensure that the static type of the two branches do not both have the unnecessary M type in them.
Rather than down-casting the result to I? at the end, which requires a runtime type check, I'd up-cast the original values:
final I? i3 = a ?? (b as I?); // ignore: unnecessary_cast
That should be completely free up-casts, but may (will!) cause analyzer warnings that you'll have to ignore.
Compiler doesn't seem to recognise that objects a and b are of classes inherited of I in that case.
So the syntax does the same, but in the first case needs help with casting.
final I? i1 = (a ?? b) as I?;
This does not give an error.
Once I have a constraint problem, I would like to see if it is satisfiable. Based on the returned model (when it is sat) I would like to add assertions and then run the solver again. However, it seems like I am misunderstanding some of the types/values contained in the returned model. Consider the following example:
solv = z3.Solver()
n = z3.Int("n")
solv.add(n >= 42)
solv.check() # This is satisfiable
model = solv.model()
for var in model:
# do something
solv.add(var == model[var])
solv.check() # This is unsat
I would expect that after the loop i essentially have the two constraints n >= 42 and n == 42, assuming of course that z3 produces the model n=42 in the first call. Despite this, in the second call check() returns unsat. What am I missing?
Sidenote: when replacing solv.add(var == model[var]) with solv.add(var >= model[var]) I get a z3.z3types.Z3Exception: Python value cannot be used as a Z3 integer. Why is that?
When you loop over a model, you do not get a variable that you can directly query. What you get is an internal representation, which can correspond to a constant, or it can correspond to something more complicated like a function or an array. Typically, you should query the model with the variables you have, i.e., with n. (As in model[n].)
You can fix your immediate problem like this:
for var in model:
solve.add(var() == model[var()])
but this'll only work assuming you have simple variables in the model, i.e., no uninterpreted-functions, arrays, or other objects. See this question for a detailed discussion: https://stackoverflow.com/a/11869410/936310
Similarly, your second expression throws an exception because while == is defined over arbitrary objects (though doing the wrong thing here), >= isn't. So, in a sense it's the "right" thing to do to throw an exception here. (That is, == should've thrown an exception as well.) Alas, the Python bindings are loosely typed, meaning it'll try to make sense of what you wrote, not necessarily always doing what you intended along the way.
If I have a object like this:
class MyClass<K>{...
How I could check type of K? If was a variable was easy,
ex:
(myVar is Object)... //true | false
But in my case, this dont works:
(K is Object) // awalys false
You want == here. Using is is for comparing the type of variable, not a literal type.
This will only check if K is actually Object if you use K == Object. If you pass K as int for instance, it will not be considered to be an Object.
I recommend not using == for comparison of Type objects. It only checks exact equality, which might be useful in a few situations, but in plenty of situations you do want a subtype check.
You can get that subtype check using a helper function like:
bool isSubtype<S, T>() => <S>[] is List<T>;
Then you can check either isSubtype<K, Object> to check if K is a subtype of Object (which is true for everything except Null and types equivalent to Object?, but that can also be checked like null is! K), or isSubtype<Object, K> to check whether K is a supertype of Object.
It has the advantage that you can compare to any type, not just types you can write literals for. For example K == List only works for List<dynamic>. If you need to check whether K is a List<int>, you can do isSubtype<K, List<int>>.
You can get equivalence of types (mutual subtype), without requiring them to be the same type, by doing isSubtype in both directions. For example isSubtype<Object?, dynamic>() and isSubtype<dynamic, Object?>() are both true, but if K is Object? then K == dynamic is false.
There is a linter rule which verifies that one don't check for null equality in the overridden == operator.
The rule is here.
I understand this rule but can't see how it is realized technically.
It seems that Dart itself makes some implicit check on other != null and == returns false in this case. Is this correct?
In other languages, e.g. Java, one needs to explicitly add this check in the overridden equals.
Second question is why then it does not check automatically on the type of other as well. Why it is ok to spare me as a programmer from checking on null, but I still need to check if other is Person? Are there cases when one overrides == and checks there for some other type then the type of that class?
The linter rule implementation is simple, it just checks whether you compare the argument of operator == to null.
The reason you don't need to is that e1 == e2 in Dart is defined to first evaluate e1 and e2 to a value, then give a result early if one or both of the values is null, and only otherwise it calls the operator== method on the value of e1.
So, when that method is called, you know for certain that the argument is not null.
The reason the == operator doesn't do more checks before calling the operator== method is that there are examples where that would be wrong.
In particular, int and double can be equal to each other. Having instances of different classes potentially being equal to each other is more common that you'd think (proxies, mocks, wrappers, Cartesian point vs polar point, int vs double).
The other check you could potentially do early is to say that an object is equal to itself, so if (identical(this, other)) return true;, but there is one counter-example forced upon the language: NaN, aka. double.nan. That particular "value" is not equal to itself (which breaks the reflexivity requirement for ==, but is specified that way by the IEEE-754 standard which is what the CPUs implement natively).
If not for NaN, the language would probably have checked for identity before calling operator== too.
It seems that Dart itself makes some implicit check on other != null and == returns false in this case. Is this correct?
Yes.
Second question is why then it does not check automatically on the type of other as well. Why it is ok to spare me as a programmer from checking on null, but I still need to check if other is Person? Are there cases when one overrides == and checks there for some other type then the type of that class?
It's less common, but there can be cases where you might want to allow a different type on the right-hand-side of the equality. For example, the left-hand-side and right-hand-side might be easily convertible to each other or to a common type. Imagine that you created, say, a Complex number class and that you wanted Complex(real: 4.0, imaginary: 0.0) == 4 to be true.
From the doc:
no class can be equivalent to [null]
Meaning, when other is Person is true, then other != null is also true. This is because:
The null object is the sole instance of the built-in class Null.
(https://dart.dev/guides/language/spec)
So every instance check against any type but Null will return false for null:
class A {}
void main() {
final x = null;
final a = A();
print(x is Null); // true
print(x is A); // false
print(a is Null); // false
print(a is A); // true
}
I have a question about the some built-in primitives. Is possible to use the built-ins: difference, min, max, sum also for DateTime types or it is better to create custom built-ins for this purpose?
They work fine with integer and float but it seems not for DateTime types (or maybe the syntax I have used is wrong).
Your syntax isn't incorrect. First, we can jump over to Builtin's javadoc in order to identify what Builtins exist.
Selecting Max, as per your mention of it, can we go ahead and look up it's fully qualified class name on GrepCode. Once we get there, we notice that the parimary method that it implements is bodyCall(Node[], int, RuleContext), so let's take a look at it's implementation (as of 2.11.0) and see why it's behaving the way it is:
#Override
public boolean bodyCall(Node[] args, int length, RuleContext context) {
checkArgs(length, context);
BindingEnvironment env = context.getEnv();
Node n1 = getArg(0, args, context);
Node n2 = getArg(1, args, context);
if (n1.isLiteral() && n2.isLiteral()) {
Object v1 = n1.getLiteralValue();
Object v2 = n2.getLiteralValue();
Node res = null;
if (v1 instanceof Number && v2 instanceof Number) {
Number nv1 = (Number)v1;
Number nv2 = (Number)v2;
if (v1 instanceof Float || v1 instanceof Double
|| v2 instanceof Float || v2 instanceof Double) {
res = (nv1.doubleValue() > nv2.doubleValue()) ? n1 : n2;
} else {
res = (nv1.longValue() > nv2.longValue()) ? n1 : n2;
}
return env.bind(args[2], res);
}
}
// Doesn't (yet) handle partially bound cases
return false;
}
The important thing to note here is that the method will only bind a value if once of the instances are a derivative of java.lang.Number.
Note that if we look at the implementation (as of 2.11.0) of LessThan#bodyCall(Node[], int, RuleContext), we can trace it's behavior to use of Util that is sensitive to date/time objects.
If you have a rule that uses max(?a ?b ?c) to bind the maximum value to ?c, you can sometimes (if your rule has nice symmetry) use lessThan(?a ?b) to just limit the ways in which the rule gets bound (thus, achieving the same result). In the lessThan case, the rest of the rule can go on assuming that ?b was the greater value, all along. Again, this requires that your rule have a nice symmetry that, elsewhere, allows the binding of ?a and ?b without other constraints.
If you need an equivalent of Max that can use XSDDateTime literals, then you, indeed, may have to make some yourself. Thankfully, as the code for these Builtins show, it can actually be quite easy to create them.
On a more philosohpical note, I am uncertain whether this was a conscious decision by the developers or if it was, perhaps, a small oversight. I imagine that the comparison utilities (Util) used by LessThan may actually be newer than the Max builtin, so Max wasn't implemented in terms of it.