Maybe my title is a little bit confusing so I'll illustrate with a scenario
Let say I want to compare between 2 int values and return me a boolean based on the logical comparison.
if (int1 > int2) return true;
if (int3 < int4) return true;
if (int5 == int6) return true;
if (int7 >= int8) return true;
if (int9 <= int10) return true;
But instead of writing this manually, I wish to do something like
- (bool)compareVal1: (int)val1 withVal2: (int)val2 usingLogical: (NSString*)logic
{
if (val1 "logic" val2) return true;
}
I want a general function which can be used to represent the 5 logical comparison that I want.
I'm not sure whether this is achievable but if you have any other solutions, please advise :)
Well first off, I would use an enum instead of an NSString to decide which logical operator to use. So try something like this:
typedef enum {
GREATER_THAN,
LESS_THAN,
LESS_THAN_OR_EQUAL,
GREATER_THAN_OR_EQUAL,
EQUALS
} logicalOperator;
And the actual function would look like this:
+ (bool)compareVal1: (int)val1 withVal2: (int)val2 usingLogical: (logicalOperator)op
{
switch(op) {
case GREATER_THAN:
return (val1 > val2);
case LESS_THAN:
return (val1 < val2);
case LESS_THAN_OR_EQUAL:
return (val1 <= val2);
case GREATER_THAN_OR_EQUAL:
return (val1 >= val2);
case EQUALS:
return (val1 == val2);
}
}
I would also make the function a static/class function because it does not truly affect a specific instance of a class, but rather it is a utility function that operates on the values passed in. An example of this functions usage would be this:
bool isGreater = [MyClass compareVal1: 4 withVal2: 3 usingLogical: GREATER_THAN];
Not sure why you can't just directly parse the string and return the result of the expression. For example (only illustrating two operators):
- (bool)compareVal1: (int)val1 withVal2: (int)val2 usingLogical: (NSString*)operator
{
if([operator isEqualTo:#">"])
{
return (val1 > val2);
}
else if ([operator isEqualTo:#"<"])
{
return (val1 < val2);
}
// similar logic statements for other operators
}
More pertinently, though, why do you need a method to do this when you can just write the evaluation itself instead?
Related
I recently created a function that checks if a pair exists in my swap smart contract.
The functoin looks like this:
function checkIfPairExists(address _token1, address _token2) internal returns(uint, bool) {
for (uint index = 0; index < tokenPairs.length; index++) {
if (tokenPairs[index].token1 == _token1 && tokenPairs[index].token2 == _token2) {
return (index, true);
}
else if (tokenPairs[index].token2 == _token1 && tokenPairs[index].token1 == _token2) {
return (index, true);
} else {
return (0, false);
}
}
}
This function works fine but then when I try to use the function in an if statement like this:
if (checkIfPairExists(_token1, _token2) == (uint256, true))
How do I write it so it is correct? I am trying to receive index of the pair for my array and bool to see if the pair exists. I then need to save that index to find which pair it should add to.
Hope it makes sense.
Let me know if I should rephrase the question so more people will understand it and it can help them.
Thanks
You need to assign the returned values to two separate variables. Then you can validate either of them.
(uint256 index, bool exists) = checkIfPairExists(_token1, _token2);
if (exists == true) {
// do something with `index`
}
As said in the above answer by #pert-hejda, you will need to assign the function return values then you can use those to check the condition. Why? Because multiple returns are represented as tuples and currently the feature you want is not supported in solidity. So, you will need to assign the return values and use those values in conditionals. Thank you.
I've read somewhere that a variable should be entered into the code if it is reused. But when I write my code for logic transparency, I sometimes create intermediate variables (with names reflecting what they contain) which are used only once.
How incorrect is this concept?
PS:
I want to do it right.
It is important to note that most of the time clarity takes precedence over re-usability or brevity. This is one of the basic principles of clean code. Most modern compilers optimize code anyway so creating new variables need not be a concern at all.
It is perfectly fine to create a new variable if it would add clarity to your code. Make sure to give it a meaningful name. Consider the following function:
public static boolean isLeapYear(final int yyyy) {
if ((yyyy % 4) != 0) {
return false;
}
else if ((yyyy % 400) == 0) {
return true;
}
else if ((yyyy % 100) == 0) {
return false;
}
else {
return true;
}
}
Even though the boolean expressions are used only once, they may confuse the reader of the code. We can rewrite it as follows
public static boolean isLeapYear(int year) {
boolean fourth = year % 4 == 0;
boolean hundredth = year % 100 == 0;
boolean fourHundredth = year % 400 == 0;
return fourth && (!hundredth || fourHundredth);
}
These boolean variables add much more clarity to the code.
This example is from the Clean Code book by Robert C. Martin.
i was looking some examples of interactions with the keyboard and stumbled upon this code that i found interesting. But i'm having trouble understanding a certain part of it(it's marked down below).I don't get how all this whole ''boolean'' declaration, ''switch'' and ''CASE'' works, i tried to look in the reference but still. Could someone explain in a simple maner how these work?
float x = 300;
float y = 300;
float speed = 5;
boolean isLeft, isRight, isUp, isDown;
int i = 0;
void keyPressed() {
setMove(keyCode, true);
if (isLeft ){
x -= speed;
}
if(isRight){
x += speed;
}
}
void keyReleased() {
setMove(keyCode, false);
}
boolean setMove(int k, boolean b) {// <<<--- From this part down
switch (k) {
case UP:
return isUp = b;
case DOWN:
return isDown = b;
case LEFT:
return isLeft = b;
case RIGHT:
return isRight = b;
default:
return b; }
}
Questions like these are best answered by the reference:
Works like an if else structure, but switch() is more convenient when you need to select between three or more alternatives. Program controls jumps to the case with the same value as the expression. All remaining statements in the switch are executed unless redirected by a break. Only primitive datatypes which can convert to an integer (byte, char, and int) may be used as the expression parameter. The default is optional.
The rest of the code is setting the corresponding variable to whatever value you passed in as the b parameter, and then returning it.
You should get into the habit of debugging your code. Add print statements to figure out exactly what the code is doing.
Is there a considerable difference of optimization between these two codes (in Java and/or C++, currently, even if I guess it's the same in every languages) ? Or is it just a question of code readability ?
int foo(...) {
if (cond) {
if (otherCondA)
return 1;
if (otherCondB)
return 2;
return 3;
}
int temp = /* context and/or param-dependent */;
if (otherCondA)
return 4 * temp;
if (otherCondB)
return 4 / temp;
return 4 % temp;
}
and
int foo(...) {
int value = 0;
if (cond) {
if (otherCondA)
value = 1;
else if (otherCondB)
value = 2;
else value = 3;
}
else {
int temp = /* context and/or param-dependent */;
if (otherCondA)
value = 4 * temp;
else if (otherCondB)
value = 4 / temp;
else
value = 4 % temp;
}
return value;
}
The first one is shorter, avoid multiple imbrications of else statement and economize one variable (or at least seems to do so), but I'm not sure that it really changes something...
After looking deeper into the different assembly codes generated by GCC, here's the results :
The multiple return statement is more efficient during "normal" compilation, but with the -O_ flag, the balance change :
The more you optimise the code, the less the first approach worths. It makes the code harder to optimise, so, use it carefully. As said in comments, it's very powerful when used at the front of the function when testing preconditions, but in the middle of the function, it's a nightmare for the compiler.
Of course the multiple return is acceptable.
Because you can halt the program as soon as the function is finished
I'm porting a class which implements IEquatable<T> and IComparable<T> and overrides ==, !=, < and > from C# into C++/CLI. So far I have:
Header:
virtual bool Equals(Thing other);
virtual int CompareTo(Thing other);
static bool operator == (Thing tc1, Thing tc2);
static bool operator != (Thing tc1, Thing tc2);
static bool operator > (Thing tc1, Thing tc2);
static bool operator < (Thing tc1, Thing tc2);
Source file:
bool Thing ::Equals(Thing other)
{
// tests equality here
}
int Thing ::CompareTo(Thing other)
{
if (this > other) // Error here
return 1;
else if (this < other)
return -1;
else
return 0;
}
bool Thing ::operator == (Thing t1, Thing t2)
{
return tc1.Equals(tc2);
}
bool Thing ::operator != (Thing t1, Thing t2)
{
return !tc1.Equals(tc2);
}
bool Thing::operator > (Thing t1, Thing t2)
{
// test for greater than
}
bool Thing::operator < (Thing t1, Thing t2)
{
// test for less than
}
I'm not sure why the original tested equality in the interface and compared things in the operator, but I'm trying to preserve the original structure.
Anyway, I get a compilation error at the marked line: "error C2679: binary '>' : no operator found which takes a right-hand operand of type 'ThingNamespace::Thing' (or there is no acceptable conversion)", and a corresponding error two lines below. Why isn't it picking up the existence of the overloaded operator?
this is a pointer, you'll need to dereference it.
if ((*this) > other)
return 1;
else if ((*this) < other)
return -1;
else
return 0;
return (*this) == other ? 0 : ((*this) > other ? 1 : -1);
as arul said, you need to dereference the this keyword, but on a side note, you should probably use const references in your function paramaters instead of passing the object since:
-C++ passes all objects by value, not by reference(which is what happens in C#), so using references reduces the overhead.
-It'll let you use functions from the standard library such as std::sort without needing to explicitly specify a new comparison operator