Skip to content

Objects

Objects are dynamic collections of key-value pairs. They store structured data and can be created, modified, and accessed at runtime.


Object Creation

Object Literal Syntax

object = {
  "key1": value1,
  "key2": value2,
  "key3": value3
};

Example:

customer = {
  "firstName": "John",
  "lastName": "Doe",
  "age": 35,
  "email": "john.doe@example.com"
};

Empty Object

empty = {};

Keys Must Be Strings

// CORRECT: String keys
object = {
  "name": "Alice",
  "age": 30,
  "123": "numeric string key" // numeric-looking keys are quoted too
};

// ERROR: Keys without quotes
// object = {
//     name: "Alice",              // ERROR
//     age: 30                      // ERROR
// };

Values Can Be Any Type

mixed = {
  "string": "text",
  "number": 42,
  "boolean": true,
  "null": null,
  "date": $Now(),
  "array": [1, 2, 3],
  "object": {
    "nested": "value"
  }
};

Property Access

Dot Notation

object = {
  "name": "Alice",
  "age": 30
};

name = object.name; // "Alice"
age = object.age; // 30

Accessing Nested Properties

person = {
  "name": "Alice",
  "address": {
    "street": "123 Main St",
    "city": "Springfield",
    "zip": "12345"
  }
};

city = person.address.city; // "Springfield"
zip = person.address.zip; // "12345"

Accessing Non-Existent Properties

Returns null:

object = { "name": "Alice" };

value = object.age; // null (doesn't exist)
nested = object.address.city; // ERROR: Cannot access property of null

Safe access:

if (object.address != null) {
  city = object.address.city;
}

Dynamic Property Access

Using $GetValue

Get property value by name:

object = {
  "firstName": "John",
  "lastName": "Doe"
};

propertyName = "firstName";
value = $GetValue(object, propertyName); // "John"

Nested Property Access

person = {
  "name": "Alice",
  "contact": {
    "email": "alice@example.com"
  }
};

// Nested access with dot notation
email = $GetValue(person, "contact.email"); // "alice@example.com"

Using $SetValue

Set property value by name:

object = {
  "name": "Alice"
};

$SetValue(object, "age", 30);

age = object.age; // 30

Creating New Properties Dynamically

policy = {};

$SetValue(policy, "number", "POL-001");
$SetValue(policy, "premium", 1200);
$SetValue(policy, "coverage", 250000);

// policy is now:
// {
//     "number": "POL-001",
//     "premium": 1200,
//     "coverage": 250000
// }

Modifying Objects

Adding Properties

Using .AddProperty()

customer = {
  "firstName": "John",
  "lastName": "Doe"
};

customer = customer.AddProperty("email", "john@example.com");

email = customer.email; // "john@example.com"

Direct Assignment

object = {};

object.name = "Alice"; // ERROR: Cannot assign via dot notation
// Use .AddProperty() or $SetValue() instead

Note: EverSharp does not support property assignment via dot notation. Use .AddProperty() or $SetValue().

Updating Properties

customer = {
  "name": "Alice",
  "age": 30
};

// Update using $SetValue
$SetValue(customer, "age", 31);

age = customer.age; // 31

Removing Properties

EverSharp does not have a built-in way to remove properties. Workaround:

// Create new object without unwanted property
original = {
  "name": "Alice",
  "age": 30,
  "temp": "remove this"
};

// Manual copy without 'temp'
filtered = {
  "name": original.name,
  "age": original.age
};

Working with Objects

Copying Objects

Objects are reference types. Assignment creates a reference, not a copy:

original = {
  "name": "Alice",
  "age": 30
};

reference = original;
$SetValue(reference, "age", 31);

age1 = original.age; // 31 (modified)
age2 = reference.age; // 31 (same object)

Shallow copy:

function shallowCopy(obj) {
  copy = {};
  // Manually copy each property
  copy = copy.AddProperty("name", obj.name);
  copy = copy.AddProperty("age", obj.age);
  return copy;
}

Checking for Properties

object = {
  "name": "Alice",
  "age": 30,
  "email": null
};

