Jump to content
Sign in to follow this  
rwillis

SQF functions over SQF scripts?

Recommended Posts

How do I know when to use "call" to call a SQF function file over using "execVM" to call a SQF script file? Or basicly, what's the difference between SQF scripts and functions and how do I know when to use one over the other?

Share this post


Link to post
Share on other sites

I cannot remember who explained it this way, but it is far more short and concise than I would have put it:

Functions halt the engine, execute, and return a value (which is why they are usually short and to the point - e.g. do a calculation).

Scripts run in parallel (which is why sleep command is used to prevent too much CPU usage - e.g. position a container below a helo while it is moving to give appearance it is carrying it).

Best advice I can give to newbies:

Use functions ONLY when the code is short and performs a single action to return a value.

Share this post


Link to post
Share on other sites
Best advice I can give to newbies:

Use functions ONLY when the code is short and performs a single action to return a value.

I'd even say: Only use functions when you _need_ a return (beside the script handle). wink_o.gif If you don't need a return, just start a script.

Share this post


Link to post
Share on other sites

If you need a return from a script then you can also give it an array as parameter where the script puts the result(s) in. Since the array is given to the script by reference, you can read out the return values afterwards.

Something like this:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_resultArray = [0,""];

_handle = [_resultArray] execVM "resultScript.sqf";

// script runs and changes the _resultArray that is was given

waitUntil {scriptDone _handle};

_resultInt = _resultArray select 0;

_resultString = _resultArray select 1;

Share this post


Link to post
Share on other sites
Quote[/b] ]If you need a return from a script then you can also give it an array as parameter where the script puts the result(s) in. Since the array is given to the script by reference, you can read out the return values afterwards.

Yep, but it's has some restrictions. For example, you can use + or - on _resultArray, otherwise you loose your pointer to it.

Functions are also required when you want to guarantee run a succession of commands on an object, before the screen updates. Like setpos and setdir in a loop.

You don't stop functions like you do with scripts, when you hit escape to pause the game.

The games interal clock won't increment while using functions, unless told to using sleep. See this thread about functions and the sleep command.

Share this post


Link to post
Share on other sites
The games interal clock won't increment while using functions, unless told to using sleep. See this thread about functions and the sleep command.

There we are again with the lack of clear terminology... now what you said is misleading - kinda. Because we can't use the sleep command in functions (as in a function that returns a value as it was used before in this thread).

EDIT: just read your last comment in the other thread, so well. we still can't always use it wink_o.gif It remains to be seen why it works in your example...

But in the "normal" case we can only use sleep in what Kegetys called an SQF function in the other thread, as opposed to an SQF script which is a script that uses the SQF syntax - but it's not really a function.

Share this post


Link to post
Share on other sites
Quote[/b] ]we still can't always use it

Whats that got to do with anything? We are talking about executing a script with the three new Arma commands?

Don't take my word, or anyone elses for that matter. Try the example I posted yourself.

Oh and yes, always best to read all of a post.

Share this post


Link to post
Share on other sites
Quote[/b] ]we still can't always use it

Whats that got to do with anything? We are talking about executing a script with the three new Arma commands?

Don't take my word, or anyone elses for that matter. Try the example I posted yourself.

Oh and yes, always best to all of a post.

it has to do with everything, because what you found is probably some very special case. But the sleep command won't work when you execute a regular "function" (<-- that's the word you used) so now we have the problem of terminology, I don't understand what you are saying. If you say function I must assume you mean an SQF function, called with the call command. Then you statement is not really correct. It works in your example but it doesn't work in any case I tried when the SQF Function was in a separate file as opposed to a constant of type code as in your example. Maybe the interpreter analyses the code constant and figures it must be an SQF script because sleep is used. I don't know. As I said it remains to be seen why this works and most other cases don't.

However your statement could also mean that you talk about SQF scripts which behave differently from SQF functions but share the same syntax. Then we can use the sleep command of course.

