Chapter 1.12: What Does NOT Exist (Gotchas)
Home | << Previous: Error Handling | Gotchas | Next: Functions & Methods >>
Indice dei Contenuti
- Complete Gotchas Reference
- No Ternary Operator
- No do...while Loop
- No try/catch/throw
- No Multiple Inheritance
- No Operator Overloading (Except Index)
- No Lambdas / Anonymous Functions
- No Delegates / Function Pointers (Native)
- No String Escape for Backslash/Quote
- No Variable Redeclaration in else-if Blocks
- No Ternary in Variable Declaration
- Object.IsAlive() Does NOT Exist on Base Object
- No nullptr — Use NULL or null
- switch/case Does NOT Fall Through
- No Default Parameter Expressions
- JsonFileLoader.JsonLoadFile Returns void
- No #define Value Substitution
- No Interfaces / Abstract Classes (Enforced)
- No Generics Constraints
- No Enum Validation
- No Variadic Parameters
- No Nested Class Declarations
- Static Arrays Are Fixed-Size
- array.Remove Is Unordered
- No #include — Everything via config.cpp
- No Namespaces
- String Methods Modify In-Place
- ref Cycles Cause Memory Leaks
- No Destructor Guarantee on Server Shutdown
- No Scope-Based Resource Management (RAII)
- GetGame().GetPlayer() Returns null on Server
- Le classi
sealednon possono essere estese (1.28+) - Limite parametri metodo: massimo 16 (1.28+)
- Avvisi attributo
Obsolete(1.28+) - Bug di confronto
int.MIN - La negazione booleana di elementi array fallisce
- Espressione complessa in assegnazione array causa crash
foreachsu valore di ritorno del metodo causa crash- Precedenza operatori bitwise vs confronto
- Blocchi
#ifdef/#ifndefvuoti causano crash GetGame().IsClient()restituisce False durante il caricamento- I messaggi di errore di compilazione indicano il file sbagliato
- I file
crash_*.lognon sono crash reali
- Coming From C++
- Coming From C#
- Coming From Java
- Coming From Python
- Quick Reference Table
- Navigation
Riferimento Completo delle Insidie
1. No Ternary Operator
Cosa scriveresti:
int x = (condition) ? valueA : valueB;Cosa succede: Errore di compilazione. The ? : operator does not exist.
Soluzione corretta:
int x;
if (condition)
x = valueA;
else
x = valueB;2. No do...while Loop
Cosa scriveresti:
do {
Process();
} while (HasMore());Cosa succede: Errore di compilazione. The do keyword does not exist.
Soluzione corretta — flag pattern:
bool first = true;
while (first || HasMore())
{
first = false;
Process();
}Soluzione corretta — break pattern:
while (true)
{
Process();
if (!HasMore())
break;
}3. No try/catch/throw
Cosa scriveresti:
try {
RiskyOperation();
} catch (Exception e) {
HandleError(e);
}Cosa succede: Errore di compilazione. These keywords do not exist.
Soluzione corretta: Guard clauses with ritorno anticipato.
void DoOperation()
{
if (!CanDoOperation())
{
ErrorEx("Cannot perform operation", ErrorExSeverity.WARNING);
return;
}
// Proceed safely
RiskyOperation();
}Vedi Chapter 1.11 — Error Handling for full patterns.
4. No Multiple Inheritance
Cosa scriveresti:
class MyClass extends BaseA, BaseB // Two base classesCosa succede: Errore di compilazione. Only ereditarieta' singola is supported.
Soluzione corretta: Inherit from one class, compose the other:
class MyClass extends BaseA
{
ref BaseB m_Helper;
void MyClass()
{
m_Helper = new BaseB();
}
}5. No Operator Overloading (Except Index)
Cosa scriveresti:
Vector3 operator+(Vector3 a, Vector3 b) { ... }
bool operator==(MyClass other) { ... }Cosa succede: Errore di compilazione. Custom operators cannot be defined.
Soluzione corretta: Use named methods:
class MyVector
{
float x, y, z;
MyVector Add(MyVector other)
{
MyVector result = new MyVector();
result.x = x + other.x;
result.y = y + other.y;
result.z = z + other.z;
return result;
}
bool Equals(MyVector other)
{
return (x == other.x && y == other.y && z == other.z);
}
}Eccezione: The index operator [] can be overloaded via Get(index) and Set(index, value) methods:
class MyContainer
{
int data[10];
int Get(int index) { return data[index]; }
void Set(int index, int value) { data[index] = value; }
}
MyContainer c = new MyContainer();
c[3] = 42; // Calls Set(3, 42)
int v = c[3]; // Calls Get(3)6. No Lambdas / Anonymous Functions
Cosa scriveresti:
array.Sort((a, b) => a.name.CompareTo(b.name));
button.OnClick += () => { DoSomething(); };Cosa succede: Errore di compilazione. Lambda syntax does not exist.
Soluzione corretta: Define named methods and pass them as ScriptCaller or use string-based callbacks:
// Named method
void OnButtonClick()
{
DoSomething();
}
// String-based callback (used by CallLater, timers, etc.)
GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(this.OnButtonClick, 1000, false);7. No Delegates / Function Pointers (Native)
Cosa scriveresti:
delegate void MyCallback(int value);
MyCallback cb = SomeFunction;
cb(42);Cosa succede: Errore di compilazione. The delegate keyword does not exist.
Soluzione corretta: Use ScriptCaller, ScriptInvoker, or string-based method names:
// ScriptCaller (single callback)
ScriptCaller caller = ScriptCaller.Create(MyFunction);
// ScriptInvoker (event with multiple subscribers)
ref ScriptInvoker m_OnEvent = new ScriptInvoker();
m_OnEvent.Insert(MyHandler);
m_OnEvent.Invoke(); // Calls all registered handlers8. No String Escape for Backslash/Quote
Cosa scriveresti:
string path = "C:\\Users\\folder";
string quote = "He said \"hello\"";Cosa succede: CParser crashes or produces garbled output. The \\ and \" escape sequences break the string parser.
Soluzione corretta: Evita backslash and quote characters in string literals entirely:
// Use forward slashes for paths
string path = "C:/Users/folder";
// Use single quotes or rephrase to avoid embedded double quotes
string quote = "He said 'hello'";
// Use string concatenation if you absolutely need special chars
// (still risky — test thoroughly)Nota:
\n,\r, and\tescape sequences DO work. Only\\and\"are broken.
9. No Variable Redeclaration in else-if Blocks
Cosa scriveresti:
if (condA)
{
string msg = "Case A";
Print(msg);
}
else if (condB)
{
string msg = "Case B"; // Same variable name in sibling block
Print(msg);
}Cosa succede: Errore di compilazione: "multiple declaration of variable 'msg'". Enforce Script treats variables in sibling if/else if/else blocks as sharing the same scope.
Soluzione corretta — unique names:
if (condA)
{
string msgA = "Case A";
Print(msgA);
}
else if (condB)
{
string msgB = "Case B";
Print(msgB);
}Soluzione corretta — declare before the if:
string msg;
if (condA)
{
msg = "Case A";
}
else if (condB)
{
msg = "Case B";
}
Print(msg);10. No Ternary in Variable Declaration
Related to gotcha #1, but specific to declarations:
Cosa scriveresti:
string label = isAdmin ? "Admin" : "Player";Soluzione corretta:
string label;
if (isAdmin)
label = "Admin";
else
label = "Player";11. Object.IsAlive() Does NOT Exist on Base Object
Cosa scriveresti:
Object obj = GetSomething();
if (obj.IsAlive()) // Check if aliveCosa succede: Errore di compilazione or crash a runtime. IsAlive() is defined on EntityAI, not on Object.
Soluzione corretta:
Object obj = GetSomething();
EntityAI eai;
if (Class.CastTo(eai, obj) && eai.IsAlive())
{
// Safely alive
}12. No nullptr — Use NULL or null
Cosa scriveresti:
if (obj == nullptr)Cosa succede: Errore di compilazione. The nullptr keyword does not exist.
Soluzione corretta:
if (obj == null) // lowercase works
if (obj == NULL) // uppercase also works
if (!obj) // idiomatic null check (preferred)13. switch/case Does NOT Fall Through
Cosa scriveresti (expecting C/C++ fall-through):
switch (value)
{
case 1:
case 2:
case 3:
Print("1, 2, or 3"); // In C++, cases 1 and 2 fall through to here
break;
}Cosa succede: Only case 3 executes the Print. Cases 1 and 2 are empty — they do nothing and do NOT fall through.
Soluzione corretta:
if (value >= 1 && value <= 3)
{
Print("1, 2, or 3");
}
// Or handle each case explicitly:
switch (value)
{
case 1:
Print("1, 2, or 3");
break;
case 2:
Print("1, 2, or 3");
break;
case 3:
Print("1, 2, or 3");
break;
}Nota:
breakis technically opzionale in Enforce Script since there is no fall-through, but it is conventional to include it.
14. No Predefinito Parameter Expressions
Cosa scriveresti:
void Spawn(vector pos = GetDefaultPos()) // Expression as default
void Spawn(vector pos = Vector(0, 100, 0)) // Constructor as defaultCosa succede: Errore di compilazione. Predefinito parameter values must be literals or NULL.
Soluzione corretta:
void Spawn(vector pos = "0 100 0") // String literal for vector — OK
void Spawn(int count = 5) // Integer literal — OK
void Spawn(float radius = 10.0) // Float literal — OK
void Spawn(string name = "default") // String literal — OK
void Spawn(Object obj = NULL) // NULL — OK
// For complex defaults, use overloads:
void Spawn()
{
Spawn(GetDefaultPos()); // Call the parametric version
}
void Spawn(vector pos)
{
// Actual implementation
}15. JsonFileLoader.JsonLoadFile Restituisce void
Cosa scriveresti:
MyConfig cfg = JsonFileLoader<MyConfig>.JsonLoadFile(path);
// or:
if (JsonFileLoader<MyConfig>.JsonLoadFile(path, cfg))Cosa succede: Errore di compilazione. JsonLoadFile returns void, not the loaded object or a bool.
Soluzione corretta:
MyConfig cfg = new MyConfig(); // Create instance first with defaults
JsonFileLoader<MyConfig>.JsonLoadFile(path, cfg); // Populates cfg in-place
// cfg now contains loaded values (or still has defaults if file was invalid)Nota: The newer
JsonFileLoader<T>.LoadFile()method returnsbool, butJsonLoadFile(the commonly seen version) does not.
16. No #define Value Substitution
Cosa scriveresti:
#define MAX_PLAYERS 60
#define VERSION_STRING "1.0.0"
int max = MAX_PLAYERS;Cosa succede: Errore di compilazione. Enforce Script #define only creates existence flags for #ifdef checks. It does not support value substitution.
Soluzione corretta:
// Use const for values
const int MAX_PLAYERS = 60;
const string VERSION_STRING = "1.0.0";
// Use #define only for conditional compilation flags
#define MY_MOD_ENABLED17. No Interfaces / Abstract Classes (Enforced)
Cosa scriveresti:
interface ISerializable
{
void Serialize();
void Deserialize();
}
abstract class BaseProcessor
{
abstract void Process();
}Cosa succede: The interface and abstract keywords do not exist.
Soluzione corretta: Use regular classes with empty base methods:
// "Interface" — base class with empty methods
class ISerializable
{
void Serialize() {} // Override in subclass
void Deserialize() {} // Override in subclass
}
// "Abstract" class — same pattern
class BaseProcessor
{
void Process()
{
ErrorEx("BaseProcessor.Process() must be overridden!", ErrorExSeverity.ERROR);
}
}
class ConcreteProcessor extends BaseProcessor
{
override void Process()
{
// Actual implementation
}
}The compiler does NOT enforce that subclasses override the base methods. Forgetting to override silently uses the empty base implementation.
18. No Generics Constraints
Cosa scriveresti:
class Container<T> where T : EntityAI // Constrain T to EntityAICosa succede: Errore di compilazione. The where clause does not exist. Template parameters accept any type.
Soluzione corretta: Validate at runtime:
class EntityContainer<Class T>
{
void Add(T item)
{
// Runtime type check instead of compile-time constraint
EntityAI eai;
if (!Class.CastTo(eai, item))
{
ErrorEx("EntityContainer only accepts EntityAI subclasses");
return;
}
// proceed
}
}19. No Enum Validation
Cosa scriveresti:
EDamageState state = (EDamageState)999; // Expect error or exceptionCosa succede: No error. Any int value can be assigned to an enum variable, even values outside the defined range.
Soluzione corretta: Validate manually:
bool IsValidDamageState(int value)
{
return (value >= EDamageState.PRISTINE && value <= EDamageState.RUINED);
}
int rawValue = LoadFromConfig();
if (IsValidDamageState(rawValue))
{
EDamageState state = rawValue;
}
else
{
Print("Invalid damage state: " + rawValue.ToString());
EDamageState state = EDamageState.PRISTINE; // fallback
}20. No Variadic Parameters
Cosa scriveresti:
void Log(string format, params object[] args)
void Printf(string fmt, ...)Cosa succede: Errore di compilazione. Variadic parameters do not exist.
Soluzione corretta: Use string.Format with fixed parameter counts, or use Param classes:
// string.Format supports up to 9 positional arguments
string msg = string.Format("Player %1 at %2 with %3 HP", name, pos, hp);
// For variable-count data, pass an array
void LogMultiple(string tag, array<string> messages)
{
foreach (string msg : messages)
{
Print("[" + tag + "] " + msg);
}
}21. No Nested Class Declarations
Cosa scriveresti:
class Outer
{
class Inner // Nested class
{
int value;
}
}Cosa succede: Errore di compilazione. Classes cannot be declared inside other classes.
Soluzione corretta: Declare all classes at the top level, use naming conventions to show relationships:
class MySystem_Config
{
int value;
}
class MySystem
{
ref MySystem_Config m_Config;
}22. Static Arrays Are Fixed-Size
Cosa scriveresti:
int size = GetCount();
int arr[size]; // Dynamic size at runtimeCosa succede: Errore di compilazione. Static array sizes must be compile-time constants.
Soluzione corretta:
// Use a const for static arrays
const int BUFFER_SIZE = 64;
int arr[BUFFER_SIZE];
// Or use dynamic arrays for runtime sizing
array<int> arr = new array<int>;
arr.Resize(GetCount());23. array.Remove Is Unordered
Cosa scriveresti (expecting order preservation):
array<string> items = {"A", "B", "C", "D"};
items.Remove(1); // Expect: {"A", "C", "D"}Cosa succede: Remove(index) swaps the element with the last element, then removes the last. Result: {"A", "D", "C"}. Order is NOT preserved.
Soluzione corretta:
// Use RemoveOrdered for order preservation (slower — shifts elements)
items.RemoveOrdered(1); // {"A", "C", "D"} — correct order
// Use RemoveItem to find and remove by value (also ordered)
items.RemoveItem("B"); // {"A", "C", "D"}24. No #include — Everything via config.cpp
Cosa scriveresti:
#include "MyHelper.c"
#include "Utils/StringUtils.c"Cosa succede: No effect or errore di compilazione. Non c'e' #include directive.
Soluzione corretta: All script files are loaded through config.cpp in the mod's CfgMods entry. File loading order is determined by the script layer (3_Game, 4_World, 5_Mission) and alphabetical order within each layer.
// config.cpp
class CfgMods
{
class MyMod
{
type = "mod";
dependencies[] = { "Game", "World", "Mission" };
class defs
{
class gameScriptModule
{
files[] = { "MyMod/Scripts/3_Game" };
};
class worldScriptModule
{
files[] = { "MyMod/Scripts/4_World" };
};
class missionScriptModule
{
files[] = { "MyMod/Scripts/5_Mission" };
};
};
};
};25. No Namespaces
Cosa scriveresti:
namespace MyMod { class Config { } }
namespace MyMod.Utils { class StringHelper { } }Cosa succede: Errore di compilazione. The namespace keyword does not exist. All classes share a single global scope.
Soluzione corretta: Use naming prefixes to evita conflicts:
class MyConfig { } // MyFramework
class MyAI_Config { } // MyAI Mod
class MyM_MissionData { } // MyMissions Mod
class VPP_AdminConfig { } // VPP Admin26. String Methods Modify In-Place
Cosa scriveresti (expecting a return value):
string upper = myString.ToUpper(); // Expect: returns new stringCosa succede: ToUpper() and ToLower() modify the string in place and return void.
Soluzione corretta:
// Make a copy first if you need the original preserved
string original = "Hello World";
string upper = original;
upper.ToUpper(); // upper is now "HELLO WORLD", original unchanged
// Same for TrimInPlace
string trimmed = " hello ";
trimmed.TrimInPlace(); // "hello"27. ref Cycles Cause Memory Leaks
Cosa scriveresti:
class Parent
{
ref Child m_Child;
}
class Child
{
ref Parent m_Parent; // Circular ref — both ref each other
}Cosa succede: Neither object is ever garbage collected. The reference counts never reach zero perche' each holds a ref to the other.
Soluzione corretta: One side must use a raw (non-ref) pointer:
class Parent
{
ref Child m_Child; // Parent OWNS the child (ref)
}
class Child
{
Parent m_Parent; // Child REFERENCES the parent (raw — no ref)
}28. No Destructor Guarantee on Server Shutdown
Cosa scriveresti (expecting cleanup):
void ~MyManager()
{
SaveData(); // Expect this runs on shutdown
}Cosa succede: Server shutdown may kill the process before destructors run. Your save never happens.
Soluzione corretta: Save proactively at regular intervals and on known lifecycle events:
class MyManager
{
void OnMissionFinish() // Called before shutdown
{
SaveData(); // Reliable save point
}
void OnUpdate(float dt)
{
m_SaveTimer += dt;
if (m_SaveTimer > 300.0) // Every 5 minutes
{
SaveData();
m_SaveTimer = 0;
}
}
}29. No Scope-Based Resource Management (RAII)
Cosa scriveresti (in C++):
{
FileHandle f = OpenFile("test.txt", FileMode.WRITE);
// f automatically closed when scope ends
}Cosa succede: Enforce Script does not close file handles when variables go out of scope (even with autoptr).
Soluzione corretta: Sempre close resources explicitly:
FileHandle fh = OpenFile("$profile:MyMod/data.txt", FileMode.WRITE);
if (fh != 0)
{
FPrintln(fh, "data");
CloseFile(fh); // Must close manually!
}30. GetGame().GetPlayer() Restituisce null on Server
Cosa scriveresti:
PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
player.DoSomething(); // CRASH on server!Cosa succede: GetGame().GetPlayer() returns the local player. On a server dedicato, there is no local player — it returns null.
Soluzione corretta: On server, iterate the player list:
#ifdef SERVER
array<Man> players = new array<Man>;
GetGame().GetPlayers(players);
foreach (Man man : players)
{
PlayerBase player;
if (Class.CastTo(player, man))
{
player.DoSomething();
}
}
#else
PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
if (player)
{
player.DoSomething();
}
#endif31. Le classi sealed non possono essere estese (1.28+)
A partire da DayZ 1.28, il compilatore Enforce Script applica la parola chiave sealed. Una classe o un metodo contrassegnato sealed non puo essere ereditato o sovrascritto. Se provi a estendere una classe sealed:
// Se BI segna SomeVanillaClass come sealed:
class MyClass : SomeVanillaClass // ERRORE DI COMPILAZIONE in 1.28+
{
}Controlla il dump degli script vanilla per verificare se una classe e contrassegnata sealed prima di provare a ereditare da essa. Se devi modificare il comportamento di una classe sealed, usa la composizione (incapsulala come membro) invece dell'ereditarieta.
32. Limite parametri metodo: massimo 16 (1.28+)
Enforce Script ha sempre avuto un limite di 16 parametri per i metodi, ma prima della 1.28 era un overflow silenzioso del buffer che causava crash casuali. A partire dalla 1.28, il compilatore produce un errore hard:
// ERRORE DI COMPILAZIONE in 1.28+ — supera 16 parametri
void MyMethod(int a, int b, int c, int d, int e, int f, int g, int h,
int i, int j, int k, int l, int m, int n, int o, int p,
int q) // 17esimo parametro = errore
{
}Soluzione: Rifattorizza passando una classe o un array invece di parametri individuali.
33. Avvisi attributo Obsolete (1.28+)
DayZ 1.28 ha introdotto l'attributo Obsolete. Le funzioni e le classi contrassegnate con [Obsolete] generano avvisi del compilatore. Queste API funzionano ancora ma sono programmate per la rimozione in un futuro aggiornamento. Controlla l'output della build per gli avvisi di obsolescenza e migra all'alternativa raccomandata.
34. Bug di confronto int.MIN
I confronti che coinvolgono int.MIN (-2147483648) producono risultati errati:
int val = 1;
if (val < int.MIN) // Si valuta come TRUE — dovrebbe essere false
{
// Questo blocco viene eseguito in modo errato
}Evita confronti diretti con int.MIN. Usa una costante memorizzata oppure confronta con un valore negativo specifico.
35. La negazione booleana di elementi array fallisce
La negazione booleana diretta degli elementi di un array non compila:
array<int> list = {0, 1, 2};
if (!list[1]) // NON COMPILA
if (list[1] == 0) // Funziona — usa un confronto esplicitoUsa sempre controlli di uguaglianza espliciti quando verifichi gli elementi di un array per vero/falso.
36. Espressione complessa in assegnazione array causa crash
Assegnare un'espressione complessa direttamente a un elemento di un array puo causare un segmentation fault:
// CRASH a runtime
m_Values[index] = vector.DistanceSq(posA, posB) <= distSq;
// SICURO — usa una variabile intermedia
bool result = vector.DistanceSq(posA, posB) <= distSq;
m_Values[index] = result;Memorizza sempre i risultati delle espressioni complesse in una variabile locale prima di assegnare a un array.
37. foreach su valore di ritorno del metodo causa crash
Usare foreach direttamente sul valore di ritorno di un metodo causa un'eccezione null pointer alla seconda iterazione:
// CRASH al 2o elemento
foreach (string item : GetMyArray())
{
}
// SICURO — memorizza prima in una variabile locale
array<string> items = GetMyArray();
foreach (string item : items)
{
}38. Precedenza operatori bitwise vs confronto
Gli operatori bitwise hanno precedenza inferiore rispetto agli operatori di confronto, seguendo le regole C/C++:
int flags = 5;
int mask = 4;
if (flags & mask == mask) // SBAGLIATO: valutato come flags & (mask == mask)
if ((flags & mask) == mask) // CORRETTO: usa sempre le parentesi39. Blocchi #ifdef / #ifndef vuoti causano crash
I blocchi condizionali del preprocessore vuoti — anche quelli contenenti solo commenti — causano segmentation fault:
#ifdef SOME_DEFINE
// Questo blocco con solo commenti causa un SEGFAULT
#endifIncludi sempre almeno un'istruzione eseguibile o rimuovi completamente il blocco.
40. GetGame().IsClient() restituisce False durante il caricamento
Durante la fase di caricamento del client, GetGame().IsClient() restituisce false e GetGame().IsServer() restituisce true — anche sui client. Usa IsDedicatedServer() al suo posto:
// INAFFIDABILE durante la fase di caricamento
if (GetGame().IsClient()) { } // false durante il caricamento!
if (GetGame().IsServer()) { } // true durante il caricamento, anche sul client!
// AFFIDABILE
if (!GetGame().IsDedicatedServer()) { /* codice client */ }
if (GetGame().IsDedicatedServer()) { /* codice server */ }Eccezione: Se devi supportare la modalita offline/giocatore singolo, IsDedicatedServer() restituisce false anche per i listen server.
41. I messaggi di errore di compilazione indicano il file sbagliato
Quando il compilatore incontra una classe non definita o un conflitto di nomi di variabili, segnala l'errore alla posizione EOF dell'ultimo file analizzato con successo — non alla posizione reale dell'errore. Se vedi un errore che punta a un file che non hai modificato, l'errore reale si trova nel file che veniva analizzato subito dopo.
42. I file crash_*.log non sono crash reali
I file di log chiamati crash_<data>_<ora>.log contengono eccezioni di runtime, non veri segmentation fault. Il nome e fuorviante — sono errori di script, non crash del motore.
Provenendo da C++
Se are a C++ developer, here are the biggest adjustments:
| C++ Funzionalita' | Enforce Script Equivalent |
|---|---|
std::vector | array<T> |
std::map | map<K,V> |
std::unique_ptr | ref / autoptr |
dynamic_cast<T*> | Class.CastTo() or T.Cast() |
try/catch | Guard clauses |
operator+ | Named methods (Add()) |
namespace | Name prefixes (My, VPP_) |
#include | config.cpp files[] |
| RAII | Manual cleanup in lifecycle methods |
| Multiple inheritance | Single inheritance + composition |
nullptr | null / NULL |
| Templates with constraints | Templates without constraints + runtime checks |
do...while | while (true) { ... if (!cond) break; } |
Provenendo da C#
| C# Funzionalita' | Enforce Script Equivalent |
|---|---|
interface | Base class with empty methods |
abstract | Base class + ErrorEx in base methods |
delegate / event | ScriptInvoker |
Lambda => | Named methods |
?. null conditional | Manual null checks |
?? null coalescing | if (!x) x = default; |
try/catch | Guard clauses |
using (IDisposable) | Manual cleanup |
Properties { get; set; } | Public fields or explicit getter/setter methods |
| LINQ | Manual loops |
nameof() | Hardcoded strings |
async/await | CallLater / timers |
Provenendo da Java
| Java Funzionalita' | Enforce Script Equivalent |
|---|---|
interface | Base class with empty methods |
try/catch/finally | Guard clauses |
| Garbage collection | ref + reference counting (no GC for cycles) |
@Override | override keyword |
instanceof | obj.IsInherited(typename) |
package | Name prefixes |
import | config.cpp files[] |
enum with methods | enum (int-only) + helper class |
final | const (for variables only) |
| Annotations | Not available |
Provenendo da Python
| Python Funzionalita' | Enforce Script Equivalent |
|---|---|
| Dynamic typing | Static typing (all variables typed) |
try/except | Guard clauses |
lambda | Named methods |
| List comprehension | Manual loops |
**kwargs / *args | Fixed parameters |
| Duck typing | IsInherited() / Class.CastTo() |
__init__ | Constructor (same name as class) |
__del__ | Destructor (~ClassName()) |
import | config.cpp files[] |
| Multiple inheritance | Single inheritance + composition |
None | null / NULL |
| Indentation-based blocks | { } braces |
| f-strings | string.Format("text %1 %2", a, b) |
Tabella di Riferimento Rapido
| Funzionalita' | Exists? | Soluzione alternativa |
|---|---|---|
Ternary ? : | No | if/else |
do...while | No | while + break |
try/catch | No | Guard clauses |
| Multiple inheritance | No | Composition |
| Operator overloading | Index only | Named methods |
| Lambdas | No | Named methods |
| Delegates | No | ScriptInvoker |
\\ / \" in strings | Broken | Evita them |
| Variable redeclaration | Broken in else-if | Unique names or declare before if |
Object.IsAlive() | Not on base Object | Cast to EntityAI first |
nullptr | No | null / NULL |
| switch fall-through | No | Each case is independent |
| Predefinito param expressions | No | Literals or NULL only |
#define values | No | const |
| Interfaces | No | Empty classe base |
| Generic constraints | No | Runtime type checks |
| Enum validation | No | Manual range check |
| Variadic params | No | string.Format or arrays |
| Nested classes | No | Top-level with prefixed names |
| Variable-size static arrays | No | array<T> |
#include | No | config.cpp files[] |
| Namespaces | No | Name prefixes |
| RAII | No | Manual cleanup |
GetGame().GetPlayer() server | Restituisce null | Iterate GetPlayers() |
Ereditarieta classi sealed (1.28+) | Errore di compilazione | Usa la composizione |
| 17+ parametri metodo (1.28+) | Errore di compilazione | Passa una classe o un array |
API [Obsolete] (1.28+) | Avviso del compilatore | Migra all'API sostitutiva |
Confronti int.MIN | Risultati errati | Usa una costante memorizzata |
Negazione !array[i] | Errore di compilazione | Usa array[i] == 0 |
| Espr. complessa in assegnazione array | Segfault | Usa variabile intermedia |
foreach su ritorno metodo | Crash null pointer | Memorizza prima in variabile locale |
| Precedenza bitwise vs confronto | Valutazione errata | Usa sempre le parentesi |
Blocchi #ifdef vuoti | Segfault | Aggiungi un'istruzione o rimuovi il blocco |
IsClient() durante il caricamento | Restituisce false | Usa IsDedicatedServer() |
| Errore compilazione file sbagliato | Posizione fuorviante | Controlla il file analizzato dopo |
File crash_*.log | Non sono crash reali | Sono eccezioni runtime di script |
Navigazione
| Precedente | Up | Successivo |
|---|---|---|
| 1.11 Error Handling | Part 1: Enforce Script | 1.13 Funzioni e Metodi |