// Check whether a property key exists
hasName = object.HasProperty("name"); // true
hasAge = $HasProperty(object, "age"); // true
hasEmail = object.HasProperty("email"); // true
hasPhone = $HasProperty(object, "phone"); // false

// If you need to know whether the stored value is non-null, check the value explicitly
emailValue = $GetValue(object, "email");
hasNonNullEmail = emailValue != null; // false

Iterating Over Properties

EverSharp doesn't have built-in property iteration. Properties must be accessed by known names.


Nested Objects

Creating Nested Structures

policy = {
  "number": "POL-001",
  "premium": 1200,
  "customer": {
    "firstName": "John",
    "lastName": "Doe",
    "age": 35,
    "address": {
      "street": "123 Main St",
      "city": "Springfield",
      "state": "IL",
      "zip": "62701"
    }
  },
  "coverage": {
    "amount": 250000,
    "type": "Term Life",
    "years": 20
  }
};

Accessing Nested Data

customerName = policy.customer.firstName + " " + policy.customer.lastName;
city = policy.customer.address.city;
coverageType = policy.coverage.type;

Safe Nested Access

// Unsafe: Will error if intermediate property is null
// city = policy.customer.address.city;

// Safe: Check each level
if (policy != null && policy.customer != null && policy.customer.address != null) {
  city = policy.customer.address.city;
}

Modifying Nested Properties

policy = {
  "number": "POL-001",
  "customer": {
    "name": "Alice"
  }
};

// Update nested property
$SetValue(policy.customer, "age", 30);

age = policy.customer.age; // 30

Objects in Arrays

Array of Objects

customers = [
  { "name": "Alice", "age": 30 },
  { "name": "Bob", "age": 25 },
  { "name": "Charlie", "age": 35 }
];

// Access by index
firstCustomer = customers[0];
name = firstCustomer.name; // "Alice"

// Or combined
name = customers[0].name; // "Alice"

Filtering Objects

customers = [
  { "name": "Alice", "age": 30, "isActive": true },
  { "name": "Bob", "age": 25, "isActive": false },
  { "name": "Charlie", "age": 35, "isActive": true }
];

// Get active customers
active = customers.Filter((c) => c.isActive);

// Get customers over 30
over30 = customers.Filter((c) => c.age > 30);

Mapping Objects

// Extract property
names = customers.Map((c) => c.name);
// ["Alice", "Bob", "Charlie"]

// Transform objects
simplified = customers.Map((c) => {
  return {
    "name": c.name,
    "status": c.isActive ? "Active" : "Inactive"
  };
});

Sorting Objects

// Sort by age
sortedByAge = customers.OrderBy((c) => c.age);

// Sort by name (descending)
sortedByName = customers.OrderByDescending((c) => c.name);

Common Patterns

Pattern 1: Object Builder

function createCustomer(firstName, lastName, age, email) {
  customer = {};
  customer = customer.AddProperty("firstName", firstName);
  customer = customer.AddProperty("lastName", lastName);
  customer = customer.AddProperty("age", age);
  customer = customer.AddProperty("email", email);
  customer = customer.AddProperty("createdDate", $Today());
  customer = customer.AddProperty("isActive", true);
  return customer;
}

customer = createCustomer("John", "Doe", 35, "john@example.com");

Pattern 2: Object Validation

function validateCustomer(customer) {
  errors = [];

  if (customer == null) {
    errors.Push("Customer is null");
    return errors;
  }

  if (customer.firstName == null || customer.firstName == "") {
    errors.Push("First name required");
  }

  if (customer.age == null || customer.age < 18) {
    errors.Push("Must be 18 or older");
  }

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

  return errors;
}

Pattern 3: Object Transformation

function transformPolicyForExport(policy) {
  return {
    "policyNumber": policy.number,
    "customerName": policy.customer.firstName + " " + policy.customer.lastName,
    "monthlyPremium": $Round(policy.premium / 12, 2),
    "coverageAmount": "$" + policy.coverage.ToString(),
    "status": policy.isActive ? "Active" : "Inactive"
  };
}

