Author Topic: Which is 'Cleaner' and why?  (Read 1079 times)

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #15 on: May 28, 2012, 02:55:15 am »


               

NineCoronas2021 wrote...

2) What effect does "||" have in the if-clause? Why are some other conceivable ways I could use it? (just trying to wrap my mind around it, no pun intended)

As Baaleos said this is an code expression for logical OR.

In a conditional statement with OR, if a left value is TRUE, then right part of the conditional is not executed at all. So its better to use:

if(!bPC || bDM) return;

than

if(bPC && !bDM)
{
do stuff;
}
               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #16 on: May 28, 2012, 08:02:27 pm »


               

Baaleos wrote...
1. int and void lines ended with a ;    are called function prototypes.
In nwnscript, you may have noticed that if you try to call function 1 from inside function 2, you will have to have function 1 being defined above function 2. Otherwise the compiler doesnt know where Function 1 is - it compiles from top down.
Prototypes allow you to move the single line prototype of the function, to the top of the script, without needing to move the contents.
The below example wouldnt work without the prototype


Why exactly are these lines repeated:
int HasDoneThisBefore( object oPC );
int HasDoneThisBefore( object oPC )

it appears as if the second one is superflous?


Also, your answer to my third question went completely over my head lol
               
               

               


                     Modifié par NineCoronas2021, 28 mai 2012 - 07:20 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #17 on: May 28, 2012, 08:35:32 pm »


               the first line with semicolon /function prototype) allows this function to be viewed (after you include the include into your script using #include "include_name") right side of the script editor where are listed all functions. The function need not have to prototype. It works without it the same way.

(just a note that doesnt have real meaning and you dont have to worry about it)
A common definition treat functions without prototype as a "private function" not intented to use by builder, performing very specific task.

However also functions with prototype might be private in the sense they are doing something so specific that their reusability is next to zero (there is several such functions thorough bioware default includes).
               
               

               


                     Modifié par ShaDoOoW, 28 mai 2012 - 07:36 .
                     
                  


            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #18 on: May 28, 2012, 08:37:01 pm »


               The example you are referencing doesnt seem to be a valid example - I dont think it would compile.



void MyFunction(int myArg, int mySecondArg);  //   This is the prototype - it tells the script the basic calling convention of the function, without requiring the function to be put at the top

void MyFunction(int myArg, int mySecondArg)
{
  // my code here
}


You can see in my example, that the prototype just shows the calling convention along with the return type (void) and the arguments.

as for the 3rd comment.



int myNumber(object oPC)
{
int iVal = GetLocalInt(oPC,"my_Number");
return iVal;
}

int myNumber(object oPC)
{
   return GetLocalInt(oPC, "my_Number");
}

These are both doing the same,
but the second one returns the value, without first storing it unecessarily storing it to a variable.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #19 on: May 28, 2012, 09:24:43 pm »


               

NineCoronas2021 wrote...

Why exactly are these lines repeated:

int HasDoneThisBefore( object oPC );
int HasDoneThisBefore( object oPC )

it appears as if the second one is superflous?


Also, your answer to my third question went completely over my head lol


As Baaleos Stated this  'int HasDoneThisBefore( object oPC );' is a proto tyoe of the function.   
I would call it a forward declairation.  It basicly give the compiler all the information needed to allow a code block to use the function, without knowing what the function does or how it does it.   

The second one woud define what the function does and how it does it.  
since you do nto have the sini colon at the end of the statment, the compiler will expect a code block that defines what the function does.  

int HasDoneThisBefore( object oPC )
{
  // code block for that the function does. 
}    
 
superflous?  Yep without the code block it would be. 



Lets see the answer to your third question about the return.   In order to understand the return you first have to understand functions.     Functions are nothing more then a Lable given to a block of code.  Kind of like variables are nothing more then a Lable given to a memory location.  Just like the varaiable have a data type ( int, float,string...)  so does the function.   This data type that is given to the function is concidered its Return Value. This Return Value is calculated by the Code Block of the function and returned to the calling code.   The way it is the code block tells it what to Return is by the 'return' reserved word.  in our function declairation we have: 

       
int HasDoneThisBefore( object oPC )
{
    int x;    
    // Code doing something with oPC 
    return x;  


lookint at it one piece at a time we have ;

int : This is the data type that the code block will return,  It is also the data type that you can use the function as.   anyplace you can legally use an int you will be able to use this function. 

HasDoneThisBefore :  The Lable that we are giving to the code block that will evulate out to our data type.

( ):   The parentheses following the Lable denote this to the compiler as a function as opposed to just being a Varaible.

(object oPC)  :  If we have a varaiable defined within the parentheses, thies varaiables are created on the stack before the function's code block is ran.   they will also be initialized with the data given when the function is used. 

{ }  :  Is where the code block that defines what the function does goes.   

return  x :  is a keword in the functions code that tells the compiler that this is where the function ends and the value to return.   If there is nothing behind the return;  That means that the function was a void data type and has no return value.   

So to answer your question


 return GetLocalInt( oPC, GetTag( OBJECT_SELF ));

The Return is at the begining because we are wanting to return the integer that   GetLocalInt( oPC, GetTag( OBJECT_SELF )) is evaulating to.
               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #20 on: May 29, 2012, 01:30:36 am »


               So that means that 'return' is doing something different there than when it is placed like this in a normal script:
if (HasDoneThisBefore(oPC)) return;
where it is telling the script to stop running if that criteria is met?

EDIT:

How many "||"'s can be used? just one? or multiple?
               
               

               


                     Modifié par NineCoronas2021, 29 mai 2012 - 12:31 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #21 on: May 29, 2012, 02:14:57 am »


               

NineCoronas2021 wrote...

So that means that 'return' is doing something different there than when it is placed like this in a normal script:
if (HasDoneThisBefore(oPC)) return;
where it is telling the script to stop running if that criteria is met?



Not really both do the same thing.   In this case the return value is just void.  Meaning what ever function you are using it in is a void data type.     Every function has a return,  This may not seem the case because it is often implied in void returning functions.    Even in the main entry function for a script, you know the ' void main() { //code}  yes even that is nothing more then a special function with extra  code attached to it, because it is the main entry point for the script.   If you write that main code block without a return anywhere in it,  it is still implied and the compiler adds one at the end of the code block for you.     

EDIT:

How many "||"'s can be used? just one? or multiple?


As many as you want.  the || ( Logical OR Operator)  Is an Operator just like +, - , /, *...   There is no real limit on how many you can stack together.   
               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #22 on: May 29, 2012, 02:27:25 am »


               

Not really both do the same thing.   In this case the return value is just void.  Meaning what ever function you are using it in is a void data type.     Every function has a return,  This may not seem the case because it is often implied in void returning functions.    Even in the main entry function for a script, you know the ' void main() { //code}  yes even that is nothing more then a special function with extra  code attached to it, because it is the main entry point for the script.   If you write that main code block without a return anywhere in it,  it is still implied and the compiler adds one at the end of the code block for you.

Damn that was confusing.

Okay, why does 'return' if put at the end of a line behind a semi-colon cause the script to stop if the condition before it isn't met?
What I got from the quote above is that every line of code with a semi-colon has a 'return' that is implied, or "hidden", and that writing 'return' is actually redundant.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #23 on: May 29, 2012, 03:01:45 am »


               

NineCoronas2021 wrote...

Damn that was confusing.

Okay, why does 'return' if put at the end of a line behind a semi-colon cause the script to stop if the condition before it isn't met?

 It stops the code if the code is met,  Because the return is then excuted.   Basicly saying return the execution path back to the calling code. 
 
 

What I got from the quote above is that every line of code with a semi-colon has a 'return' that is implied, or "hidden", and that writing 'return' is actually redundant.


No every  void returning function code block has one implied if not supplied.


void main()
{
   object oPC = GetEnteringObject();
   if (GetIsPC(oPC)) SendMessageToPC(oPC," You are not allowed to tread here!!");
  
   return;// This return is optional.  if it is not present it is assumed.
}
It is not at the end of every statment that it is assumed.  only at the end of every void returning function code block.
               
               

               


                     Modifié par Lightfoot8, 29 mai 2012 - 02:02 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #24 on: May 29, 2012, 04:55:46 am »


               Have a question as well. I assume that every variable defined inside if or even loop is undefined at the end of conditional statement/loop iteration. But im only guessing there, I guess that defining variable inside loop "int n = X;" is extremely bad idea. And I guess that while someone might think that defining the variable inside if statement is better than at the end of the script (because that gets done only when condition is fulfilled and not everytime) its practically the same or maybe even less efficient than defining the variable without value and assigning the value inside if.

Am I correct?
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #25 on: May 29, 2012, 06:00:56 am »


               That one is not easy to answer in NWScript.  My current thought, without digging back into the VM, is that every variable is defined at the place in the code where the declairation is encountered.  I have had times when I was defining Vars within a loop causing a Stack Underflow Run Time error.  Since that time I have Quit defining Vars inside loops.  It is realy not a good practice anyway.  

Within NWScript I am unsure where the Var clean up happens per NameSpace.  But each Var is individually created.  

In a modern language compiler, Like c++, thing are a lot simpler.   Reguardless of where the variable are declaired in the script, they are all allocated storage on the stack with a single machine instruction.   On one of the parsing passes of the compiler all of the Variables are counted with there size, to get a full byte size count for the storage.  Then that size is simply subtacted from the Top Of Stack Pointer ( the ESP regester under 32 bit systems)  to allocate the storage needed all at once.   When the function is left the stack pointer is simply returned to the place it was before the function was called.   Clean up done.  

The Variables themselves are  refferanced either by an offset from a BaseStackPointer (regester EBP)  Or an offset from the Top of the Stack ( ESP regester) .  

NWScript is just not that effecient.  It creats and destroys each Variable One at a time.   The VM stack is also a combination of 2 arrays.  one array of dwords to hold the value for the variable and another array of bytes that holds the data type for the variable.     So if you definded  int Lable = 5 ;   and it ended up being at index  20 in the stack.    5 would end up at index 20 in the array of Dwords and  3 ( the constant for the integer data type)  would end up at index 20 in the array of bytes.    

drifting  off topic,
I hope that helped somewhat, though I dout I answered you question.  
L8
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #26 on: May 29, 2012, 07:32:13 am »


               

ShaDoOoW wrote...

Have a question as well. I assume that every variable defined inside if or even loop is undefined at the end of conditional statement/loop iteration. But im only guessing there, I guess that defining variable inside loop "int n = X;" is extremely bad idea. And I guess that while someone might think that defining the variable inside if statement is better than at the end of the script (because that gets done only when condition is fulfilled and not everytime) its practically the same or maybe even less efficient than defining the variable without value and assigning the value inside if.

Am I correct?


Correct.

For example the following will always return true

int ReturnTrue()
{
int n = 1;
if(n)
  {
  n = 2;
  int n = 0;
  if (n)
    return FALSE;
  }
if(n == 2)
  return TRUE;
return FALSE;
}
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #27 on: May 29, 2012, 08:39:03 am »


               @Whiz

I am not sure that is what he was asking.   The  there is no dout that you have 2 vars named n, in two different namespaces.   Also correct that you are accesing both n Vars within your inner name space because of the way you r wrote it.   But they are in fact two different variables. With two different memory locations.   If I read his question correctly, he was asking when the Variable was undefined or un allocated.   I at this point do not know when that happens without looking back into the VM.     It could be at the end of the name space, but that is not given.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #28 on: May 29, 2012, 11:10:58 am »


               Just relized that I do not have to go into the VM.  I can just read a compiled script to give you your answer.  And yes The Vars are created at the place the ar at in the code.  They are also removed from the stack upon leaving the name space.  


Here is what the compiled code would look like with wiz's function added int a main. 


code:.

 int ReturnTrue()
{
int n = 1;
if(n)
  {
  n = 2;
  int n = 0;
  if (n)
    return FALSE;
  }
if(n == 2)
  return TRUE;
return FALSE;
}
 

void main()
{
  ReturnTrue();
}

** removed* *

EDIT: Boy that looks bad.  Ill Try and get you a better copy tonight.    

Here is a Link to the code I removed above. It is a little better format, but not much.
               
               

               


                     Modifié par Lightfoot8, 29 mai 2012 - 11:15 .
                     
                  


            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Which is 'Cleaner' and why?
« Reply #29 on: May 29, 2012, 02:44:43 pm »


               

ShaDoOoW wrote...

Have a question as well. I assume that every variable defined inside if or even loop is undefined at the end of conditional statement/loop iteration. But im only guessing there, I guess that defining variable inside loop "int n = X;" is extremely bad idea. And I guess that while someone might think that defining the variable inside if statement is better than at the end of the script (because that gets done only when condition is fulfilled and not everytime) its practically the same or maybe even less efficient than defining the variable without value and assigning the value inside if.

Am I correct?


No. It just depends.

[Edit  - should be clear that "no" refers to the second part of the question - is it always a bad idea. Also, I didn't
see Lightfoot and Whizard's relies for some reason... sorry.  I agree that in lightfoot's example of using the
outer scoped n inside the loop and then redefining it is a bad way to code. But in general limiting variables
to the scope they are needed is a good pprogramming practice]

[Edit again - i mean Whizard's example... more coffee please]

This gets into the concept of scope. The scope of a variable consists of the code blocks in which is is visible.
A code block being in this case basically anything between a set of {}.  (or defined outside of a specific scope
like the constants commonly found in include files).

It should be no more or less efficient to defined a variable inside an "if" block, to use your example, that it is
to do so at the top of the function and only assign value inside the "if". 

It depends on whether the variable needs to be used outside the block as to whether it's useful or not to
define it there. 

If it is only needed in that specific "if" block the it makes sense and is cleaner in my opinion to define it
in that block. I find it makes the code easier to read.  It makes it clear that that variable is only used
and only set and only meaningful in that block of code.

One thing to be wary of is hiding variables from a higher scope. That can lead to confusion. For example
defining a variable at the to of the function and then defining another with the same name in a tighter scope
(like within an "if" block) can be error prone.

void main () 
{
    int n = y;

    if (something) 
    {
             int n = x;

            SpeakString("Got " + IntToString(n));
    }
}

This wil produce "Got x".  You cannot access the outer scope n variable in that if block.
And outside the "if" block n still equals y.

 
               
               

               


                     Modifié par meaglyn, 29 mai 2012 - 01:58 .