But how am I supposed to know what you are talking about when you just say "function" which is atm often misused and you also talk about using the sleep command which is only allowed in scripts (normally)

Share this post


Link to post
Share on other sites
Quote[/b] ]It works in your example but it doesn't work in any case I tried when the SQF Function was in a separate file

The why didn't you say that in the first place?

Quote[/b] ]But how am I supposed to know what you are talking about when you just say "function" which is atm often misused and you also talk about using the sleep command which is only allowed in scripts (normally)

I defined my version of what I think should be referred to as a function, long before this thread appeared. I even discussed it on the wiki. The only difference was, I said the term function based script should be dropped and we stick to just two types, like we did with OFP. Functions (*.sqf) and scripts (*.sqs). To cut it short, use call to execute functions. Everything else gets executed with the remaining commands.

As to why you can use call in that way, who knows. If it won't work in an external file (I've yet to check that) then it might be down to scope. Using the call command with {}, in a script, allows you to share the scope of that script. However like I said in the other post, that could well be a bug that needs to be added to the Wiki. If it's not a bug, then we at least have to be aware of when you can and can't use it. For beginners it's probably better not to bog them down with minor details like using sleep with the call command when embedded in scripts. But I for one would like to know how things work and what options we have.

Either way, I'm glad to know that someone has at least confirmed it as a fact, even if you find it misleading it's still a fact.  Now it can be added to the wiki bug list, for BIS to decided if it is or isn't.

Share this post


Link to post
Share on other sites
Best advice I can give to newbies:

Use functions ONLY when the code is short and performs a single action to return a value.

I'd even say: Only use functions when you _need_ a return (beside the script handle). wink_o.gif If you don't need a return, just start a script.

I wouldn't.

That would take away a good chunk of patterns and practices capable with functions. In fact, I would recommend using less "scripts" be it sqs or sqf style simply because they are inherently less reliable.

A function that doesn't return a value: Ever hear of a "void" function before?

Coding practices should be clean and simple. By reducing to as many functions as possible (actual functions using call) you make code more portable, more reliable, and more adaptable. Scripts should be used simply to weather out code which loops such as checking for events or when executing mutliple functions concurrently that are not time-sensitive.

[EDIT] I made a discussion post on the biki yesterday to suggest calling functions which use execVM or spawn (a.k.a "scripts") "ArmA Scripts" and old sqs files "OFP Scripts". Functions called with call command would still be functions.

Reminds me.. I should check if anyone replied....

Hmm... Raedor, I replied back that basically if we call them "OFP scripts" regardless of using them in ArmA it might suggest that they are "old style."

[/edit]

Share this post


Link to post
Share on other sites

I didn't say it in "first place" because it's pretty clear that sleep cannot be allowed in a regular functions. Because it then can freeze the game for very long periods. A functions is there to perform a calculation or something that returns a value. This has to be done quickly so the script (or init-Line) that called it can continue with it's execution. If a script has to wait 60 seconds for a returning value because people use "sleep 60" in the function it can't continue (and as I understand it neither will the whole game continue) which obviously doesn't lead to the desired effect in most cases.

