is checking for nil when looping over units still needed?

All discussions & material related to Command's Lua interface

Moderators: angster, RoryAndersonCDT, michaelm75au, MOD_Command

Post Reply
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

is checking for nil when looping over units still needed?

Post by Whicker »

I have been checking to see if a unit is ~= nil when looping thru units so as to avoid the code/function exiting prematurely if a unit does not exist.

In looking at this closer it doesn't seem to be necessary.

I have 12 F-15s named Eagle #1 thru 12.
Looping thru 15 to pretend 3 were destroyed.

Code:
-------------------------------------
for i = 1,15 do
ScenEdit_AssignUnitToMission("Eagle #"..i, 'CAP')
print(i)
end
-------------------------------------

If I run it as is in the lua console it does error - and the luahistory file shows that it exited on the first error. Not good.

But that is in the console, and the console works differently than the game. To emulate the game, at the top you need to add:
Tool_EmulateNoConsole(true)

then the console results are blank, but the luahistory file shows that it ran thru all 15 loops and errored on the ones that didn't exist - but the error did not make it exit. No problem.

This looks to me to be the same behavior as checking to see if it is nil - if it is nil, you get an error, but it continues. The only time it seems to be an issue is if you get fancy and assign the unit to a variable, and then use the variable, then if the unit doesn't exist when you call the variable it will error and quit. I think.

Example that is a problem if you don't check for nil:
--------------------------------------
Tool_EmulateNoConsole(true)
for i = 1,15 do
local u = ScenEdit_GetUnit({name ="Eagle #"..i})
ScenEdit_AssignUnitToMission(u.name, 'CAP2')
print(i)
end
--------------------------------------

that will error on the first one that doesn't exist and quit (bad). So on that checking for nil before the assignment to the mission is necessary. But there is no real reason (at least in this simple example) to set up a variable to hold the unit.

So, if all I am doing is changing a loadout or mission, it seems like I can skip the nil check? it may not work properly in the console but in the game it seems fine.
User avatar
michaelm75au
Posts: 12455
Joined: Sat May 05, 2001 8:00 am
Location: Melbourne, Australia

RE: is checking for nil when looping over units still needed?

Post by michaelm75au »

Script run without a console (as in events) will cause the script to terminate. The designer is expected to handle such errors that would normally 'kill' the script. Main reason why I added the Tool_EmulateNoConsole() function so you can run a background script in the foreground for testing.
That said, some errors can be benign but I find it best to check the return result just in case it isn't.[:D]
Michael
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: is checking for nil when looping over units still needed?

Post by KnightHawk75 »

I always just check for nil anyway when accessing, assigning or otherwise using any object if the object or the lookup has any possibility of failing or not existing. The perf cost is minimal (it seems) in most cases and you get added script resiliency and re-usability. I also find it aids during dev and debugging - ie I can more easily spot unexpected nils and situations via prints for those conditions. So while there are cases where it doesn't matter as Whicker rightly points out, better to be safer most of the time than sorry for relying on particular quirks of the console vs runtime environment that could, at least in theory, change over time.
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: is checking for nil when looping over units still needed?

Post by Whicker »

I guess my confusion here is the nil check itself causes an error anyways so what is the point? how do you check for nil without causing an error? - using the same example I have above.

The only time I found it needed was if you set a variable equal to a unit and that unit didn't exist, then when you use that variable it will crash. But if you are directly changing something with the ScenEdit functions it works fine - as far as I can tell.
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: is checking for nil when looping over units still needed?

Post by KnightHawk75 »

Could be I'm confused. This is how I usually write it.

Code: Select all

 --Will generate popup on nil in console, but work in game or with EmulateNoConsole(true) in console script
 for i = 1,15 do
     local tmp = ScenEdit_GetUnit({name ="Eagle #".. i})
     if tmp ~= nil then
         ScenEdit_AssignUnitToMission(tmp.name, 'CAP2');
         print('Eagle #' .. i .. ' Added to  CAP2.');
     else
         --redundant in this case since error message is very specific, but personal habit
         print('Object named Eagle #' .. i .. ' does not exist, skipping.');
     end
 end 
 
Alternative Variant of same, bit more shorthand

Code: Select all

 --Will generate popup on nil in console, but work in game or with EmulateNoConsole(true) in console script
 for i = 1,15 do
     if ScenEdit_GetUnit({name ="Eagle #"..i}) then 
         ScenEdit_AssignUnitToMission("Eagle #" .. i, 'CAP2');
         print('Eagle #' .. i .. ' Added to  CAP2.');
     end
 end 
 
 

