tags: - variables - constants - scope - assignment
Variables and Constants¶
This guide covers variable declaration, assignment, scope, and constants in EverSharp.
Variable Declaration¶
No Declaration Keyword¶
EverSharp does not use var, let, or const keywords. Variables are created by assignment:
// Simple assignment creates variable
name = "John";
age = 30;
active = true;
// Multiple assignments
x = 10;
y = 20;
z = x + y;
Automatic Initialization¶
Unassigned variables automatically initialize to null:
// These are equivalent
result; // null (auto-initialized)
result = null; // null (explicit)
// Check before use
if (result == null) {
result = 0;
}
Assignment¶
Simple Assignment¶
// Basic assignment
premium = 1000;
discount = 0.15;
message = "Hello";
// Assign from expressions
total = premium + tax;
fullName = firstName + " " + lastName;
isEligible = age >= 18;
Multiple Assignment¶
Assignment returns the assigned value, allowing chaining:
// Right-to-left evaluation
a = b = c = 10; // All variables set to 10
// Equivalent to:
c = 10;
b = c; // b = 10
a = b; // a = 10
Compound Assignment¶
value = 100;
// Arithmetic compound
value += 50; // value = 150
value -= 30; // value = 120
value *= 2; // value = 240
value /= 4; // value = 60
value %= 7; // value = 4
// String compound
message = "Hello";
message += " World"; // "Hello World"
Variable Scope¶
Global Scope¶
Variables declared outside functions are global:
// Global variables
globalTax = 0.08;
globalDiscount = 0.1;
function calculate() {
// Can access global variables
amount = basePremium * (1 + globalTax);
return amount;
}
Function Scope¶
Variables inside functions are local to that function:
function calculatePremium() {
// Local variables
base = 1000;
rate = 0.15;
premium = base * rate;
return premium;
}
// Cannot access 'base', 'rate', or 'premium' here
Block Scope¶
Blocks (code inside {}) create new scopes:
x = 10; // Outer scope
{
y = 20; // Inner scope
z = x + y; // Can access outer 'x'
}
// 'y' and 'z' not accessible here (block scope)
With control structures:
if (condition) {
temp = 10; // Local to if block
$Log(temp);
}
// 'temp' not accessible here
while (i < 10) {
value = i * 2; // Local to while block
i++;
}
// 'value' and 'i' not accessible here if declared inside
Lexical Scoping¶
EverSharp uses lexical (static) scoping:
x = "global";
function outer() {
x = "outer";
function inner() {
// Accesses 'x' from outer, not global
$Log(x); // "outer"
}
inner();
}
outer();
$Log(x); // "global" (unchanged)
Closures¶
Functions capture variables from their enclosing scope:
function makeCounter() {
count = 0;
// Returns function that captures 'count'
return function () {
count++;
return count;
};
}
counter = makeCounter();
$Log(counter()); // 1
$Log(counter()); // 2
$Log(counter()); // 3
Lambda closures:
multiplier = 10;
// Lambda captures 'multiplier'
multiply = (x) => x * multiplier;
$Log(multiply(5)); // 50
multiplier = 20;
$Log(multiply(5)); // 100 (uses current value)
Constants¶
Defining Constants¶
Constants are set via InitializeEnvironment from C#:
// C# code
var constants = new EverDictionary
{
{ "TAX_RATE", 0.08m },
{ "MAX_PREMIUM", 10000m },
{ "MIN_AGE", 18m }
};
runner.InitializeEnvironment(constants, variables);
Using Constants¶
// Read constants
premium = basePremium * (1 + TAX_RATE);
if (premium > MAX_PREMIUM) {
premium = MAX_PREMIUM;
}
if (age < MIN_AGE) {
return null;
}
Constants are Read-Only¶
Attempting to modify a constant creates a new local variable instead:
// Constants defined in C#
TAX_RATE = 0.08; // Original constant
function test() {
// This creates a NEW local variable
TAX_RATE = 0.1;
$Log(TAX_RATE); // 0.10 (local variable)
}
test();
$Log(TAX_RATE); // 0.08 (original constant unchanged)
Convention¶
By convention, constants use UPPER_SNAKE_CASE:
// Constants (from C#)
MAX_PREMIUM;
MIN_AGE;
DEFAULT_RATE;
TAX_RATE;
// Variables (in script)
premium;
customerAge;
currentRate;
Naming Conventions¶
Valid Identifiers¶
Variables can contain:
- Letters (a-z, A-Z)
- Digits (0-9, but not at start)
- Underscore (_)
- Dollar sign ($)
// Valid names
userName;
user_name;
UserName;
_private;
$specialVar;
camelCase;
PascalCase;
snake_case;
value123;
Invalid Identifiers¶
// Invalid names
// 123value // Cannot start with digit
// user-name // Hyphen not allowed
// user name // Space not allowed
// if // Reserved keyword
Reserved Keywords¶
Cannot be used as variable names:
if,elsewhilefunction,returntrue,false,null
Naming Styles¶
Recommended conventions:
// Variables and functions: camelCase
customerName = "John";
totalPremium = 1000;
function calculateTotal() {
return basePremium + tax;
}
// Constants: UPPER_SNAKE_CASE (defined in C#)
MAX_PREMIUM;
TAX_RATE;
// Objects and types: PascalCase (less common in scripts)
Customer = {
Name: "John",
Age: 30,
};
Variable Lifecycle¶
Creation¶
// Variable created on first assignment
count = 0; // 'count' now exists
// Before assignment, variables are null
// $Log(newVar); // null (auto-initialized)
newVar = 10;
Update¶
Scope Lifetime¶
function example() {
local = 10; // Created when function runs
if (condition) {
temp = 20; // Created if condition is true
}
// 'local' still exists
// 'temp' still exists (function scope)
}
// After function ends:
// 'local' and 'temp' are destroyed
Working with External Data¶
Receiving Data from C¶
// C# code
var variables = new EverDictionary
{
{ "userAge", 35m },
{ "userName", "Alice" },
{ "policyData", policyDictionary }
};
runner.InitializeEnvironment(constants, variables);
// EverSharp script can use these variables
greeting = "Hello, " + userName;
isAdult = userAge >= 18;
premium = policyData.basePremium;
Returning Data to C¶
// Set variables in script
result = 1000;
status = "approved";
details = {
premium: result,
approved: true,
};
// C# code
runner.Run(script);
var result = runner.GlobalVariables.GetNumber("result");
var status = runner.GlobalVariables.GetStr("status");
var details = runner.GlobalVariables.GetDictionary("details");
Common Patterns¶
Pattern 1: Accumulator¶
Pattern 2: Conditional Assignment¶
// Default value
discount = 0;
if (isPremium) {
discount = 0.2;
}
// Using ternary
discount = isPremium ? 0.2 : 0;
Pattern 3: Swap Variables¶
Pattern 4: Counter¶
Pattern 5: Flag Variables¶
hasErrors = false;
isComplete = false;
if (validate()) {
isComplete = true;
} else {
hasErrors = true;
}
Pattern 6: Configuration¶
// Load configuration
config = {
maxAttempts: 3,
timeout: 30,
retryDelay: 1000,
};
// Use configuration
attempts = 0;
while (attempts < config.maxAttempts) {
if (tryOperation()) {
break;
}
attempts++;
}
Variable Shadowing¶
Inner scope can shadow outer scope variables:
x = 10; // Outer x
function test() {
x = 20; // Shadows outer x
$Log(x); // 20
}
test();
$Log(x); // Still 10 (outer unchanged)
In blocks:
value = "outer";
{
value = "inner"; // Shadows outer
$Log(value); // "inner"
}
$Log(value); // "outer" (if block-scoped correctly)
Best Practices¶
1. Initialize Before Use¶
// Good
result = 0;
if (condition) {
result = calculate();
}
// Risky (relying on auto-initialization)
if (condition) {
result = calculate();
}
// result might still be null
2. Use Descriptive Names¶
// Good
customerAge = 35;
totalPremium = 1500;
isEligible = true;
// Poor
x = 35;
t = 1500;
f = true;
3. Minimize Global Variables¶
// Good: encapsulate in function
function calculatePremium(base, rate) {
result = base * rate;
return result;
}
// Less ideal: many globals
base = 1000;
rate = 0.15;
premium = base * rate;
4. Constants for Magic Numbers¶
// Good (constants defined in C#)
if (age < MIN_DRIVING_AGE) {
return null;
}
premium = amount * DEFAULT_RATE;
// Less ideal
if (age < 16) {
return null;
}
premium = amount * 0.15;
5. Check Null for Optional Values¶
// Good
if (optionalValue != null) {
process(optionalValue);
}
// Risky
process(optionalValue); // May error if null
6. Use Meaningful Scope¶
// Good: limited scope
function calculate() {
temp = performComplexCalculation();
return temp * 2;
}
// Less ideal: unnecessary global
temp = performComplexCalculation();
result = temp * 2;
Common Mistakes¶
Mistake 1: Using var/let/const¶
// ERROR: var, let, const don't exist
// var x = 10;
// let y = 20;
// const Z = 30;
// CORRECT: Direct assignment
x = 10;
y = 20;
Z = 30;
Mistake 2: Forgetting Null Check¶
// ERROR: May fail if object is null
name = object.name;
// CORRECT: Check first
if (object != null) {
name = object.name;
}
Mistake 3: Assuming Type Persistence¶
// Type can change
value = 42; // number
value = "hello"; // now string
value = [1, 2, 3]; // now array
// Be careful with type assumptions
// result = value + 10; // ERROR if value is string
Mistake 4: Scope Confusion¶
function outer() {
x = 10;
function inner() {
x = 20; // Modifies outer's x
}
inner();
$Log(x); // 20, not 10
}
Next Steps¶
- Learn control flow: Control Flow
- Explore functions: Functions
- See examples: Basic Calculations