What I think is most important to beginners is that we precisely define what we are talking about. There's nothing more confusing if you try to get into a "language" than unclear definitions and a lot of exceptions. (That's also why I could never really grasp French grammar). And calling everything in an .sqf file a function is very unclear. Because we have two different types of code that are stored in an .sqf file. So the only thing that the different codes in an .sqf file have in common is their syntax (and that is only by convention, as you can use the "SQF Syntax" also in .sqs files, and I didn't try it but probably any text file format will work). But we need to distinguish between those types of code that we store in .sqf files somehow because we cannot use all commands in both types. The sleep command is a perfect example. And it also helps us to decide if we need to "call" or "execVM" the file to not get a compiler error. ANd the most important aspect is probably that we must distinguish between the fundamentally different workings of those two types of code. The "script" can run paralelly with other scripts and the game while the "function" halts the game and they get executed sequentially.

Share this post


Link to post
Share on other sites

If you are execing/execvming/calling a file (whether it be a script, a script function, or a function) once every 0.001 seconds, that does a simple check and ends (no wait, loop, etc) what would be THE most efficient way?

Exec?

ExecVM?

Call?

Share this post


Link to post
Share on other sites

Use call... and make it a SQF "Function" you can preprocess

The fact you are controlling the interval externally (assuming from an SQF or SQS "script") means you can reduce it to the quickest and most efficient way to check something - i.e. "function"

[EDIT] Let me clarify something for everyone....

Calling preprocessed functions from within other preprocessed functions should be minimal simply to prevent function induced lag. However, good code flow is when you have an SQF or SQS "script" which is like a breakdown of the steps needed to complete your idea. Each "step" should be a short function which can be run to either check a value or do some sort of calculation or even to perform an action (like setPos). By breaking your idea into multiple functions you can use the "script" to run parallel each function("step") while controlling time intervals to allow the engine to run smoothly.

If you run everything wolely within a "script", you cannot control when the engine will pause your code to continue with the game core on the main thread. For people with low framerates it is very obvious that code does in fact pause. By putting your individual steps within functions you can better control where the pauses take place. And if you prevent functions from calling alot of other functions you prevent excessive delays in code execution. It's the balance of coding which is in itself an artform.[/EDIT]

Share this post


Link to post
Share on other sites
Quote[/b] ]I didn't say it in "first place" because it's pretty clear that sleep cannot be allowed in a regular functions. Because it then can freeze the game for very long periods.

There is absolutely no reason why that can't be the case, if BIS want to build that into their language. There are no irrefutable laws of nature that say it can't be done.

Clearly using sleep with the call command does not freeze the entire game. That fact started all this, or did you forget that, just then smile_o.gif I also believe the Call command is not broken, but it may or may not, not be working exactly the way BIS intended.

Quote[/b] ]And calling everything in an .sqf file a function is very unclear. Because we have two different types of code that are stored in an .sqf file. So the only thing that the different codes in an .sqf file have in common is their syntax (and that is only by convention, as you can use the "SQF Syntax" also in .sqs files, and I didn't try it but probably any text file format will work).

Your missing my point, there is only one type of code that should be used in an function (*.sqf). Code thats designed specifically to be used with the call command. Any other code should be called using execVM or Spawn, this should have the file extension (*.sqs). That way you know how the file should be used, even before you open it.

The most important aspects of functions have nothing to do with syntax. In a function, you can end each line with a wink for all I care. How it executes the code and what it returns, is the most important thing.

Quote[/b] ]ANd the most important aspect is probably that we must distinguish between the fundamentally different workings of those two types of code.

Yes, that’s exactly my point. Two different types of code only require two different descriptions. But unfortunately, I believe old style OFP scripts are still required in some cases? I'm not exactly sure where, I think it's init.sqs. Although IMHO this single exception is easier to add as a sub clause.

Quote[/b] ] If you are execing/execvming/calling a file (whether it be a script, a script function, or a function) once every 0.001 seconds, that does a simple check and ends (no wait, loop, etc) what would be THE most efficient way?

If you mean like this?

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">WaitUntil {

Sleep 0.001;

<Execute MrZig’s simple check>;

};

Or in OFP style code:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">#Loop

~0.001

<Execute MrZig’s simple check>;

goto [“Loopâ€]

Then probably a function, so use the Call command. The reason I say a function is, scripts can’t loop any quicker that 0.001. There is a good chance they may take longer. So if you have such a short time span, only a function will guarantee the command(s) are executed when they’re supposed to. So in that case, function is the best way.

Edit:

Quote[/b] ]It works in your example but it doesn't work in any case I tried when the SQF Function was in a separate file

I just tested this in Arma:

Function.sqf:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Player SideChat Format ["Time 1 : %1",Time];