policies = getPolicies();
exports = policies.Map((p) => transformPolicyForExport(p));

Pattern 4: Merging Objects

function merge(obj1, obj2) {
  result = {};

  // Copy from obj1 (manually, property by property)
  result = result.AddProperty("name", obj1.name);
  result = result.AddProperty("age", obj1.age);

  // Copy from obj2
  result = result.AddProperty("email", obj2.email);
  result = result.AddProperty("phone", obj2.phone);

  return result;
}

// Or use object literal
function merge(obj1, obj2) {
  return {
    "name": obj1.name,
    "age": obj1.age,
    "email": obj2.email,
    "phone": obj2.phone
  };
}

Pattern 5: Default Values

function getCustomerEmail(customer) {
  if (customer == null) {
    return null;
  }

  email = customer.email;

  if (email == null || email == "") {
    return "no-email@example.com";
  }

  return email;
}

// Or using ternary
function getCustomerEmail(customer) {
  return customer != null && customer.email != null && customer.email != "" ? customer.email : "no-email@example.com";
}

Pattern 6: Nested Object Creation

function createPolicy(number, premium, customerData, coverageData) {
  return {
    "number": number,
    "premium": premium,
    "isActive": true,
    "createdDate": $Today(),
    "customer": {
      "firstName": customerData.firstName,
      "lastName": customerData.lastName,
      "age": customerData.age,
      "contact": {
        "email": customerData.email,
        "phone": customerData.phone
      }
    },
    "coverage": {
      "amount": coverageData.amount,
      "type": coverageData.type,
      "term": coverageData.term
    }
  };
}

Objects as Function Returns

Returning Single Object

function createResult(success, message) {
  return {
    "success": success,
    "message": message,
    "timestamp": $Now()
  };
}

result = createResult(true, "Operation completed");

if (result.success) {
  $Log(result.message);
}

Returning Multiple Values

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

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

  monthlyPremium = basePremium / 12;

  return {
    "annual": $Round(basePremium, 2),
    "monthly": $Round(monthlyPremium, 2),
    "ageCategory": age < 25 ? "young" : (age > 65 ? "senior" : "standard")
  };
}

premium = calculatePremium(250000, 30);
annual = premium.annual;
monthly = premium.monthly;

Error Handling Pattern

function processPayment(amount) {
  if (amount <= 0) {
    return {
      "success": false,
      "error": "Invalid amount",
      "errorCode": "INVALID_AMOUNT"
    };
  }

  // Process payment
  transactionId = generateTransactionId();

  return {
    "success": true,
    "transactionId": transactionId,
    "processedAmount": amount,
    "timestamp": $Now()
  };
}

result = processPayment(100);

if (result.success) {
  $Log("Payment successful: " + result.transactionId);
} else {
  $Log("Error: " + result.error);
}

Best Practices

1. Use Descriptive Property Names

// Less clear
obj = { "p": 1200, "c": 250000 };

// Clear
policy = { "premium": 1200, "coverage": 250000 };
// Less organized
customer = {
  "name": "John",
  "street": "123 Main",
  "city": "Springfield",
  "email": "john@example.com"
};

// Better organized
customer = {
  "name": "John",
  "address": {
    "street": "123 Main",
    "city": "Springfield"
  },
  "contact": {
    "email": "john@example.com"
  }
};

3. Check for Null Before Access

// Unsafe
city = policy.customer.address.city;

// Safe
if (policy != null && policy.customer != null && policy.customer.address != null) {
  city = policy.customer.address.city;
}

4. Use Consistent Structure

// Consistent object structure
function createResponse(success, data, error) {
  return {
    "success": success,
    "data": data,
    "error": error,
    "timestamp": $Now()
  };
}

// Always same structure
successResult = createResponse(true, { "id": 123 }, null);
errorResult = createResponse(false, null, "Not found");

5. Validate Object Structure

function isValidCustomer(obj) {
  if (obj == null) return false;
  if (obj.firstName == null) return false;
  if (obj.lastName == null) return false;
  if (obj.age == null) return false;
  return true;
}

