DM: what does "as()" or "as anything" in for loop means?

as anything in the loop??

for(var/mob/each_mob in mob_list) // example #1
  to_chat("Hello, [each_mob]!")

for(var/mob/each_mob as anything in mob_list) // example #2
  to_chat("Hello, [each_mob]!")

for(var/mob/each_mob as() in mob_list) // example #3
  to_chat("Hello, [each_mob]!")

in the example, mob_list is a list type.
Let’s say you have these items in a list:

  1. mob_reference: [0x1000]
  2. object_reference: [0x2000]
  3. mob_typepath: “/mob/ghost”
  4. null: null
  5. mob_reference: [0x5000]

The first example will only take #1 mob_ref[0x1000] and #5 mob_ref[0x5000]
eventually, the loop will only process 2 times.
This is because “var/mob/each_mob” kinda does type check. So…

for(var/mob/each_mob in mob_list) // example #1
  to_chat("Hello, [each_mob]!")

is identical to:

for(var/i in mob_list) // alt version of example #1
  if(!istype(i, /mob)) 
    continue
  var/mob/each_mob = i
  to_chat("Hello, [each_mob]!")

as both of these will do the same: only #1 mob_ref[0x1000] and #5 mob_ref[0x5000].
So, specifying a type path in a loop is handy when you want to grab wanted items and filter unwanted items when a list is complex with multiple stuff.

  1. mob_reference: [0x1000]
    This passes istype() because it’s an existing reference type ingame.
  2. object_reference: [0x2000]
    This is an existing reference type ingame, but this is not /mob typepath. Fails.
  3. mob_typepath: “/mob/ghost”
    This is “typepath” which doesn’t really exist ingame, only tells the path of an mob. Fails.
  4. null: null
    Obviously fails.
  5. mob_reference: [0x5000]
    This passes istype() because it’s an existing reference type ingame.

Thus, you get only two.


the second/third example will take everything because of as() and as anything
This means:

for(var/mob/each_mob as anything in mob_list)
  to_chat("Hello, [each_mob]!")

is identical to:

for(var/i in mob_list)
  var/mob/each_mob = i
  to_chat("Hello, [each_mob]!")

as both of these will do the same.
These will grab everything in mob_list into var/mob/each_mob, but it will possibly cause a runtime.
This should be used with an exact purpose with an expected result.


WARNING

This is bad usage of type filtering loop.

for(var/mob/each_mob in some_list)
  pass()
for(var/obj/each_obj in some_list)
  pass()
for(var/turf/each_turf in some_list)
  pass()

This is expensive because you’re going to run the loop 3 times, calling the list 3 times.
That should be this:

for(var/each_thing in some_list)
  if(ismob(each_thing))
    var/mob/each_mob = each_thing
    pass()
  else if(isobj(each_thing))
    var/obj/each_obj = each_thing
    pass()
  else if(isturf(each_thing))
    var/turf/each_turf = each_thing
    pass()

This will run the loop once and do a thing. This is cheaper than the first thing.

I’d add that lists do not enforce types. Even if your list has a type you can have any object inside. It’s on you to make sure you insert valid objects.

Also instead of chaining else just add continue :wink:

1 Like

More accurately, typed list isn’t a thing currently (DM v515 at this moment)

var/list/datum/mind/mind_list = list()

If you see this, you’d expect a list can work well with mind datum.
in fact, it’s just var/list/mind_list = list()
It can be used to tell a coder which types a list should contain at least, but I am not a fan of that since it can be used wrong.
so, yeah, list() can accept anything no matter how it’s typed… for now.

There is a conceptual idea in DM about typed list, but currently, it’s not intended.


This is an example of typed list

/datum/test
 var/stuff = "hello"

/datum/test/proc/saythat()
 return stuff

/proc/main()
 var/list/datum/test/things = list()
 things += new /datum/test()
 things += new /datum/test()

 world.log << things[1].stuff
 world.log << things[1].saythat()

## WARNING: DO NOT USE THIS CODE. THIS IS NOT INTENDED BEHAVIOR

image

but the current DM (v515 at this moment) won’t accept and compile this format. (BeeBot can handle that, but DM can’t do this.)