I'm using the same context, so my entities should always be equatable in code. Is it then better to use:
if (instance1 == instance2) //...
or
if (instance1.id == instance2.id) //...
i.e. which is faster? Presumably the hashcode - i.e. option 1?
Related
On dart tour page (https://dart.dev/guides/language/language-tour#getting-an-objects-type) these have a statement that testing variable type with "is" expression is more stable. Why is it so?
An is test is a subtype test.
If you do e is Iterable, you check whether the value of e implements Iterable<dynamic>, which includes any of List, Set and Queue, as well as all the subtypes of Iterable used internally by the runtime system, like _TakeIterable (which is used to implement Iterable.take).
It matches both values of type Iterable<Object> and Iterable<int>.
All of these are objects which can safely be used as an Iterable, and are intended to be used as such.
If you do e.runtimeType == Iterable, you are checking whether the Type object returned by e.runtimeType is equal to precisely the type Iterable<dynamic>. That will be false for any list, set or queue, for any actual iterable class which only implements Iterable, and even for something which returns the Type object of Iterable<int> or Iterable<Object?> from runtimeType.
I say that you check the object returned by e.runtimeType, not the run-time type of the value, because anyone can override the runtimeType getter.
I can make a class like:
class WFY {
Type get runtimeType => Iterable<int>;
}
void main() {
print(WFY().runtimeType == Iterable<int>); // True!
}
The value returned by runtimeType doesn't have to have any relation to the actual runtime type of the object.
Obviously it usually has, because there is no benefit in overriding runtimeType, because you shouldn't be using it for anything anyway,
Even if your code works today, say:
assert(C().runtimeType == C); // Trivial, right!
it might fail tomorrow if I decide to make C() a factory constructor which returns a subtype, _C implementing C.
That's a change that is usually considered non-breaking, because the _C class can do everything the C interface requires, other than having C as actual runtime type.
So, doing Type object checks is not stable.
Another reason using is is better than comparing Type objects for equality is that it allows promotion.
num x = 1;
if (x is int) {
print(x.toRadixString(16)); // toRadixString is on int, not on num
}
The is check is understod by the language, and trusted to actually guarantee that the value's runtime type implements the type you check against.
Comparing Type objects can mean anything, so the compiler can't use it for anything.
Some people like to use runtimeType in their implementation of ==, like;
class MyClass {
// ...
bool operator ==(Object other) =>
MyClass == other.runtimeType && other is MyClass && this.x == other.x;
}
This is intended to avoid subclass instance being equal to super-class instances when you ask the superclass, but not if you ask the subclass (the "ColorPoint problem", where ColorPoint extends Point with a color, and is equal to a another ColorPoint with the same coordinates and color, but if you ask a plain Point whether it's equal to a ColorPoint, it only checks the coordinates.)
This use of runtimeType "works", but is not without issues.
It means you cannot use mocks for testing.
It means you cannot create a subclass which doesn't extend the state, only the behavior, and which would want to be equal to the superclass instances with the same state.
And it means you do extra work, because you still need to cast the other object from Object to the surrounding type in order to access members, and Type object checks do not promote.
If possible, it's better to never allow subclasss of a concrete class that has a == method, and if you need to share other behavior, inherit that from a shared superclass.
(In other words: Don't extend classes that aren't intended to be extended, don't put == on classes which are intended to be extended.)
In this official Flutter example there is a class, which does not extend another class. So why int get hashCode has #override over it? I.e. there is nothing to override, no?
class Item {
final int id;
final String name;
final Color color;
final int price = 42;
Item(this.id, this.name)
// To make the sample app look nicer, each item is given one of the
// Material Design primary colors.
: color = Colors.primaries[id % Colors.primaries.length];
#override
int get hashCode => id;
#override
bool operator ==(Object other) => other is Item && other.id == id;
}
From hashCode property documentation:
All objects have hash codes. The default hash code represents only the identity of the object, the same way as the default operator == implementation only considers objects equal if they are identical (see identityHashCode).
And from Object class documentation
Because Object is the root of the Dart class hierarchy, every other Dart class is a subclass of Object.
Every class is a subclass of the Object class, therefore they will always have the same properties of it and this is what you are overriding.
And now if you are asking why to override both hashCode and equals, check this link
From the official docs
A hash code is a single integer which represents the state of the object that affects operator == comparisons. All objects have hash codes. The default hash code represents only the identity of the object, the same way as the default operator == implementation only considers objects equal if they are identical (see identityHashCode).
In other words every time you create an object of class Item, you generate a hashCode property for it as well.
So now if you want to check equality of two objects of class item, Dart (like Java) will check the equality by doing == of the hashcode.
Which means that Item object1 != Item Object2 since each object will have its own unique hashcode.
Hence, the hashcode has to be overriden, in this case so that Item object1 can be checked for equality with Item object2
Does the Map class in Dart have a way to ignore case if the key is a string?
Eg.
var map = new Map<String, int>(/*MyComparerThatIgnoresCase*/);
map["MyKey"] = 42;
var shouldBe42 = map["mykey"];
In C# the Dictionary constructor takes a comparer like the comment above. What is the canonical way to do this in Dart?
Maps in Dart have an internal method that compares keys for equality. So far as I know, you can't change this for the default Map class. However, you can use the very similar core LinkedHashMap class, which not only allows, but requires that you specify a key equality method. You can check out more about LinkedHashMaps at https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:collection.LinkedHashMap
LinkedHashMap<String, String> map = new LinkedHashMap(
(a, b) => a.toLowerCase() == b.toLowerCase(),
(key) => key.toLowerCase().hashCode
);
map['Foo'] = 'bar';
print(map['foo']); //bar
The way to create a HashMap with a custom equals function (and corresponding custom hashCode function) is to use the optional parameters on the HashMap constructor:
new HashMap<String,Whatever>(equals: (a, b) => a.toUpperCase() == b.toUpperCase(),
hashCode: (a) => a.toUpperCase().hashCode);
I really, really recommend finding a way to not do the toUpperCase on every operation!
You can also do this using package:collection's CanonicalizedMap class. This class is explicitly designed to support maps with "canonical" versions of keys, and is slightly more efficient than passing a custom equality and hash code method to a normal Map.
Dart has a nifty
CaseInsensitiveEquality().equals(String a, String b)
in their
import 'package:collection/collection.dart';
It returns a bool and worked great for me when I was translating strings back to an enum. You do have to run dart pub add collection at the command line to install the package.
I have a scenario where I have a property that is data-bound using polymer.dart, but it does not have its own backing field. Instead it is dynamically evaluated at run-time by logic which is dependent on a lot of other internal conditions. So when other logic dictates I want to tell the data-binding to update the value. In C#/XAML the NotifyPropertyChange does not require you to pass in old and new value so it is easy to solve this. But in polymer.dart we do need to pass old and new value always, which is not possible for a dynamically evaluated property (or at least not preferable for performance reasons). How would we handle this in polymer.dart?
Here is a pseudo example. The question is what I should put in the ??? fields?
class MyBoundClass extends Observable {
void run() {
... logic, sets values in several internal non-observable objects...
notifyPropertyChange(#status, ???, ???);
}
String get status {
result = ... logic, evaluates values from several internal non-observable objects...
return result;
}
}
I guess one solution would be to simply introduce another backing field in MyBoundClass. But what I really want is just to update the binding and I don't see why it required to pass the old value. It seems to me that if you just want to update the binding, the old value is not relevant?
Passing null as old value should do.
I'm working on the verification of an interface formalised in the OMG's IDL, and am having problems finding a definitive answer on the semantics of getting an attribute value. In an interface, I have an entry...
interface MyInterface {
readonly attribute SomeType someName;
};
I need to know if it is acceptable for someObj.someName != someObj.someName to be true (where someObj is an instance of an object implementing MyInterface).
All I can find in OMG documentation in regards to attributes is...
(5.14) An attribute definition is logically equivalent to declaring a
pair of accessor functions; one to retrieve the value of the attribute
and one to set the value of the attribute.
...
The optional readonly keyword indicates that there is only a single
accessor function—the retrieve value function.
Ergo, I'm forced to conclude that IDL attributes need not be backed by a data member, and are free to return basically any value the interface deems appropriate. Can anyone with more experience in IDL confirm that this is indeed the case?
As we know, IDL interface always will be represented by a remote object. An attribute is no more then a syntatic sugar for getAttributeName() and setAttributeName(). Personally, i don't like to use attribute because it is hardly to understand than a simply get/set method.
CORBA also has valuetypes, object by value structure - better explaned here. They are very usefull because, different from struct, allow us inherit from other valuetypes, abstract interface or abstract valuetype. Usualy, when i'm modeling objects with alot of
get/set methods i prefer to use valuetypes instead of interfaces.
Going back to your question, the best way to understand 'attribute' is looking for C#. IIOP.NET maps 'attribute' to properties. A property simulates a public member but they are a get/set method.
Answering your question, i can't know if someObj.someName != someObj.someName will return true or false without see the someObj implementation. I will add two examples to give an ideia about what we can see.
Example 1) This implementation will always return false for the expression above:
private static i;
public string getSomeName() {
return "myName" i;
}
Example 2) This implementation bellow can return true or false, depending of concurrency or 'race condition' between clients.
public string getSomeName() {
return this.someName;
}
public setSomeName(string name) {
this.someName = name;
}
First client can try to access someObj.someName() != someObj.someName(). A second client could call setSomeName() before de second call from the first client.
It is perfectly acceptable for someObj.someName != someObj.someName to be true, oddly as it may seem.
The reason (as others alluded to) is because attributes map to real RPC functions. In the case of readonly attributes they just map to a setter, and for non-readonly attributes there's a setter and a getter implicitly created for you when the IDL gets compiled. But the important thing to know is that an IDL attribute has a dynamic, server-dictated, RPC-driven value.
IDL specifies a contract for distributed interactions which can be made at runtime between independent, decoupled entities. Almost every interaction with an IDL-based type will lead to an RPC call and any return value will be dependent on what the server decides to return.
If the attribute is, say, currentTime then you'll perhaps get the server's current clock time with each retrieval of the value. In this case, someObj.currentTime != someObj.currentTime will very likely always be true (assuming the time granularity used is smaller than the combined roundtrip time for two RPC calls).
If the attribute is instead currentBankBalance then you can still have someObj.currentBankBalance != someObj.currentBankBalance be true, because there may be other clients running elsewhere who are constantly modifying the attribute via the setter function, so you're dealing with a race condition too.
All that being said, if you take a very formal look at the IDL spec, it contains no language that actually requires that the setting/accessing of an attribute should result in an RPC call to the server. It could be served by the client-side ORB. In fact, that's something which some ORB vendors took advantage of back in the CORBA heyday. I used to work on the Orbix ORB, and we had a feature called Smart Proxies - something which would allow an application developer to overload the ORB-provided default client proxies (which would always forward all attribute calls to the server hosting the target object) with custom functionality (say, to cache the attribute values and return a local copy without incurring network or server overhead).
In summary, you need to be very clear and precise about what you are trying to verify formally. Given the dynamic and non-deterministic nature of the values they can return (and the fact that client ORBs might behave differently from each other and still remain compliant to the CORBA spec) you can only reliably expect IDL attributes to map to getters and setters that can be used to retrieve or set a value. There is simply no predictability surrounding the actual values returned.
Generally, attribute does not need to be backed by any data member on the server, although some language mapping might impose such convention.
So in general case it could happen that someObj.someName != someObj.someName. For instance attribute might be last access time.