void main() => Foo() == 1;
class Foo {
#override
bool operator ==(Object other) {
print(super == this); // true
// print(this == super); // Compile error
return super == other;
}
}
There are 2 questions.
Why can't I do this == super?
If you look at the return statement return super == other, you can tell the operator == is called on the Object class, so is the entire == implementation not a call which has been delegated to the Object class?
Let me explain the 2nd question further if it wasn't clear. Let's say I check for
Foo() == 1
The == operator defined in Foo class will be invoked and there all I'm doing is return super == other that means Object's == operator is being invoked and the other is int, so where the Foo instance in above code is? Here, it is only Object and int. I think super is doing something else too, not sure what is.
To answer your questions:
You can't do this == super because super is not an expression which is explained if you try run the program (the analyzed could give a better explanation):
bin/stackoverflow.dart:7:19: Error: Can't use 'super' as an expression.
To delegate a constructor to a super constructor, put the super call as an initializer.
print(this == super); // Compile error
^^^^^
Which also make sense since super is not an object. It is a concept we can use to specify if we want to refer to fields/methods that are overridden. But we cannot use super as some kind of object since our object is not multiple objects in layers where you can extract a layer and then represent this as another object. Instead, our object is a combined implementation based on how you define your class.
Yes, you're basically calling the Object's == operator when you return super == other.
Supplementary example:
But remember, we are just calling the == operator defined in Object. Our object is still a combined data structure which can be illustrated by this example:
class A {
final int a = 5;
int getA() => a;
}
class B extends A {
int get a => 10;
int getA() {
return super.getA();
}
}
void main() {
print(B().getA()); // 10
}
You can see that even if we call super.getA() we are still operating on a B object where we have overridden the a field but we are calling the A.getA() method.
Related
I am trying to up-cast the subclass object but it is not working.
The following program compiles without any errors.
VideoStreamModel model = VideoStreamModel("");
VideoStream entity = model;
print(model); // prints VideoStreamModel
print(entity); // prints VideoStreamModel
print(entity as VideoStream); // prints VideoStreamModel
print(cast<VideoStream>(model)); // prints VideoStreamModel
I have written a testcase to test the relation of above two classes and it passes.
test('should be a subtype of VideoStream', () async {
expect(model, isA<VideoStream>());
});
What could be the problem here?
EDIT:
[deleted]
EDIT 2:
[deleted]
Edit 3:
Here is the complete code reproducing the error.
import 'package:equatable/equatable.dart';
import 'package:test/test.dart';
class A extends Equatable {
final String x;
A(this.x);
#override
List<Object> get props => [x];
}
class B extends A {
B(String x) : super(x);
A method() {
B b = B(x); // doing A b = A(x) makes the test pass
return b;
}
}
void main() {
B b = B("");
test('test', () async {
final expected = A(b.x);
final actual = b.method();
expect(actual, expected);
});
}
It generates the following assertion error:
Expected: A:<A>
Actual: B:<B>
print is calling the toString() on the object you are pointing at (in this case VideoStreamModel) which knows what type it is. When you are casting, you are not changing anything about the object itself but only how the compiler should see the object when it determines if you are allowed to use a given typed variable to point to the object.
So when you are doing entity as VideoStream you are really just telling the compiler that you "promise" that the entity can be seen as a VideoStream. But on runtime, this cast will be tested to see if it is true.
All of this is really not an issue since you should never test for the specific type of the object when you are programming Dart but instead use the is operator which tests if a given object is compatible with a given interface.
So e,g, (entity is VideoStream) will return true.
Updated part
You problem seems to be a misunderstanding of the use of Equatable. It is important to notice that Equatable are not only using the elements from props to determine if two objects are equal but it also looks at the runtimeType. You can see this from the implementation:
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Equatable &&
runtimeType == other.runtimeType &&
equals(props, other.props);
https://github.com/felangel/equatable/blob/master/lib/src/equatable.dart#L46
This means that:
A a = A("");
B b = B("");
print(a == b); // false
When you are using expect without any matcher, it will just make an == operation which is stated in the documentation:
matcher can be a value in which case it will be wrapped in an equals matcher
Since we (as stated before) cannot change the runtimeType of an object after its creation you need to implement your own == if you want the two object instances to be seen as equal since equatable does only see two objects as equal if they both is created from the same class and contains the same values defined with props.
What should IEquatable<T>.Equals(T obj) do when this == null and obj == null?
1) This code is generated by F# compiler when implementing IEquatable<T>. You can see that it returns true when both objects are null:
public sealed override bool Equals(T obj)
{
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
// Code when both this and obj are not null.
}
2) Similar code can be found in the question "in IEquatable implementation is reference check necessary" or in the question "Is there a complete IEquatable implementation reference?". This code returns false when both objects are null.
public sealed override bool Equals(T obj)
{
if (obj == null)
{
return false;
}
// Code when obj is not null.
}
3) The last option is to say that the behaviour of the method is not defined when this == null.
leppie is right. Just to elaborate on his answer (and confirm his suspicion that F# doesn't guarantee this != null): discriminated unions may be marked with the attribute [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] allowing cases to be represented by the value null. Option<'T> is such a type. The None case is represented by null at run-time. (None : option<int>).Equals(None) is syntactically valid. Here's a fun example:
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type Maybe<'T> =
| Just of 'T
| Nothing
[<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
member this.ThisIsNull() = match this with Nothing -> true | _ -> false
Decompiling ThisIsNull with Reflector shows
public bool ThisIsNull()
{
return (this == null);
}
And the result:
Nothing.ThisIsNull() //true
The reason F# does this (I suspect) to optimize empty lists as null.
By adding this check, it allows one to call an instance method on a null instance without any problems.
See my blog post from a while back.
In C#, this is irrelevant.
To answer the question:
It should return true as both instances are null and deemed equal.
If this is null, the code can't be called, so that case needn't be considered (in C# anyway, there are cases where languages allow a null object to have a method dereferenced though obviously if it internally examines any of its non-existent fields it will error. Consider:
return x.Equals(y);
If x is null, we don't even get to call into Equals for the null check to count.
Hence we need only consider:
public bool Equals(T obj)
{
if(obj == null)
return false;
//logic defining equality here.
}
Where the possibility of both objects being null does come up, is when we are examining them from a static == operator override or from an IEqualityComparer<T> implementation:
public bool Equals(T x, T y)
{
if(x == null)
return y == null;
if(y == null)
return false;
//logic defining equality here.
}
Note that a useful shortcut here if equality can be lengthy to determine (e.g. comparing long strings), then we may take advantage of the fact that identity entails equality - that is something is always equal to itself, even Ayn Rand could figure that out ;) There are also algorithms that make comparing an item with itself quite common, making this shortcut well worth including. In this case the identity comparison already includes the check for both being null, so we leave it out again:
public bool Equals(T x, T y)
{
if(ReferenceEquals(x, y))
return true;
if(x == null || y == null)
return false;
//logic defining equality here.
}
For most methods I assume undefined behavior when called with this==null. That's because most programmers write their code under the assumption that this!=null, which is guaranteed by the C# specification if the calling code is written in C#.
That's why every sane caller of x.Equals(y) should either know for sure that that x is not null, or add a manual null check.
In most cases I wouldn't call Equals directly at all, but instead use EqualityComparer<T>.Default.
I would definitelly go with option 1:
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
null object always equals null object.
Sample code is in the MSDN: http://msdn.microsoft.com/en-us/library/ms131190.aspx?ppud=4
If this==null you will get a runtime exception calling Equals() on that object.
I have a class in AngularDart as followings:
abstract class Validator {
Map validate(AbstractControl c);
}
Looking closely, this used to be (before we added strong-mode support):
abstract class Validator {
validate(AbstractControl c);
}
The issue that it technically supports returning a Future or Map.
I'd like to refactor this and properly type it using FutureOr:
abstract class Validator {
FutureOr<T> validate(AbstractControl c);
}
Will I be able to use an is check at runtime? (In DDC and dart2js)
void runValidator(Validator v) {
var result = v.validate(...);
if (result is Future) {
// async...
} else {
// sync...
}
}
Am I thinking about this correctly?
EDIT: As mentioned below, I mean
if (result is Future<T>) {
} else if (result is T) {
}
One more question, would validate match these two typedefs:
Future<Map> AsyncValidate(AbstractControl c);
Map SyncValidate(AbstractControl c);
Yes, you can do result is Future<Map>. The actual value returned by the validate method is either a Future or it's not. The static type of the function doesn't affect that, and since FutureOr<Map> isn't an actual class, you can't have an object that is "a FutureOr". It's either a real Future<Map> or it's a Map.
For the second question, that depends on what yo mean by "match".
You can override the method with a method that returns either Map or FutureMap:
abstract class Validator {
FutureOr<Map> validate(abstractControl c);
}
class AsyncValidator extends Validator {
Future<Map> validate(AbstractControl c) {...}
}
class SyncValidator extends Validator {
Map validate(AbstractControl c) {...}
}
That is, you can use one of the function types you mention as a Validator.validate, but not in the other direction.
typedef FutureOr<Map> Validate(AbstractControl c);
typedef Future<Map> AsyncValidate(AbstractControl c);
typedef Map SyncValidate(AbstractControl c);
Validator v = ...;
Validate f0 = v.validate; // Safe.
AsyncValidate f1 = v.validate; // BAD assignment.
SyncValidate f2 = v.validate; // BAD assignment.
Map syncValidate(AbstractControl c) { ... }
Future<Map> asyncValidate(AbstractControl c) { ... }
v = syncValidate; // Good assignment.
v = asyncValidate; // Good assignment.
In practice, the concrete validate method of the validator v will probably be assignable to one of f1 or f2, but its static type doesn't say which one, so both are considered bad assignments.
You should only very rarely have a non-abstract method that is declared as returning FutureOr. In most cases, it's better to just always return a Future or a non-Future, and declare the method as such. Then you can always use the function as returning FutureOr if you need to, but use the more precise type in cases where you need it.
Say I have a class that has many instance variables,. I want to overload the == operator (and hashCode) so I can use instances as keys in maps.
class Foo {
int a;
int b;
SomeClass c;
SomeOtherClass d;
// etc.
bool operator==(Foo other) {
// Long calculation involving a, b, c, d etc.
}
}
The comparison calculation may be expensive, so I want to check if other is the same instance as this before making that calculation.
How do I invoke the == operator provided by the Object class to do this ?
You're looking for "identical", which will check if 2 instances are the same.
identical(this, other);
A more detailed 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 ==(Person other) {
return (other.ssn == ssn);
}
}
main() {
var bob = new Person('111', 'Bob');
var robert = new Person('111', 'Robert');
print(bob == robert); // true
print(identical(bob, robert)); // false, because these are two different instances
}
You can use identical(this, other).
For completeness, this is a supplemental answer to the existing answers.
If some class Foo does not override ==, then the default implementation is to return whether they are the same object. The documentation states:
The default behavior for all Objects is to return true if and only if this object and other are the same object.
That's my way how I compare deep 2 Objects they're not the same:
class Foo{
String uid;
bool isActiv;
Foo(this.uid, this.isActiv){}
Map<String, dynamic> toJson() => _$FooToJson(this);
}
Foo A = Foo("alpha", true);
Foo B = Foo("alpha", true);
print(A.toJson().toString() == B.toJson().toString()); // true
B.uid = "beta";
print(A.toJson().toString() == B.toJson().toString()); // false
On a different yet similar note, in cases where the framework calls to check the equality among the objects e.g. in case of list.toSet() to get the unique elements from a list, identical(this, other) may not be a choice. That time the class must override the == operator and the hasCode() methods.
However for this case another way could be to use the equatable package. This saves a lot of boiler plate code and is especially handy when you have lot of model classes.
You can use Equatable library
class Foo extends EquatableMixin{
int? a;
int? b;
SomeClass? c;
SomeOtherClass? d;
Foo(this.a,this.b,this.c,this.d);
// this does the job, it overrides the hashcode and equals operator
// give all properties to this `props`
#override
List<Object> get props => [a,b,c,d];
}
class SomeOtherClass with EquatableMixin{
String name;
SomeOtherClass(this.name);
#override
List<Object> get props => [name];
}
class SomeClass with EquatableMixin{
String name;
SomeClass(this.name);
#override
List<Object> get props => [name];
}
Foo foo =
Foo(1,2,SomeOtherClass("roger"),SomeOtherClassObject("mack"));
Foo foo2 =
Foo(1,2,SomeOtherClass("roger"),SomeOtherClassObject("mack"));
print(foo == foo2) // prints true
So, we don't need to manually override == and hashcode() methods
the library will do that.
Note : the inner objects (SomeClass and SomeOtherClass) should also use EquatableMixin, we can extends this or use as a mixin too
Is there a method in the JDK that compares two objects for equality, accounting for nulls? Something like this:
public static boolean equals(Object o1, Object o2)
{
if (o1 == null)
{
return o2 == null; // Two nulls are considered equal
}
else if (o2 == null)
{
return false;
}
return o1.equals(o2);
}
It seems silly to write this method myself since I would think that it has to exist already somewhere.
Java 7.0 added a new handy class: Objects.
It has a method exactly for this: Objects.equals(Object a, Object b)
Apache Commons Lang has such a method: ObjectUtils.equals(object1, object2). You don't want generics on such a method, it will lead to bogus compilation errors, at least in general use. Equals knows very well (or should - it is part of the contract) to check the class of the object and return false, so it doesn't need any additional type safety.
FWIW, this was my implementation:
private static boolean equals(Object a, Object b) {
return a == b || (a != null && a.equals(b));
}
In my application, I know that a and b will always be the same type, but I suspect this works fine even if they aren't, provided that a.equals() is reasonably implemented.
public static boolean equals(Object object1, Object object2) {
if (object1 == null || object2 == null) {
return object1 == object2;
}
return object1.equals(object2);
}
If you are worried about NullPointerExceptions you could just test equality like:
if (obj1 != null && obj1.equals(obj2)) { ... }
The general contract of equals() is that a non-null object should never be equal to a null reference, and that the equals() method should return false if you are comparing an object to a null reference (and not throw a NPE).
Whenever I come across a need and think "this is so common Java must have it" but find it doesn't, I check the Jakarta Commons project. It almost always has it. A quick search of the commons-lang API (which has the most basic of common utilities) shows an equals() method that provides what you want.
Jakarta Commons Lang API has what you are looking for ObjectUtils.equals(Object,Object)