ID:2080945
 
(See the best response by Rushnut.)
Code:
mob
var/list/completedmissions=new
var/prerequisite
verb
Test()
if(!src.prerequisite||src.prerequisite in src.completedmissions)
world<<"working"


Problem description:
I've been wondering this for sometime now, Why can't you combined an 'in' operator with other statements using || or &&. In the above example prerequisite is null and still can't pass the if statement.
Best response
You need to encapsulate it within parenthesis.
Thx bro.
are you able to explain what makes it fail tho?
since prerequisite is null,it shouldn't even touch the second part of the if statements and automatically pass
It is a precedence issue. I don't know what exact order it works in but I pretty much always use parentheses in checks like that just to avoid this issue. I advise you do the same.
As stated, it's a precedence issue, 'in' comes fairly late in the order of operations so you're not actually formatting the if() the way you'd expect.
if(condition && item in list)


Actually looks like
if(condition && null)


Since the 'in' hasn't been processed yet, that statement is nothing.

So that null will never be true.

if(condition && (item in list))


Works differently, since you have the parenthesis there the process knows to evaluate that before anything else, which will evaluate to a true or false.

if(condition && true) // If the item is in the list.
// or not
if(condition && false)


In the end, so the top one will pass and the bottom won't.
Alright, you've cleared it up slightly for me but in my example I'm using ||. Are you saying not having the parenthesis will make the entire if statement false even tho its separated by || not &&. Cause by logic standpoints, even if it prioritizes the 'in' and return false it should still check the other part, which in my example is true and should pass.
In response to Fat Albert
This is how the logic works out.
!a || a in b // what you start with
(!a || a) in b // order of operations
(!null || null) in b // plugging in for a = null
(TRUE || null) in b // applying ! operation
TRUE in b // applying || operation
FALSE // assuming b doesn't contain TRUE
Interesting, so it looks like a shorthand for checking if two variables are in a list, which could be useful in many situations.
In response to Fat Albert
Pretty sure you misunderstand what Kaiochao wrote.
Yeah nvm. Its is checking if true or false is in the list. which is false.
In response to Fat Albert
Well, it's checking if (TRUE || null) in b, which is not the same as (TRUE in b) || (null in b). There is no distribution going on. (TRUE || null) == TRUE and so it's checking if TRUE in b. If it had been (FALSE || null) in b then the or portion would evaluate as (FALSE || null) == null and then the in statement would check null in b.
yeah, ive just been avoiding combining 'in' if statements with other statements for along time, to find out I just have to put a parentheses around my 'in' statement is just one of those programming moments.
This stuff should be documented. Would save some future developers some heartache.
The in operator's precedence issue actually has a bug report open, as Tom considered it a bug. I've always been on the fence about how I feel about it, because IMO the current precedence makes no sense. There's a slight possibility that changing it would impact some games negatively, but I strongly doubt it.

I'm even more on the fence about the relative precedence of the ! operator. Some people might want if(!item in list) to be like if(!(item in list)), but I think a Dart-style in! operator would be much clearer. The ! operator has always been tight-binding.

Changing the precedence, though, is a difficult situation because of how expressions are parsed in the axial deframbulator. It's code I haven't done much with.
In response to Lummox JR
Lummox JR wrote:
axial deframbulator.

well I'm glad to know about the having parenthesis solves the problem, in! doesn't seem like too bad of a special case, it certainly will avoid precedence confusion.