command /s:
trigger:
{_s::*} contains "a":
send "contains"
{_s::*} doesn't contain "a":
send "doesnt contain"
{_s::*} is empty. This command send nothing to me. Both "contains" and "doesn't contain" return false it the list is empty.
What version of Skript are you running?
It occurs on both dev-37c and dev-36.
Can somebody please check whether this happens too for example with %entities% are in world %world% vs %entities% aren't in world %world% or "%livingentities% are wearing %itemtypes% vs "%livingentities% aren't wearing %itemtypes%? If so then the .check method of the SimpleExpression class might require some modification
Isn't this related to how the contains check works?
for (Object o : all) {
if (Relation.EQUAL.is(Comparators.compare(o, item)))
return true; // Found equal, success!
}
return false; // Not found
It will return false directly but it will be true because negated.
Before the Checkers:
if (all == null && isNegated())
return false;
should be enough.
command /a:
trigger:
message "start"
if {_x::*} contains "a":
message "yes"
if {_x::*} doesn't contain "a":
message "no"
if {_x::*} is in world "world_nether":
message "yes"
if {_x::*} isn't in world "world_nether":
message "no"
if {_x::*} are wearing iron helmet:
message "yes"
if {_x::*} aren't wearing iron helmet:
message "no"
message "end"
@Blueyescat my guess was correct, this needs to be reworked in the .check method (unless this behavior is really intended?)

This has been reported previously - see #404. It is also intended behavior; variables that do not exist are not lists. It is a bit confusing, though, especially since adding to nothingness creates a list.
Feedback on this welcome. If we decide to change this, it shouldn't be too hard.
Smart programming with Skript often includes handling false or disabled states by having the variable not exist at all. This isn't possible in many languages but in Skript we have the freedom to say if {_random garbage variable name} is set which saves on both memory and load time. That being the case, my opinion is that unset variables should be respected somewhat like a falsy value because we know that people will be checking values against unset variables as if they were set. So IMO an unset variable should effectively act like a set-but-empty list for all intents and purposes - adding stuff to it works, removing stuff does nothing but doesn't fail/error, and checking contains against it never passes while doesn't contain should always pass.
With my recent commit doing for example players in world "world" doesn't contain {_some.online.player} when no players are in the world world should return true, but with list variables the issue (described by @bensku) still exists, and I agree with @TheBentoBox here:
IMO an unset variable should effectively act like a set-but-empty list for all intents and purposes
This is now fixed with the last changes on CondContains.
Most helpful comment
Smart programming with Skript often includes handling false or disabled states by having the variable not exist at all. This isn't possible in many languages but in Skript we have the freedom to say
if {_random garbage variable name} is setwhich saves on both memory and load time. That being the case, my opinion is that unset variables should be respected somewhat like a falsy value because we know that people will be checking values against unset variables as if they were set. So IMO an unset variable should effectively act like a set-but-empty list for all intents and purposes - adding stuff to it works, removing stuff does nothing but doesn't fail/error, and checkingcontainsagainst it never passes whiledoesn't containshould always pass.