I work on a class for measurements, so I would like to provide a nice API to compare two measurements.
In order to work with ordering in collection I implemented Comparator. For a nice API I implemented as well comparing operators <, <=, =>, >, ==.
So my class has the following methods:
bool operator <=(SELF other) => _value <= other._value;
bool operator <(SELF other) => _value < other._value;
bool operator >(SELF other) => _value > other._value;
bool operator >=(SELF other) => _value >= other._value;
#override
bool operator ==(Object other) =>
identical(this, other) || other is UnitValue && runtimeType == other.runtimeType && _value == other._value;
#override
int get hashCode => _value.hashCode;
int compareTo(SELF other) => _value.compareTo(other._value);
It feels like I had to add way too much boilerplate code. Does Dart provide any mixing for getting all that implementation based on a subset of operators?
I don't think so... but you can use a simple mixin for implementing operators based on the Comparable implementation:
mixin Compare<T> on Comparable<T> {
bool operator <=(T other) => this.compareTo(other) <= 0;
bool operator >=(T other) => this.compareTo(other) >= 0;
bool operator <(T other) => this.compareTo(other) < 0;
bool operator >(T other) => this.compareTo(other) > 0;
bool operator ==(other) => other is T && this.compareTo(other) == 0;
}
Example usage:
class Vec with Comparable<Vec>, Compare<Vec> {
final double x;
final double y;
Vec(this.x, this.y);
#override
int compareTo(Vec other) =>
(x.abs() + y.abs()).compareTo(other.x.abs() + other.y.abs());
}
main() {
print(Vec(1, 1) > Vec(0, 0));
print(Vec(1, 0) > Vec(0, 0));
print(Vec(0, 0) == Vec(0, 0));
print(Vec(1, 1) <= Vec(2, 0));
}
Related
Let's say I have:
class Test<T> {
void method() {
if (T is int) {
// T is int
}
if (T == int) {
// T is int
}
}
}
I know I can override == operator but what's the main difference between == and is in Dart if I don't override any operator.
Edit:
Say I have
extension MyIterable<T extends num> on Iterable<T> {
T sum() {
T total = T is int ? 0 : 0.0; // setting `T == int` works
for (T item in this) {
total += item;
}
return total;
}
}
And when I use my extension method with something like:
var addition = MyIterable([1, 2, 3]).sum();
I get this error:
type 'double' is not a subtype of type 'int'
identical(x, y) checks if x is the same object as y.
x == y checks whether x should be considered equal to y. The default implementation for operator == is the same as identical(), but operator == can be overridden to do deep equality checks (or in theory could be pathological and be implemented to do anything).
x is T checks whether x has type T. x is an object instance.
class MyClass {
MyClass(this.x);
int x;
#override
bool operator==(dynamic other) {
return runtimeType == other.runtimeType && x == other.x;
}
#override
int get hashCode => x.hashCode;
}
void main() {
var c1 = MyClass(42);
var c2 = MyClass(42);
var sameC = c1;
print(identical(c1, c2)); // Prints: false
print(identical(c1, sameC)); // Prints: true
print(c1 == c2); // Prints: true
print(c1 == sameC); // Prints: true
print(c1 is MyClass); // Prints: true
print(c1 is c1); // Illegal. The right-hand-side must be a type.
print(MyClass is MyClass); // Prints: false
}
Note the last case: MyClass is MyClass is false because the left-hand-side is a type, not an instance of MyClass. (MyClass is Type would be true, however.)
In your code, T is int is incorrect because both sides are types. You do want T == int in that case. Note that T == int would check for an exact type and would not be true if one is a derived type of the other (e.g. int == num would be false).
Basically, == is equality operator and "is" is the instanceof operator of Dart (If you come from Java background, if not, it basically tells you if something is of type something).
Use == for equality, when you want to check if two objects are equal. You can implement the == operator (method) in your class to define on what basis do you want to judge if two objects are equal.
Take this example:
class Car {
String model;
String brand;
Car(this.model, this.brand);
bool operator == (otherObj) {
return (otherObj is Car && other.brand == brand); //or however you want to check
//On the above line, we use "is" to check if otherObj is of type Car
}
}
Now you can check if two cars are "equal" based on the condition that you have defined.
void main() {
final Car micra = Car("Micra", "Nissan");
print(micra == Car("Micra", "Nissan")); // true
print(micra is Car("Micra", "Nissan")); // true
}
Hence, == is something you use to decide if two objects are equal, you can override and set it as per your expectations on how two objects should be considered equal.
On the other hand, "is" basically tells you if an instance is of type object (micra is of type Car here).
I am trying to detect if there is a function call inside an if statement as part of condition; like following:
if (cmp(a, b)){
\\do something
}
I have found I could do this with AST matcher in following manner:
Matcher.addMatcher(ifStmt(hasCondition(callExpr().bind("call_expr")))
.bind("call_if_stmt"),&handleMatch);
But the problem is condition could have shortcuts like &&, ||; like following:
if(a != b && cmp(a,b) || c == 10){
\\ do something
}
Now this condition has binaryoperator && and ||; also have a call expression as part of it. Now how I could detect that there is a call expression inside this if statement? Definitely I don't know how many binary operator as shortcuts will be there, so I am looking for a generalize solution for this, possibly using clange AST matcher.
In the first case, if(cmp(a,b)), the CallExpr node is a direct child of the IfStmt. In the second case, it is a descendant of the IfStmt, but not a child. Instead, it is nested beneath two BinaryOperator nodes. (I found this out by looking at the AST with clang-check -ast-dump test.cpp --.) Adding a hasDescendant traversal matcher will find the more deeply nested CallExpr. Unfortunately, that alone will not find the first case. So we could use anyOf to combine it with the original matcher:
ifStmt(
hasCondition(
anyOf(
callExpr().bind("top_level_call_expr"),
hasDescendant(
callExpr().bind("nested_call_expr")
)
)
)
).bind("call_if_stmt")
If I take test.cpp to have the following code:
bool cmp(int a, int b){return a < b;}
int f(int a, int c){
int b = 42;
if( a != b && cmp(a,b) || c == 10){
return 2;
}
return c;
}
int g(int a, int c){
int b = 42;
if( cmp(a,b)) {
return 2;
}
return c;
}
then I can test this with clang-query test.cpp --:
clang-query> let m2 ifStmt( hasCondition( anyOf(callExpr().bind("top_level_call_expr"),hasDescendant(callExpr().bind("nested_call_expr"))))).bind("call_if_stmt")
clang-query> m m2
Match #1:
/path/to/test.xpp:5:7: note: "call_if_stmt" binds here
if( a != b && cmp(a,b) || c == 10){
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/path/to/test.cpp:5:21: note: "nested_call_expr" binds here
if( a != b && cmp(a,b) || c == 10){
^~~~~~~~
/path/to/test.cpp:5:7: note: "root" binds here
if( a != b && cmp(a,b) || c == 10){
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Match #2:
/path/to/test.cpp:13:7: note: "call_if_stmt" binds here
if( cmp(a,b)) {
^~~~~~~~~~~~~~~
/path/to/test.cpp:13:7: note: "root" binds here
if( cmp(a,b)) {
^~~~~~~~~~~~~~~
/path/to/test.cpp:13:11: note: "top_level_call_expr" binds here
if( cmp(a,b)) {
^~~~~~~~
2 matches.
When working with a sort function, the implemented node i had created seems to cause some issues.
I have tracked it down to the comparison of Nodes in the Merge function of MergeSort. That being said, the line of code in question is:
if (_tmpArray[i] <= _tmpArray[j])
_tmpArray is defined in the the constructor, but given content value in the merge
Node implementation of operator ==, operator <, operator <= are as follows.
bool operator ==( Node<T> other) => identical(this, other);
bool operator <( Node<T> other){
//other is of same type, T.
if (_value.compareTo(other) == -1){
return true;
}
return false;
}
bool operator <= ( Node<T> other){
return (this == other) || (this < other);
}
It seems that maybe my implementation is wrong. I am doing a test inside of main with a List of size 400, of T = int.
Attached is my Dartpad file: https://dartpad.dartlang.org/612422345f1ac8a27f8e
It seems that the comparison of: _value.compareTo is not correct because T doesnt have compareTo in this case of int being T. When converting the int to "String" which is comparable though compareTo it still shows the same error.
//other is of same type, T.
if (_value.compareTo(other._value) == -1){
// ^^^^^^^ was missing
return true;
}
return false;
I have two longish blocks of code that are identical except in various comparative statements > is switched with <, >= with <= etc. I wanted to put these in a function and use one operator or another depending on a function input.
I am coding in MQL5 but this is very similar to C++ so hopefully methods that work in this will also be useable in my case.
You can create a comparator function for each comparison you need, and then pass the right function as an argument to the longish code blocks (wrapped in a suitably defined function)
As an example, consider the following hypothetical case where a function (myFunc) receives 2 integers(a and b)
and processes them. The processing steps are similar except for the type of comparison done on the arguments. We get around the problem by providing myFunc with the right tool for comparison.
#include <iostream>
using namespace std;
bool comp1(int a, int b) {
return a > b;
}
bool comp2(int a, int b) {
return a < b;
}
void myFunc(int a, int b, bool (*myComp)(int, int)) {
bool res = myComp(a, b);
cout << "value : " << res << endl;
}
int main()
{
myFunc(1, 2, comp1); //use >
myFunc(1, 2, comp2); //use <
return 0;
}
Clearly, comp1 and comp2 are the 2 different comparators. We pass one of them to myFunc depending on the requirements (< or >).
The best thing is that your comparisons can now be as complex as you want, and myFunc is oblivious to the complexities.
Coding in MQL4 you haven't pointers to function / templates. MQL5 has templates but formal parameter types are only built-in or basic user-defined types.
You could try something like:
enum COMPARATOR
{
C_EQUAL = 0,
C_LESS = 1,
C_GREATER = -1
C_AT_MOST = 2,
C_AT_LEAST = -2,
};
bool cmp(int a, int b, COMPARATOR c)
{
switch (c)
{
case C_LESS: return a < b;
case C_AT_MOST: return a <= b;
case C_EQUAL: return a == b;
case C_AT_LEAST: return a >= b;
case C_GREATER: return a > b;
}
Alert("INTERNAL ERROR: UNKNOWN COMPARISON");
return false;
}
void a_function(COMPARATOR c)
{
if (cmp(MathRand(), 13, c))
Print("BOOM");
// *** If you need the "opposite" of c *** you can write:
if (cmp(Time[0], Time[1], COMPARATOR(-c))
Alert("DONE");
}
It isn't elegant but it's effective.
Pass in a "comparator" as a function or functor, in this case I'm using the std::less and std::greater functors defined in the functional header, there are functors defined for more or less all the operators.
#include <iostream>
#include <functional>
template<typename Comparator>
void do_something(Comparator comp)
{
int a = 1;
int b = 2;
if (comp(a, b)) {
std::cout << "expression was true" << std::endl;
} else {
std::cout << "expression was not true" << std::endl;
}
}
int main(int argc, char* argv[])
{
do_something(std::greater<int>());
do_something(std::less<int>());
}
Output:
expression was not true
expression was true
I would like to override >= operator in Groovy, have found this page, but I am still not sure how to do it. I have a class Banknote with properties serial and amount and I wish to implement comparison bases on the amount property.
You don't override the >= operator, you implement compareTo:
class Foo implements Comparable {
int val
int compareTo(Object o) { return val <=> ((Foo) o).val }
}
f1 = new Foo(val: 5)
f2 = new Foo(val: 10)
println f1 <= f2
=> true