Skip to content

Functions

Functions are reusable blocks of code that can be called multiple times. They accept parameters, execute statements, and optionally return values.


Function Declaration

Basic Syntax

function functionName(parameter1, parameter2, ...) {
    // Function body
    return value;
}

Example:

function greet(name) {
  return "Hello, " + name;
}

message = greet("Alice"); // "Hello, Alice"

No Parameters

function getCurrentTimestamp() {
  return $Now();
}

timestamp = getCurrentTimestamp();

Multiple Parameters

function calculatePremium(age, coverage, risk) {
  basePremium = coverage * 0.001;

  if (age < 25) {
    basePremium *= 1.5;
  } else if (age > 65) {
    basePremium *= 1.25;
  }

  if (risk == "high") {
    basePremium *= 1.3;
  }

  return $Round(basePremium, 2);
}

premium = calculatePremium(30, 250000, "low");

Return Statement

Returning Values

function add(a, b) {
  return a + b;
}

result = add(5, 3); // 8

Early Return

function divide(a, b) {
  if (b == 0) {
    return null; // Early exit
  }

  return a / b;
}

result = divide(10, 2); // 5
error = divide(10, 0); // null

No Return Value

Functions without an explicit return return null:

function logMessage(message) {
  $Log(message);
  // No return statement
}

result = logMessage("Hello"); // result is null

Multiple Returns

function categorize(score) {
  if (score >= 90) {
    return "A";
  } else if (score >= 80) {
    return "B";
  } else if (score >= 70) {
    return "C";
  } else if (score >= 60) {
    return "D";
  } else {
    return "F";
  }
}

Parameters

Parameter Count

Functions must be called with the exact number of parameters:

function calculate(a, b, c) {
  return a + b + c;
}

result = calculate(1, 2, 3); // OK: 6

// calculate(1, 2);             // ERROR: Too few arguments
// calculate(1, 2, 3, 4);       // ERROR: Too many arguments

Parameter Naming

Parameters are local variables within the function:

function multiply(x, y) {
  result = x * y; // x, y are local parameters
  return result; // result is local variable
}

output = multiply(4, 5); // 20
// x is not accessible here

No Default Parameters

EverSharp does not support default parameter values. Handle missing cases explicitly:

function greet(name) {
  if (name == null || name == "") {
    name = "Guest"; // Manual default
  }
  return "Hello, " + name;
}

No Named Parameters

Parameters must be passed positionally:

function createPolicy(number, premium, coverage) {
  return {
    number: number,
    premium: premium,
    coverage: coverage,
  };
}

// Must pass in order
policy = createPolicy("POL-001", 1200, 250000);

// Cannot use named parameters (not supported)
// policy = createPolicy(number: "POL-001", premium: 1200, coverage: 250000);

Function Scope

Local Variables

Variables declared inside functions are local:

function calculate() {
  local = 10; // Local to calculate()
  return local * 2;
}

result = calculate(); // 20
// local is not accessible here

Parameters are Local

function process(value) {
  value = value * 2; // Modifies local copy
  return value;
}

original = 10;
result = process(original); // 20
// original is still 10 (not modified)

Accessing Global Variables

Functions can read and write global variables:

taxRate = 0.08; // Global

function calculateTotal(subtotal) {
  return subtotal * (1 + taxRate);
}

total = calculateTotal(100); // 108

Shadowing

Local variables shadow globals with the same name:

value = 100; // Global

function process() {
  value = 50; // Creates local variable
  return value;
}

result = process(); // 50
// value is still 100 (global not modified)

To modify global:

value = 100; // Global

function updateGlobal() {
  value = 50; // Modifies global
}

updateGlobal();
// value is now 50

Recursion

Functions can call themselves:

Factorial