edit:
In a scenario\situation though where you have to be in the console with emulate false and at the same time you still want my example to work, yeah then you have problems and might have to go with your no-check version. I guess also a situation where perhaps it's not a background thread in the runtime, maybe special actions? I've not tested SA specifically, but I can't recall running into a problem yet, doesn't mean the case doesn't exist though.

There is another way that will work in either situation (I think from memory) but it's much heavier perf wise and that's to loop thought units via vpsides.units filtered on ( using .unitsby() ) say 'Aircraft' and then check every entry for a matching name or guid, and exit on first match, counting it as existing. I have a function\fragment somewhere I can probably find that I call for doing that from elsewhere, can't remember off hand why I had to do that once though.
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: is checking for nil when looping over units still needed?

Post by Whicker »

playing around with it yesterday it looked to me like your first one needs the nil check cause you assigned the unit to a variable - when you use that variable and it doesn't exist it will error and exit the code at that point.

The second example when you do the initial `if`, that will error just the same as if you did it without the `if`, but with Tool_EmulateNoConsole(true) in the console the code (with or without the if part) will continue to run despite the error. Thus, why bother with this type of nil check. Other than good form so when you do it the first way it works.

Still trying to nail this down though, thanks for the example code I had not seen your second one used like that in lua. I'll play around with it more when I get a chance.
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: is checking for nil when looping over units still needed?

Post by KnightHawk75 »

ORIGINAL: Whicker

playing around with it yesterday it looked to me like your first one needs the nil check cause you assigned the unit to a variable - when you use that variable and it doesn't exist it will error and exit the code at that point.

The second example when you do the initial `if`, that will error just the same as if you did it without the `if`, but with Tool_EmulateNoConsole(true) in the console the code (with or without the if part) will continue to run despite the error. Thus, why bother with this type of nil check. Other than good form so when you do it the first way it works.

Still trying to nail this down though, thanks for the example code I had not seen your second one used like that in lua. I'll play around with it more when I get a chance.

None of the samples 'need' the nil check per-say for this situation, like you mentioned since addtomission actually handles the error condition in-game and just returns you 'false' while logging a descriptive reason for false. I thought you were asking more the how to do it _with a nil check that will not throw a script stopping exception in-game more broadly, more than why in this specific case. It was I that was confused, i was thinking the question was more alone the lines of "If I wanted to see if unit exists first before attempting to add it to a mission, how would I if I wanted too with nil?". Like if I wanted to say if unit does not exist, go create it first, then add it to mission, because a 'false' return itself from assignunittomission value doesn't tell me 'unit does not exist' it could also mean 'missionname' doesn't exist.

If you're just saying, hey there is no need for it when using AssignUnitToMission in the background cause it already does this, yes, that's I think certainly correct. For that fragment at least, since function already handles that case and returns false, and if you _don't need to know why in code at that time it returned false, then yup no need for it.

My habit of checking (and pretty much always run emulate=true), is because most of the time I'm working with return tables\objects not bool retvals, so before I start enumerating though or invoking anything on it I usually want to make sure it exists first if I haven't already, and usually do something if it doesn't. But in this case\fragment 'good form' or just my habit would, I think you're right, just be adding overhead of a second check, in at least the most common cases where you don't care why it fails.
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: is checking for nil when looping over units still needed?

Post by Whicker »

ah - I think I am getting there... it is working so far on the 2 functions I ran - changing missions and loadouts - but it is those particular functions (ScenEdit_AssignUnitToMission in this case) that are handling the error gracefully?

and other cmano functions may not? I was thinking it was something more global - ie I write bad code and the game is ok with it and continues.

thus if I think I don't need the nil check just based on these 2 examples, I will eventually find a game function that does need it?

This is very helpful to me, glad I asked. I think I am 50% of the way towards understanding this particular issue.
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: is checking for nil when looping over units still needed?

Post by Whicker »

I think I will standardize on your example above:

----
for i = 1,15 do
local tmp = ScenEdit_GetUnit({name ="Eagle #".. i})
if tmp ~= nil then
ScenEdit_AssignUnitToMission(tmp.name, 'CAP2');
print('Eagle #' .. i .. ' Added to CAP2.');
else
--redundant in this case since error message is very specific, but personal habit
print('Object named Eagle #' .. i .. ' does not exist, skipping.');
end
end
----

