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",
};

// 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.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.AddProperty("name", obj.name);
  copy.AddProperty("age", obj.age);
  return copy;
}

Checking for Properties

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

// Check if property exists
name = $GetValue(object, "name");
hasName = name != null; // true

email = $GetValue(object, "email");
hasEmail = email != 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.AddProperty("firstName", firstName);
  customer.AddProperty("lastName", lastName);
  customer.AddProperty("age", age);
  customer.AddProperty("email", email);
  customer.AddProperty("createdDate", $Today());
  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: "$" + $ToString(policy.coverage),
    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.AddProperty("name", obj1.name);
  result.AddProperty("age", obj1.age);

  // Copy from obj2
  result.AddProperty("email", obj2.email);
  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.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, 0);

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

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

  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