Scripting: Do's and Don'ts – Arma Reforger

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Text replacement - "<syntaxhighlight lang="c#">" to "<enforce>")
m (Some wiki formatting)
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{Feature|important|Follow [[Arma Reforger:Scripting: Conventions]].}}
{| class="wikitable valign-top" style="width: 100%"
 
|+ {{Feature|important|Do follow {{Link|Arma Reforger:Scripting: Conventions|Scripting Conventions}}.}}
{| class="wikitable" style="width: 100%"
! style="width: 50%" | Don't
! style="width: 50%" | Don't
! style="width: 50%" | Do
! style="width: 50%" | Do
|- style="vertical-align: top"
|-
|
|
<enforce>
<enforce noGuess methods="Print">
class ExampleClass {
class ExampleClass {
   int LProcLgh;
   int LProcLgh;
Line 16: Line 15:
}
}
}
}
</syntaxhighlight>
</enforce>
|
|
<enforce>
<enforce>
Line 22: Line 21:
{
{
protected int m_iLastProcessedLength;
protected int m_iLastProcessedLength;
 
int GetStringLength(string value)
int GetStringLength(string value)
{
{
Line 29: Line 28:
return m_iLastProcessedLength;
return m_iLastProcessedLength;
}
}
 
int GetLastProcessedLength()
int GetLastProcessedLength()
{
{
Line 35: Line 34:
}
}
}
}
</syntaxhighlight>
</enforce>
|}
|}


Keep variables as close as possible to their usage:
{| class="wikitable valign-top" style="width: 100%"
{| class="wikitable" style="width: 100%"
|+ {{Feature|important|Keep variables as close as possible to their usage.}}
! style="width: 50%" | Don't
! style="width: 50%" | Don't
! style="width: 50%" | Do
! style="width: 50%" | Do
|- style="vertical-align: top"
|-
|
|
<enforce>
<enforce>
Line 48: Line 47:
{
{
protected int m_iLength;
protected int m_iLength;
 
int GetStringLength(string name)
int GetStringLength(string name)
{
{
Line 56: Line 55:
}
}
}
}
</syntaxhighlight>
</enforce>
|
|
<enforce>
<enforce>
Line 62: Line 61:
{
{
// keeping the variable into method scope and away from the instance
// keeping the variable into method scope and away from the instance
 
int GetStringLength(string name)
int GetStringLength(string name)
{
{
Line 70: Line 69:
}
}
}
}
</syntaxhighlight>
</enforce>
|}
 
{| class="wikitable valign-top" style="width: 100%"
|+ {{Feature|important|Do not scope more than necessary.}}
! style="width: 50%" | Don't
! style="width: 50%" | Do
|-
|
<enforce>
switch (value)
{
case 0:
{
Print("0");
break;
}
 
default:
{
Print("default");
break;
}
}
</enforce>
|
<enforce>
switch (value)
{
case 0:
Print("0");
break;
 
default: // brackets are needed only if variables are declared in the 'case' code
{ // otherwise scoping is superfluous (and very slightly impacts performance)
string message = "default";
Print(message);
break;
}
}
</enforce>
|}
|}


Keep a strong reference ({{hl|ref}} keyword) to required objects:
{| class="wikitable valign-top" style="width: 100%"
{| class="wikitable" style="width: 100%"
|+ {{Feature|important|Keep a strong reference (<enforce inline>ref</enforce> keyword) to required objects.}}
! style="width: 50%" | Don't
! style="width: 50%" | Don't
! style="width: 50%" | Do
! style="width: 50%" | Do
|- style="vertical-align: top"
|-
|
|
<enforce>
<enforce>
// this array only lists pointers but does not increase the reference count
// this array only lists pointers but does not increase the reference count
array<ExampleClass> classArray = new array<ExampleClass>();
array<ExampleClass> classArray = {};
 
for (int i = 0; i < 10; i++)
ExampleClass newInstance;
for (int i; i < 10; i++)
{
{
ExampleClass newInstance = new ExampleClass();
newInstance = new ExampleClass();
classArray.Insert(newInstance);
classArray.Insert(newInstance);
// newInstance will be deleted at the end of the scope
// newInstance will be deleted at the end of the scope
// as there are no references to it
// as there are no references to it
}
}
</syntaxhighlight>
</enforce>
|
|
<enforce>
<enforce>
// this array keeps strong references to its items
// this array keeps a strong reference to its items
array<ref ExampleClass> classArray = new array<ref ExampleClass>();
array<ref ExampleClass> classArray = {};
 
for (int i = 0; i < 10; i++)
ExampleClass newInstance;
for (int i; i < 10; i++)
{
{
ExampleClass newInstance = new ExampleClass();
newInstance = new ExampleClass();
classArray.Insert(newInstance);
classArray.Insert(newInstance);
// classArray keeps a strong reference to newInstance - it will not be cleared
// classArray keeps a strong reference to newInstance - it will not be cleared
}
}
</syntaxhighlight>
</enforce>
|}
|}