if (isValidCustomer(customer)) {
  // Safe to use
}

Common Mistakes

Mistake 1: Assuming Property Assignment Works

object = { "name": "Alice" };

// ERROR: Cannot assign property this way
// object.age = 30;

// CORRECT: Use .AddProperty() or $SetValue()
object = object.AddProperty("age", 30);
// Or
$SetValue(object, "age", 30);

Mistake 2: Not Checking for Null

// ERROR: If customer is null, this fails
name = customer.firstName;

// CORRECT
if (customer != null) {
  name = customer.firstName;
}

Mistake 3: Using Unquoted Keys

// ERROR: Keys must be strings
// object = { name: "Alice" };

// CORRECT
object = { "name": "Alice" };

Mistake 4: Expecting Shallow Copy on Assignment

original = { "name": "Alice" };
copy = original; // Reference, not copy!

$SetValue(copy, "name", "Bob");

name = original.name; // "Bob" (same object)

Mistake 5: Accessing Missing Nested Properties

customer = { "name": "Alice" };

// ERROR: address is null
// city = customer.address.city;

// CORRECT
if (customer.address != null) {
  city = customer.address.city;
}

Advanced Examples

Example 1: Complex Data Structure

policy = {
  "number": "POL-001",
  "status": "active",
  "dates": {
    "issued": $ToDate("2024-01-01"),
    "effective": $ToDate("2024-01-15"),
    "expires": $ToDate("2025-01-15")
  },
  "customer": {
    "id": "CUST-123",
    "personal": {
      "firstName": "John",
      "lastName": "Doe",
      "birthDate": $ToDate("1988-05-15"),
      "ssn": "***-**-1234"
    },
    "contact": {
      "email": "john.doe@example.com",
      "phone": "(555) 123-4567",
      "address": {
        "street": "123 Main Street",
        "city": "Springfield",
        "state": "IL",
        "zip": "62701"
      }
    }
  },
  "coverage": {
    "type": "Term Life",
    "amount": 250000,
    "term": 20,
    "beneficiaries": [{ "name": "Jane Doe", "relationship": "Spouse", "percentage": 100 }]
  },
  "premium": {
    "annual": 1200,
    "frequency": "monthly",
    "nextDue": $ToDate("2024-02-15")
  }
};

Example 2: Data Aggregation

function aggregateSales(orders) {
  result = {
    "totalOrders": orders.Length,
    "totalRevenue": 0,
    "averageOrderValue": 0,
    "largestOrder": 0,
    "byCategory": {}
  };

  // Calculate totals
  result.totalRevenue = orders.ReduceToNum((acc, o) => acc + o.total);

  result.averageOrderValue = $Round(result.totalRevenue / result.totalOrders, 2);

  result.largestOrder = orders.ReduceToNum((acc, o) => (o.total > acc ? o.total : acc));

  return result;
}

Example 3: Configuration Object

config = {
  "pricing": {
    "baseRate": 0.001,
    "ageFactors": {
      "under25": 1.5,
      "standard": 1.0,
      "over65": 1.25
    },
    "riskFactors": {
      "low": 0.9,
      "standard": 1.0,
      "high": 1.3
    }
  },
  "limits": {
    "minCoverage": 50000,
    "maxCoverage": 1000000,
    "minAge": 18,
    "maxAge": 75
  },
  "discounts": {
    "loyaltyYears": [
      { "years": 5, "discount": 0.05 },
      { "years": 10, "discount": 0.1 },
      { "years": 15, "discount": 0.15 }
    ]
  }
};

function calculatePremium(coverage, age, risk, years) {
  baseRate = config.pricing.baseRate;

  ageFactor =
    age < 25
      ? config.pricing.ageFactors.under25
      : (age > 65
        ? config.pricing.ageFactors.over65
        : config.pricing.ageFactors.standard);

  riskFactor = $GetValue(config.pricing.riskFactors, risk);

  premium = coverage * baseRate * ageFactor * riskFactor;

  return $Round(premium, 2);
}

Next Steps