function factorial(n) {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

result = factorial(5); // 120

Fibonacci

function fibonacci(n) {
  if (n <= 1) {
    return n;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

fib10 = fibonacci(10); // 55

Recursive Array Sum

function sumArray(arr, index) {
  if (index >= arr.Length) {
    return 0;
  }
  return arr[index] + sumArray(arr, index + 1);
}

numbers = [1, 2, 3, 4, 5];
total = sumArray(numbers, 0); // 15

Note: Be careful with recursion depth. Large recursions may cause stack overflow.


First-Class Functions

Functions are values and can be:

Assigned to Variables

function add(a, b) {
  return a + b;
}

operation = add;
result = operation(5, 3); // 8

Passed as Arguments

function apply(func, value) {
  return func(value);
}

function double(x) {
  return x * 2;
}

function square(x) {
  return x * x;
}

result1 = apply(double, 5); // 10
result2 = apply(square, 5); // 25

Returned from Functions

function multiplier(factor) {
  function multiply(value) {
    return value * factor;
  }
  return multiply;
}

double = multiplier(2);
triple = multiplier(3);

result1 = double(5); // 10
result2 = triple(5); // 15

Closures

Functions capture variables from their enclosing scope:

Basic Closure

function makeCounter() {
  count = 0;

  function increment() {
    count++;
    return count;
  }

  return increment;
}

counter1 = makeCounter();
counter1(); // 1
counter1(); // 2
counter1(); // 3

counter2 = makeCounter();
counter2(); // 1 (separate count)

Closure with Parameters

function makeAdder(x) {
  function add(y) {
    return x + y; // Captures x
  }
  return add;
}

add5 = makeAdder(5);
add10 = makeAdder(10);

result1 = add5(3); // 8
result2 = add10(3); // 13

Multiple Closures

function createCalculator(initial) {
  value = initial;

  function add(x) {
    value += x;
    return value;
  }

  function subtract(x) {
    value -= x;
    return value;
  }

  function getValue() {
    return value;
  }

  return {
    add: add,
    subtract: subtract,
    getValue: getValue,
  };
}

calc = createCalculator(100);
calc.add(50); // 150
calc.subtract(30); // 120
current = calc.getValue(); // 120

Common Patterns

Pattern 1: Validation Function

function validateAge(age) {
  if (age == null) {
    return false;
  }

  if (age < 18 || age > 100) {
    return false;
  }

  return true;
}

if (validateAge(customerAge)) {
  // Process
}

Pattern 2: Calculation Function

function calculateDiscount(premium, customerType, years) {
  discount = 0;

  if (customerType == "premium") {
    discount = 0.15;
  } else if (customerType == "standard") {
    discount = 0.1;
  }

  if (years > 5) {
    discount += 0.05;
  }

  return premium * discount;
}

Pattern 3: Factory Function

function createPolicy(number, premium) {
  return {
    number: number,
    premium: premium,
    isActive: true,
    createdDate: $Today(),
  };
}

policy1 = createPolicy("POL-001", 1200);
policy2 = createPolicy("POL-002", 1500);

Pattern 4: Guard Clauses

function processPayment(payment) {
  if (payment == null) {
    return { success: false, error: "Payment is null" };
  }

  if (payment.amount <= 0) {
    return { success: false, error: "Invalid amount" };
  }

  if (payment.method == null) {
    return { success: false, error: "Payment method required" };
  }

  // Process payment
  return { success: true, transactionId: generateId() };
}

Pattern 5: Helper Functions

function isValidEmail(email) {
  if (email == null) return false;
  return email.Contains("@") && email.Contains(".");
}

function isValidPhone(phone) {
  if (phone == null) return false;
  return phone.Length >= 10;
}

function validateCustomer(customer) {
  if (!isValidEmail(customer.email)) {
    return false;
  }

  if (!isValidPhone(customer.phone)) {
    return false;
  }

  return true;
}

Pattern 6: Mapper Function

function mapPolicyToDTO(policy) {
  return {
    policyNumber: policy.number,
    customerName: policy.customer.firstName + " " + policy.customer.lastName,
    annualPremium: policy.premium * 12,
    status: policy.isActive ? "Active" : "Inactive",
  };
}

policies = getPolicies();
dtos = policies.Map((p) => mapPolicyToDTO(p));

Function Composition

Combine functions to create complex behavior:

function add10(x) {
  return x + 10;
}

function double(x) {
  return x * 2;
}

function square(x) {
  return x * x;
}

// Compose functions
result = square(double(add10(5))); // ((5 + 10) * 2)^2 = 900

// Or step by step
step1 = add10(5); // 15
step2 = double(step1); // 30
step3 = square(step2); // 900

Best Practices

1. Single Responsibility

Each function should do one thing:

// Less ideal: Does too much
function processPolicy(policy) {
  // Validates
  // Calculates premium
  // Saves to database
  // Sends email
}

// Better: Separate concerns
function validatePolicy(policy) {}
function calculatePremium(policy) {}
function savePolicy(policy) {}
function sendNotification(policy) {}

2. Keep Functions Small

Target ~20 lines or fewer:

// Less ideal: Large function
function processOrder(order) {
  // 50+ lines of logic
}

// Better: Break into smaller functions
function validateOrder(order) {}
function calculateTotal(order) {}
function applyDiscounts(order) {}
function finalizeOrder(order) {}

3. Use Descriptive Names

// Less clear
function calc(x, y) {}

// Clear
function calculateMonthlyPremium(coverage, age) {}

4. Minimize Side Effects

// Has side effect (modifies global)
function addToTotal(value) {
  globalTotal += value; // Modifies global
}

// Pure function (no side effects)
function calculateNewTotal(currentTotal, value) {
  return currentTotal + value;
}

5. Return Early

// Less readable
function validate(data) {
  valid = false;
  if (data != null) {
    if (data.value > 0) {
      if (data.name != "") {
        valid = true;
      }
    }
  }
  return valid;
}

// More readable
function validate(data) {
  if (data == null) return false;
  if (data.value <= 0) return false;
  if (data.name == "") return false;
  return true;
}

6. Document Complex Logic

function calculateAdjustedPremium(age, coverage, history) {
  // Base calculation uses industry standard rate of 0.001 per dollar
  basePremium = coverage * 0.001;

  // Age adjustment: 50% increase for under 25, 25% for over 65
  if (age < 25) {
    basePremium *= 1.5;
  } else if (age > 65) {
    basePremium *= 1.25;
  }

  // History adjustment: -20% for excellent, +30% for poor
  if (history == "excellent") {
    basePremium *= 0.8;
  } else if (history == "poor") {
    basePremium *= 1.3;
  }

  return $Round(basePremium, 2);
}

Common Mistakes

Mistake 1: Wrong Argument Count

function add(a, b) {
  return a + b;
}

// result = add(5);             // ERROR: Too few arguments
// result = add(5, 3, 1);       // ERROR: Too many arguments
result = add(5, 3); // OK

Mistake 2: Expecting Default Parameters

// ERROR: Default parameters not supported
// function greet(name = "Guest") {
//     return "Hello, " + name;
// }

// CORRECT: Handle manually
function greet(name) {
  if (name == null) {
    name = "Guest";
  }
  return "Hello, " + name;
}

Mistake 3: Modifying Parameters Without Intent

function process(value) {
  value = value * 2; // Modifies local copy only
  return value;
}

original = 10;
result = process(original); // 20
// original is still 10

Mistake 4: Infinite Recursion

// ERROR: Missing base case
// function loop(n) {
//     return loop(n);          // Infinite recursion!
// }

// CORRECT: Include base case
function countdown(n) {
  if (n <= 0) {
    return 0; // Base case
  }
  return countdown(n - 1);
}

Mistake 5: Forgetting Return

// ERROR: Forgot return
function add(a, b) {
  result = a + b; // Calculated but not returned
  // Missing: return result;
}

output = add(5, 3); // null (no return value)

// CORRECT
function add(a, b) {
  result = a + b;
  return result;
}

Advanced Examples

Example 1: Premium Calculator

function calculateInsurancePremium(policy) {
  basePremium = calculateBasePremium(policy.coverage);
  ageAdjustment = getAgeAdjustment(policy.customer.age);
  historyDiscount = getHistoryDiscount(policy.customer.yearsWithCompany);
  riskMultiplier = getRiskMultiplier(policy.riskCategory);

  adjustedPremium = basePremium * ageAdjustment * riskMultiplier;
  finalPremium = adjustedPremium - historyDiscount;

  return $Round(finalPremium, 2);
}

function calculateBasePremium(coverage) {
  return coverage * 0.001;
}

function getAgeAdjustment(age) {
  if (age < 25) return 1.5;
  if (age > 65) return 1.25;
  return 1.0;
}

function getHistoryDiscount(years) {
  if (years > 10) return 200;
  if (years > 5) return 100;
  return 0;
}

function getRiskMultiplier(category) {
  if (category == "high") return 1.3;
  if (category == "low") return 0.9;
  return 1.0;
}

Example 2: Data Validator

function validatePolicyData(policy) {
  errors = [];

  validateRequired(policy, "number", errors);
  validateRequired(policy, "customer", errors);
  validateRequired(policy, "coverage", errors);

  if (policy.coverage != null) {
    validatePositive(policy.coverage, "Coverage", errors);
  }

  if (policy.customer != null) {
    validateCustomer(policy.customer, errors);
  }

  return errors;
}

function validateRequired(obj, field, errors) {
  value = $GetValue(obj, field);
  if (value == null) {
    errors.Push(field + " is required");
  }
}

function validatePositive(value, name, errors) {
  if (value <= 0) {
    errors.Push(name + " must be positive");
  }
}

function validateCustomer(customer, errors) {
  if (customer.age < 18) {
    errors.Push("Customer must be 18 or older");
  }

  if (customer.email == null || !customer.email.Contains("@")) {
    errors.Push("Valid email required");
  }
}

Example 3: Object Transformation

function transformPolicyForExport(policy) {
  return {
    policyNumber: policy.number,
    customer: transformCustomer(policy.customer),
    coverage: formatCurrency(policy.coverage),
    premium: formatCurrency(policy.premium),
    status: getStatusText(policy.isActive),
    dates: {
      created: formatDate(policy.createdDate),
      expires: formatDate(policy.expirationDate),
    },
  };
}

function transformCustomer(customer) {
  return {
    fullName: customer.firstName + " " + customer.lastName,
    contact: customer.email,
    age: customer.age,
  };
}

function formatCurrency(amount) {
  return "$" + $ToString($Round(amount, 2));
}

function getStatusText(isActive) {
  return isActive ? "Active" : "Inactive";
}

function formatDate(date) {
  return (
    $ToString($Year(date)) + "-" + pad($Month(date)) + "-" + pad($Day(date))
  );
}

function pad(number) {
  return number < 10 ? "0" + $ToString(number) : $ToString(number);
}

Next Steps