Sleep 5;

Player SideChat Format ["Time 2 :%1",Time];

Sleep 5;

Player SideChat Format ["Time 3 :%1",Time];

It was called from an Arma script using this:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_Func=compile LoadFIle "Function.sqf";

Call _Func;

And guess what, the sleep command works in pre-compiled, external functions to. The error message you probably saw, was caused through not pre-comiling the function.

Share this post


Link to post
Share on other sites

whats the difference between preprocessfile and compile loadfile?

Quote[/b] ]this should have the file extension (*.sqs). That way you know how the file should be used, even before you open it.

I disagree. SQS files should only contain old-style syntax. Otherwise you can potentially break third-party apps like Chris' OFP editor and such.

I use Crimson Editor myself and it codes according to file extension. If I start writing c-like syntax in an sqs file it's going to be confused as much as I will be.

[EDIT] UNN, can you verify that your sleep commands using call in a compiled function does not in fact pause the engine for 10 seconds and prevent anything else from running?[/EDIT]

Share this post


Link to post
Share on other sites
In fact, I would recommend using less "scripts" be it sqs or sqf style simply because they are inherently less reliable.

Actually, I can't fully agree there.

What you said is all valid for regular programming, but game programming is something different.

For a game what makes or breaks it is how smooth it is running and that has pretty much top priority. If you have the best AI and the best looking graphics and all but it's running at 60 frames per minute, then you can throw it all away because it's useless.

Now if a regular program has a response time of 10s it might be tolerable.

And the case of choosing between a function or a script definitely affects performance, so regular coding practices can only applied after that is taken care of.

Most of the coding that we do for OFP or ArmA doesn't rely on getting done between two frames and usually can take much longer without having any side-effects.

For all cases where it's not necessary to have a fast execution time even on the expense of performance, I think scripts should be used instead of functions.

In fact if your function is taking too long then it just gets canceled and you're off worse than with a script. In that case scripts are more reliable than functions.

Also compared to regular programs with several million lines of codes, our OFP/ArmA scripts are tiny. If you loose oversight and get less reliable, portable and adaptable code because of using scripts instead of functions, then you're doing something else wrong.

Scripts can be written just as portable, adaptable and reliable than functions. What matters is the difference in execution which makes an impact on performance.

Following general programming practices without looking at how things work under the hood isn't a good thing. It's about knowing how to structure things in a given environment and adapting the rules to it instead of blindly following them.

So know about good programming practices, know WHY they're good, know about the difference between scripts and functions (and not to forget the quirks and things about all the commands) and apply all this to get good running code that does useful things in the first place and is adaptable and portable and all those nice things second.

Share this post


Link to post
Share on other sites

According to the Wiki:

Pre-process:

Quote[/b] ]Returns preprocessed content of given file. Preprocessor is C-like, supports comments using // or /* and */ and macros defined with #define.

I can't find anything at about compiling code. But I'm sure there is something in the Wiki that states it, makes code more efficent as once it's benn pre-compiled the first time Arma does not have to do it every time it's called.

I guess you could use something like:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_Func=Compile Preprocess "Function.sqf"

In OFP you could not pre-process a function stored within an addon. Not sure if compiling it has the same restrictions. Add that the my list of things to check.

Share this post


Link to post
Share on other sites

Hold on, Nonono that's not what I'm asking UNN.

