ID:161324
 
I have the following if statement:

if(get_dir(A,D)==A.dir||get_dir(A,D)==turn(A.dir,45)||get_dir(A,D)==turn(A.dir,90)||get_dir(A,D)==turn(A.dir,135))


to check if D is in front or on the right-hand side (respectively) of A. Surely there's a better way? Also, is there a shorter way of using ||'s?

Many thanks.

~Ease~
if( get_dir(A,D) in list( A.dir,turn(A.dir,45),turn(A.dir,90),turn(A.dir,135) ) )

Maybe there's a better way than that.
Ease wrote:
I have the following if statement:

Wait, you mean that actually compiles?! :o
Anyway, what I was going to say, it's invalid syntax to put an if() statement inside another - you use the logical OR (||) operator just like you use every other operator. I'm going to get a little sidetracked here, you may skip this paragraph, of course, but it's something that should be made clear. The point of having the || and && operators is eliminating the need for multiple if() statements for logical OR and AND checks, so since you've posted the above you may (or may not) entirely understand how the if() statement works, which I'd assume to be pretty common, so I'll explain it here.
As you know, this if() statement will never execute:
if( 1-1 )
world << "You Should Never See This."


This is because, the way the if() statement works, it directly validates whether whatever expression (meaning - a proc call, a variable, an operator(s), etc) is inside it, and if it is a true value (doesn't equal 0, null, or an empty string: ""), then it runs the block of code indented under it. This is why you can put a single value (a literal constant value such as 1, or a single variable) into it without any operators such as ==, and it will check if it's true - that's how it works. If you put a complex expression such as a proc call or some operators, it has to run (execute) them first, then it checks if the value the expression returned is true/false. The || operator checks if the first argument is true, then if it is, it returns true. If it isn't, it checks the second one as well, and if it isn't true, it returns false. So you use it just like any other operator:
if( value || value2 )
if( Value == 1 || Value == 2 )
//et cetera


Surely there's a better way? Also, is there a shorter way of using ||'s?

You would use the switch() statement here, but you can't check for non-constant values with it, so it won't do here. First, doing this:
if(Proc() == 1 || Proc() == 2)

Will indeed check if Proc() returns either 1 or 2 - but if Proc() didn't return 1, then it will run it again and check if that equals 2 - which is extra processing, and is bad. To circumvent this, you call the Proc once, and store it's return value into a variable - then you check that one variable how many times you need:
var/V = Proc()
if(V == 1 || V == 2) //this will only call the Proc once



So adapt your code to that, and it should be shorter already. Maybe you can shorten it more as well (seems to me you may have some extra conditionals in your if() statement posted there).
In response to Jemai1 (#1)
Indeed, using a list is another method. Slower, I believe, but easier.
In response to Kaioken (#2)
--So far only read the top paragraph

I badly wrote out the code snippet; I don't actually have those IF's inside like that, I just have the one (as it shows now, but I must've changed it whilst you were writing your post) - I'm just a little (very) hungover right now so it didn't come out right =P

--Going back to read the rest of your post.
--Alright, finished reading;

Thank you so much for the very informative post! I completely forgot about the extra processing used by leaving the Procs() in the IF statement so many times!

~Ease~
In response to Ease (#4)
Ease wrote:
I must've changed it whilst you were writing your post) -

Ah, I see. Happens sometimes, maybe I should wait a little before replying. =P

Thank you so much for the very informative post!

No problem. Make sure you also remember the looping-through-a-list method Jemai posted, although it is less suitable for the situation here (for simple checks, you shouldn't use a loop; although if you have a lot of conditionals, it is preferable to use a loop because using ||'s would get too long).
In response to Kaioken (#3)
Oh. You are absolutely right.
Here is the proof.
proc
Proc1()
world << "Processing Proc1.."
return 1
Proc2()
world << "Processing Proc2.."
return 0
Proc3()
world << "Processing Proc3.."
return 1
Proc4()
world << "Processing Proc4.."
return 2
mob
verb
Bad_Code1()
if(Proc1()==Proc2()||Proc1()==Proc3()||Proc1()==Proc4())
usr << "TRUE!"
mob
verb
Bad_Code2()
if(Proc1() in list(Proc2(),Proc3(),Proc4()))
usr << "TRUE!"
mob
verb
Best_Code()
var/N = Proc1()
if(N==Proc2()||N==Proc3()||N==Proc4())
usr << "TRUE!"
In response to Jemai1 (#6)
I assume you are being cynical, but at any case, using that code wouldn't really yield worthwhile Profile results; all verbs should be fast enough to finish very quickly ("instantly") which will cause you to get 0.000 as the time values for all of the verbs, therefore you cannot compare them, also creating the illusion that they're equal. You need to insert something into the code that would delay it enough so the world profile can give it a non-zero rating, such as looping the code several (lots) times or using a sleep() (may not work well, though, and I haven't tested it).
I'd test it like this:
#define ITS 50000 //number of iterations
mob/verb
//checking true/false values:
check_operator()
for(var/i = 1 to ITS) //loop ITS times
if(0 || null || "" || 0 || 1)
; //empty if statement
src << "done"
check_loop()
for(var/i = 1 to ITS)
for(var/X in list(0,null,"",0,1)) //create a new list and loop through it
if(X)
;
src << "done"

//checking equality (with the built-in 'in' operator)
check_operator2()
for(var/i = 1 to ITS)
if(src == 1 || src == 2 || src == 3 || src == usr) //last condition is true
;
src << "done"
check_loop2()
for(var/i = 1 to ITS)
if(src in list(1,2,3,usr)) //create a new list and loop through it (internally)
;
src << "done"