Skip to content

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, else
  • while
  • function, return
  • true, 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

value = 100;
value = 200; // Update existing variable
value += 50; // Compound 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

total = 0;

items.ForEach((item) => {
  total += item.price;
});

$Log("Total: " + total);

Pattern 2: Conditional Assignment

// Default value
discount = 0;
if (isPremium) {
  discount = 0.2;
}

// Using ternary
discount = isPremium ? 0.2 : 0;

Pattern 3: Swap Variables

a = 10;
b = 20;

// Swap using temporary
temp = a;
a = b;
b = temp;
// Now: a = 20, b = 10

Pattern 4: Counter

counter = 0;

while (counter < 10) {
  $Log(counter);
  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