It's aleady being execed/execvmd/called 0.001 times, I can't change that (I can't say how, it's a secret!wink_o.gif

But every 0.001 it will be loading either an external script, or a preprocessed string. What is more efficient?

Calling a compiled proproccesed string every 0.001 seconds

(EVERY! ) or

ExecVMing a .sqf every 0.001 seconds?

Here's my example.

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

#lp

~0.01

;call ZigPreprocessedCode

;[] execvm "ZigCode.sqf"

;[] exec "ZigCode.sqs"

goto "lp"

Keep in mind that this isnt how it actually is, so DONT try and say that #lp and ~0.01 isnt efficient, because it's entirely different. I just want to know which execing type is more efficient.

And lets say that the file I'm trying to open every 0.01 seconds question is this.

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

IF ((getpos man select 2) > 30) THEN {man setpos [getpos man select 0, getpos man select 1, (getpos man select 2) - 0.1]};

IF ((getpos man select 2) < 15) THEN {man setpos [getpos man select 0, getpos man select 1, (getpos man select 2) + 0.1]}

This aint the actual file, just an example of how the real one flows.

Share this post


Link to post
Share on other sites

@Romulus

You should have read my clarification.

I know exactly what is running under the hood(figuratively speaking). However, as much as what you say is true, what you don't say is equally as bad.

You said "If you loose oversight and get less reliable, portable and adaptable code because of using scripts instead of functions, then you're doing something else wrong."

This is exactly what I am saying. If you simply write nothing but scripts you give less control of your code to maintain performance of the engine. However, in most cases this need not be true. I just tend to approach it from the other side of the field. I write functions. Then I control my functions by adapting scripts which give me more control over my code. If something breaks, yes it is bad code but I can better determine where the breakdown exists and control it even further.

This is one thing I never believed about game programming.. it is not inherently different then any other type of programming and most rules apply equally to help produce quality products. Only when the standards don't allow for proper functionality should you depart from good practices - NOT simply toss out standards because they might not fit under certain conditions which you might not encounter anyways.

[EDIT] If I understand your logic then I dont see what the purpose of functions are at all? Am I to assume you think functions are pointless?

On the contrary I think they are great. I can ensure my calculations execute (especially if using an object within the function) without change in state by anything. If I run scripts my object might not exists half-way through it. It is statistically remote, but a possibility none-the-less. [/Edit]

@UNN

I am familiar with what the wiki says.. I am more interested if there is a difference in the results (and what that difference is if it does produce different results)

[EDIT] This is an excellent discussion thread btw... I wish more were like this[/EDIT]

Share this post


Link to post
Share on other sites
...This is one thing I never believed about game programming.. it is not inherently different then any other type of programming and most rules apply equally to help produce quality products. Only when the standards don't allow for proper functionality should you depart from good practices - NOT simply toss out standards because they might not fit under certain conditions which you might not encounter anyways.

I still don't agree.

A rule or good practices them self have no other value than reminding you about more complex things that are valid for a specific environment. Nothing more.

Every other use of a rule or good practices is a bad use. You could as well throw a dice instead of using a certain rule or good practice.

To know if your rule or good practice is applicable, you still have to know the complex reasoning behind it and the environment it is valid for. If you don't it isn't worth anything.

So asking about rules is absolutely pointless. What people should ask for is explanations about how things are and draw their own conclusions.

Question everything!

If something is obvious, then it's easy and fast to explain and also to see that it really is. But by doing so you know for sure that things are that way and you're not just following a hollow rule.

That's the most basic quality control you can and should do.

Also when answering, I think it's also pointless to just state rules. For someone not knowing the things behind a rule, the rule itself has no value at all.

So I'm at least trying to always give explanations instead of rules even if people get annoyed because it's getting too long winded abut things they don't even want to know because they think they can get away with more simple things smile_o.gif

[edit]

Commenting on your edits CrashDome:

My main point is that it's pointless following rules just because they apply for other cases.

I don't think functions are useless at all.

But there's absolutely no way in setting up easy rules that can tell you when exactly use a function or a script. What I mean is that you need to know the differences between the two and how this affects coding in various situations. This can't be taught by rules, this has to be learned by examples. There's no shortcut for that.

My second point that results from the first is that games are different than "normal" programs since performance is the major factor. First you need to be concerned about performance, and then about everything else.

So every rule or good practice you know from programming "normal" programs needs to be tested if it's still valid and if it doesn't put priority to something else instead.

I couldn't live without good programming practices, but I always have to question whether something is applicable in the specific situation or not.

Even programming practices for "normal" programs can be fundamentally different so that you have to decide which one you want to follow for a specific case. And with games it's even more tricky.

So having good coding practices is nice, functions are nice, scripts are nice, know how they work and how they affect performance. Know how commands work and know how they affect performance. If you do that, you automatically get your own set of rules to make your life easier, but are worthless for others who don't know the rest (,yet maybe) smile_o.gif

[/edit]

Share this post


Link to post
Share on other sites
Edit:

I just tested this in Arma:

Ok I tested the function stuff with sleep. Now functions work with sleep. The error must have been on my side previously. I withdraw my point that sleep doesn't work in functions therefore.

However this behaviour is in contradiction with some entries on the Biki regarding functions. So I guess those need corrections.

Share this post


Link to post
Share on other sites

@CrashDome

Quote[/b] ]UNN, can you verify that your sleep commands using call in a compiled function does not in fact pause the engine for 10 seconds and prevent anything else from running