Avoid strong reference cyclic trap:
{| class="wikitable valign-top" style="width: 100%"
{| class="wikitable" style="width: 100%"
|+ {{Feature|important|Avoid strong reference cyclic trap.}}
! style="width: 50%" | Don't
! style="width: 50%" | Don't
! style="width: 50%" | Do
! style="width: 50%" | Do
|- style="vertical-align: top"
|-
| {{Feature|informative|Here, both ParentClass and ChildClass have a strong reference to each other, keeping the reference count above zero - creating an "island of isolation" (see [[Arma Reforger:Scripting: Automatic Reference Counting]] for more information).}}
| {{Feature|informative|
Here, both ParentClass and ChildClass have a strong reference to each other, keeping the reference count above zero - creating an "island of isolation" (see {{Link|Arma Reforger:Scripting: Automatic Reference Counting}} for more information).
}}
<enforce>
<enforce>
class MainClass
class MainClass
{
{
ref SubClass m_subClass;
ref SubClass m_SubClass;
 
void MainClass()
void MainClass()
{
{
m_subClass = new SubClass(this);
m_SubClass = new SubClass(this);
}
}
}
}
 
class SubClass
class SubClass
{
{
ref MainClass m_parent;
ref MainClass m_Parent;
 
void SubClass(MainClass parent)
void SubClass(MainClass parent)
{
{
m_parent = parent;
m_Parent = parent;
}
}
 
void DoSomething()
void DoSomething()
{
{
Print(m_parent);
Print(m_Parent);
}
}
}
}
</syntaxhighlight>
</enforce>
| {{Feature|informative|Here, the MainClass needs the SubClass (it creates it in its constructor meaning it needs it to work) but the subClass does not require MainClass - if the MainClass reference doesn't exist, it will simply not use it.}}
| {{Feature|informative|
Here, the MainClass needs the SubClass (it creates it in its constructor meaning it needs it to work) but the subClass does not require MainClass - if the MainClass reference does not exist, it will simply not use it.
}}
<enforce>
<enforce>
class MainClass
class MainClass
{
{
ref SubClass m_subClass;
ref SubClass m_SubClass;
 
void MainClass()
void MainClass()
{
{
m_subClass = new SubClass(this);
m_SubClass = new SubClass(this);
}
}
}
}
 
class SubClass
class SubClass
{
{
MainClass m_parent; // ref removed
MainClass m_Parent; // ref removed
 
void SubClass(MainClass parent)
void SubClass(MainClass parent)
{
{
m_parent = parent;
m_Parent = parent;
}
}
 
void DoSomething()
void DoSomething()
{
{
if (!m_parent) // null safety check
if (!m_Parent) // null safety check
{
return;
return;
}
 
Print(m_parent);
Print(m_Parent);
}
}
}
}
</syntaxhighlight>
</enforce>
|}
|}


Line 175: Line 219:


<!--
<!--
{| class="wikitable" style="width: 100%"
{| class="wikitable valign-top" style="width: 100%"
|+ {{Feature|important|Do this instead of that.}}
! style="width: 50%" | Don't
! style="width: 50%" | Don't
! style="width: 50%" | Do
! style="width: 50%" | Do
|- style="vertical-align: top"
|-
|
|
<enforce>
<enforce>


</syntaxhighlight>
</enforce>
|
|
<enforce>
<enforce>


</syntaxhighlight>
</enforce>
|}
|}
-->
-->

Latest revision as of 11:38, 9 September 2024

Don't Do

class ExampleClass { int LProcLgh; int stringlength( string Value ){ LProcLgh= Value.Length(); Print ( "String length obtained: "+LProcLgh ); return LProcLgh; } }

class ExampleClass { protected int m_iLastProcessedLength; int GetStringLength(string value) { m_iLastProcessedLength = value.Length(); Print("String length obtained: " + m_iLastProcessedLength); return m_iLastProcessedLength; } int GetLastProcessedLength() { return m_iLastProcessedLength; } }

Keep variables as close as possible to their usage.
Don't Do

class ExampleClass { protected int m_iLength; int GetStringLength(string name) { m_iLength = name.Length(); Print("String length obtained: " + m_iLength); return m_iLength; } }

class ExampleClass { // keeping the variable into method scope and away from the instance int GetStringLength(string name) { int length = name.Length(); Print("String length obtained: " + length); return length; } }

Do not scope more than necessary.
Don't Do

switch (value) { case 0: { Print("0"); break; } default: { Print("default"); break; } }

switch (value) { case 0: Print("0"); break; default: // brackets are needed only if variables are declared in the 'case' code { // otherwise scoping is superfluous (and very slightly impacts performance) string message = "default"; Print(message); break; } }

Keep a strong reference (ref keyword) to required objects.
Don't Do

// this array only lists pointers but does not increase the reference count array<ExampleClass> classArray = {}; ExampleClass newInstance; for (int i; i < 10; i++) { newInstance = new ExampleClass(); classArray.Insert(newInstance); // newInstance will be deleted at the end of the scope // as there are no references to it }

// this array keeps a strong reference to its items array<ref ExampleClass> classArray = {}; ExampleClass newInstance; for (int i; i < 10; i++) { newInstance = new ExampleClass(); classArray.Insert(newInstance); // classArray keeps a strong reference to newInstance - it will not be cleared }

Avoid strong reference cyclic trap.
Don't Do
Here, both ParentClass and ChildClass have a strong reference to each other, keeping the reference count above zero - creating an "island of isolation" (see Scripting: Automatic Reference Counting for more information).

class MainClass { ref SubClass m_SubClass; void MainClass() { m_SubClass = new SubClass(this); } } class SubClass { ref MainClass m_Parent; void SubClass(MainClass parent) { m_Parent = parent; } void DoSomething() { Print(m_Parent); } }

Here, the MainClass needs the SubClass (it creates it in its constructor meaning it needs it to work) but the subClass does not require MainClass - if the MainClass reference does not exist, it will simply not use it.

class MainClass { ref SubClass m_SubClass; void MainClass() { m_SubClass = new SubClass(this); } } class SubClass { MainClass m_Parent; // ref removed void SubClass(MainClass parent) { m_Parent = parent; } void DoSomething() { if (!m_Parent) // null safety check return; Print(m_Parent); } }