this seems like the best way to learn it, and the safest. If people do it this way they will have more power to do other things that are more complex. It is a bit weird - without the emulate part above it, it crashes on the first missing unit in the console, but not the game. That is my main hangup I think, and for newbs is probably hard to grasp.
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: is checking for nil when looping over units still needed?

Post by KnightHawk75 »

ie I write bad code and the game is ok with it and continues.

I think you way more than 50% have it. :)

I think that's true in most cases, game trying to handle bad input as gracefully as possible where it can, at least on it's end. How that effects one's scripts continued execution and logic after though, and how the exception is bubbled up or manifests itself through the scripting interface context can differ by script\script purpose. It's less about that an exception happened and more about how\if you need to detect or react to it, or what problems or unexpected outcomes it can cause if you don't. Sometimes it's not going to matter sometimes it will.

You're probably right that it may seem weird for new users understanding there are two different modes and that they don't always behave exactly the same on exception handling depending on execution context console editor vs runtime event. I look at emulate=false as 'let me prototype\do something fairly simple that will probably work most the time' and true= 'final code\real test before pasting into an action'. That may be a wrong way to view it though. *shug*

I could definitely see "Hey where are my print statements!!" from a new user though if they start out always emulating runtime events and don't know to watch the log in that case. Your mentioning using a 'tails' type app on the active luahistory log file in your video was an excellent suggestion that partially solves that, and it's a great suggestion for new users regardless. This whole topic is probably a good one for a video, which I presume you may have in mind already. ;)

Finalish note... I just noticed something in my first sample, it may be 'more proper' in this particular case to declare "local tmp;" before the "for i ..." loop and then inside the 'for' just say "tmp = ScenEdit...". That way one avoids technically re-declaring tmp 14 additional times on each iteration. Though we're probably talking a couple nanoseconds so doesn't much matter for 15 items and may look more clean\self contained as it was originally.

Code: Select all

 local tmp;
 for i = 1,15 do
     tmp = ScenEdit_GetUnit({name ="Eagle #".. i})
     if tmp ~= nil then
         ScenEdit_AssignUnitToMission(tmp.name, 'CAP2');
         print('Eagle #' .. i .. ' Added to  CAP2.');
     else
         --redundant in this case since error message is very specific, but personal habit
         print('Object named Eagle #' .. i .. ' does not exist, skipping.');
     end
 end 
 
Here is a recent example of where I needed\wanted to check for nils because it matters to me or the player.
It's a special action with the following description so you know generally what it's doing (this one actually mandates only 1 unit selected probably not the best example I have a refueling on that does all selected, and an example there where you want to check unit exists is because between time table is generated and object access it could in theory be destroyed.):

"When used on a Submarine or anything of that primary type this action will deploy a 'low observable' special forces observation post unit approximately 1nm north of the selected sub's position if the position is above elevation zero. Basically get in close to shore, select sub, and press this action and get some high explosive enabled recon agents with nightvision and other goodies like satcom.

This is used because it seems actual units aren't user deployable\cargo-able or carryable by the SRV-type mini-subs...sort of making them pointless for what we want to simulate here.
Your Cost: 100 points"

Code: Select all

 see attached text file.
 
edit: trying to get code formatting to not overrun post.
edit2: just attached the text file due to formatting issues in browser.


Attachments
SpecOpsDeployViaSub.txt
(3.22 KiB) Downloaded 10 times
Whicker
Posts: 664
Joined: Tue Jun 19, 2018 9:54 pm

RE: is checking for nil when looping over units still needed?

Post by Whicker »

I think the Code block in this forum is limited to a height of 300 for some reason..

I'd like to see the emulate thing be a check box in the console UI - it would make more sense than expecting people to find out about it on their own.

Nice example!
KnightHawk75
Posts: 1850
Joined: Thu Nov 15, 2018 7:24 pm

RE: is checking for nil when looping over units still needed?

Post by KnightHawk75 »

Ah that's good to know about the formatting, thanks. I think anything other than small snippets I'll post in text file format going forward. I think that UI checkbox is not a bad suggestion for the to-do list. There might be reasons for not doing it though that aren't immediately obvious to either of us though, I would be interested in what devs and more people thought about it.
Post Reply

Return to “Lua Legion”