It will halt the script it's being called from. But if you launch code with Spawn or execVM, before calling the function, they will continue to run.

Quote[/b] ]I disagree. SQS files should only contain old-style syntax. Otherwise you can potentially break third-party apps like Chris' OFP editor and such.

Chris's editor works fine with the new scripts. I've already imported the commands, so there highlighted. I can post the file if anyone is interested, but I doubt I'm going to add the syntax references. To be honest, as far as terminology goes. It's not like it's the of the world or anything. I'm sure it will work itself out one way or another.

Quote[/b] ]I am familiar with what the wiki says.. I am more interested if there is a difference in the results (and what that difference is if it does produce different results)

I think pre-processing a file should be looked at along the same lines as formatting a string with %1...%9 e.t.c. Once it's formatted, you then compile it. If I understand your question?

@MrZig

Quote[/b] ]it's a secret

Secrets are overrated smile_o.gif

Quote[/b] ]But every 0.001 it will be loading either an external script, or a pre-processed string. What is more efficient?

Neither, you should pre-compile your code into a variable and call it with the Spawn  command if it needs to behave like a script. Or call if it can get away with being executed like a function.

Quote[/b] ]And lets say that the file I'm trying to open every 0.01 seconds question is this.

setpos is ok on it's own.

@Romolus

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Most of the coding that we do for OFP or ArmA doesn't rely on getting done between two frames and usually can take much longer without having any side-effects.

For me it's the other way round and I can think of a few people who will need to use this info if they port their addons over. But I do see your point. I would try not bore novice scripters to death, in quite the same way smile_o.gif I think the info should be tiered, so you can progress through the various levels of detail.

Quote[/b] ]Ok I tested the function stuff with sleep. Now functions work with sleep. The error must have been on my side previously.

I tried to execute the same function from an objects init field, that didn't work. The sleep keeps throwing up an error. From a script it's ok.

Share this post


Link to post
Share on other sites

Thanks for testing UNN.

@Romolus

I guess we'll have to settle at disagreeing. I see your point but I still dont agree. I tend to believe alot of practices are based on performance and efficiency and do apply to games versus "normal" applications.  There is a difference between retrieving thousands of SQL datarows within an appication lifetime and retrieving thousands of packets of MP info from other clients but the end goal of acheiving high performance and efficiency is always the same. These coding practices are not developed by retards (atleast the ones I use). They are in fact a development of what is optimal underneath the language you are using and developing good practices with scripting in ArmA should not be ignored simply because it is not "normal". I agree there will be times a person who truly knows what they are doing will create the best code, but what I am suggesting is tried and true practices that teach the new guys to get started without writing spaghetti all the time. It is no different than providing a coach to play football versus having everyone learn the hardway by facing them off with a bunch of pros and watching their bones get broken all the time. What you are suggesting is that the new guys are basically SoL and need to get pushed out of the nest from day one and if they hit the ground then it's their own fault.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×