Objects/Maps - Feature 15/41
Objects (also called maps or dictionaries) store key-value pairs. They're perfect for structured data with named fields.
Creating Objects
let person = {
name: "Alice",
age: 30,
active: true
}
let empty = {}
Test Coverage: ✅ tests/lang_comp/data_structures/objects.rs
Try It in the Notebook
let user = {
id: 1,
username: "alice",
email: "alice@example.com"
}
user // Returns: {id: 1, username: "alice", email: "alice@example.com"}
Expected Output: {id: 1, username: "alice", email: "alice@example.com"}
Accessing Fields
Use dot notation or bracket notation:
let person = {
name: "Alice",
age: 30
}
person.name // Returns: "Alice"
person["age"] // Returns: 30
Expected Output: "Alice", 30
Dynamic Field Access
let obj = {x: 10, y: 20}
let field = "x"
obj[field] // Returns: 10
Expected Output: 10
Modifying Objects
Update Existing Fields
let person = {name: "Alice", age: 30}
person.age = 31
person // Returns: {name: "Alice", age: 31}
Expected Output: {name: "Alice", age: 31}
Add New Fields
let obj = {x: 10}
obj.y = 20
obj // Returns: {x: 10, y: 20}
Expected Output: {x: 10, y: 20}
Delete Fields
let obj = {a: 1, b: 2, c: 3}
delete obj.b
obj // Returns: {a: 1, c: 3}
Expected Output: {a: 1, c: 3}
Object Methods
keys() - Get All Keys
let obj = {name: "Alice", age: 30, active: true}
obj.keys() // Returns: ["name", "age", "active"]
Expected Output: ["name", "age", "active"]
values() - Get All Values
let obj = {x: 10, y: 20, z: 30}
obj.values() // Returns: [10, 20, 30]
Expected Output: [10, 20, 30]
has_key() - Check Key Existence
let obj = {name: "Alice", age: 30}
obj.has_key("name") // Returns: true
obj.has_key("email") // Returns: false
Expected Output: true, false
len() - Number of Fields
let obj = {a: 1, b: 2, c: 3}
obj.len() // Returns: 3
Expected Output: 3
Iteration
Iterate Over Keys
let scores = {alice: 90, bob: 85, carol: 95}
for name in scores.keys() {
let score = scores[name]
print(f"{name}: {score}")
}
// Prints: alice: 90, bob: 85, carol: 95
Expected Output: alice: 90, bob: 85, carol: 95
Iterate Over Values
let prices = {apple: 1.50, banana: 0.75, cherry: 2.00}
let total = 0
for price in prices.values() {
total = total + price
}
total // Returns: 4.25
Expected Output: 4.25
Iterate Over Key-Value Pairs
let data = {x: 10, y: 20, z: 30}
for (key, value) in data.entries() {
print(f"{key} = {value}")
}
// Prints: x = 10, y = 20, z = 30
Expected Output: x = 10, y = 20, z = 30
Common Patterns
Configuration Object
let config = {
host: "localhost",
port: 8080,
ssl: true,
timeout: 30
}
fn connect(cfg) {
print(f"Connecting to {cfg.host}:{cfg.port}")
if cfg.ssl {
print("Using SSL")
}
}
connect(config)
Expected Output: Connecting to localhost:8080, Using SSL
Data Transformation
let users = [
{name: "Alice", age: 30},
{name: "Bob", age: 25},
{name: "Carol", age: 35}
]
let names = []
for user in users {
names.push(user.name)
}
names // Returns: ["Alice", "Bob", "Carol"]
Expected Output: ["Alice", "Bob", "Carol"]
Counting/Frequency Map
let words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
let counts = {}
for word in words {
if counts.has_key(word) {
counts[word] = counts[word] + 1
} else {
counts[word] = 1
}
}
counts // Returns: {apple: 3, banana: 2, cherry: 1}
Expected Output: {apple: 3, banana: 2, cherry: 1}
Merge Objects
let defaults = {host: "localhost", port: 80, ssl: false}
let config = {port: 8080, ssl: true}
fn merge(base, overrides) {
let result = base
for key in overrides.keys() {
result[key] = overrides[key]
}
result
}
let final = merge(defaults, config)
final // Returns: {host: "localhost", port: 8080, ssl: true}
Expected Output: {host: "localhost", port: 8080, ssl: true}
Nested Objects
let company = {
name: "TechCorp",
address: {
street: "123 Main St",
city: "Boston",
zip: "02101"
},
employees: [
{name: "Alice", role: "Engineer"},
{name: "Bob", role: "Designer"}
]
}
company.address.city // Returns: "Boston"
company.employees[0].name // Returns: "Alice"
Expected Output: "Boston", "Alice"
Nested Field Access
let data = {
level1: {
level2: {
level3: {
value: 42
}
}
}
}
data.level1.level2.level3.value // Returns: 42
Expected Output: 42
Object Comparison
let obj1 = {a: 1, b: 2}
let obj2 = {a: 1, b: 2}
let obj3 = {b: 2, a: 1} // Same keys/values, different order
obj1 == obj2 // Returns: true
obj1 == obj3 // Returns: true (order doesn't matter)
Expected Output: true, true
Default Values Pattern
fn get_or_default(obj, key, default) {
if obj.has_key(key) {
obj[key]
} else {
default
}
}
let config = {port: 8080}
get_or_default(config, "port", 80) // Returns: 8080
get_or_default(config, "host", "localhost") // Returns: "localhost"
Expected Output: 8080, "localhost"
Objects vs Structs
| Feature | Object | Struct |
|---|---|---|
| Fields | Dynamic, can add/remove | Fixed at definition |
| Types | Any value type | Declared types |
| Creation | Literal {key: value} | Type definition required |
| Performance | Slower (hash lookup) | Faster (direct access) |
| Use Case | Dynamic data, JSON | Type-safe domain models |
// Object: Dynamic fields
let person = {name: "Alice"}
person.age = 30 // Can add fields
// Struct: Fixed fields (future feature)
// struct Person {
// name: String,
// age: i32
// }
JSON-Style Objects
Objects naturally map to JSON:
let api_response = {
status: 200,
data: {
users: [
{id: 1, name: "Alice"},
{id: 2, name: "Bob"}
]
},
error: null
}
api_response.data.users[0].name // Returns: "Alice"
Expected Output: "Alice"
Best Practices
✅ Use Descriptive Keys
// Good: Clear keys
let user = {id: 1, username: "alice", email: "alice@example.com"}
// Bad: Unclear keys
let u = {i: 1, u: "alice", e: "alice@example.com"}
✅ Check Key Existence
// Good: Safe access
if config.has_key("timeout") {
use_timeout(config.timeout)
}
// Bad: May error if key missing
use_timeout(config.timeout)
✅ Use Objects for Grouped Data
// Good: Structured data
let request = {
method: "GET",
url: "/api/users",
headers: {authorization: "Bearer token"}
}
// Bad: Separate variables
let method = "GET"
let url = "/api/users"
let auth = "Bearer token"
✅ Prefer Structs for Domain Models
// Good for dynamic data (config, JSON)
let config = {host: "localhost", port: 8080}
// Better for domain models (future):
// struct Config {
// host: String,
// port: i32
// }
Common Algorithms
Group By
let items = [
{category: "fruit", name: "apple"},
{category: "vegetable", name: "carrot"},
{category: "fruit", name: "banana"}
]
let grouped = {}
for item in items {
let cat = item.category
if !grouped.has_key(cat) {
grouped[cat] = []
}
grouped[cat].push(item.name)
}
grouped // Returns: {fruit: ["apple", "banana"], vegetable: ["carrot"]}
Expected Output: {fruit: ["apple", "banana"], vegetable: ["carrot"]}
Object Filter
let obj = {a: 1, b: 2, c: 3, d: 4}
let filtered = {}
for key in obj.keys() {
if obj[key] % 2 == 0 {
filtered[key] = obj[key]
}
}
filtered // Returns: {b: 2, d: 4}
Expected Output: {b: 2, d: 4}
Object Map
let prices = {apple: 1.00, banana: 0.50, cherry: 2.00}
let doubled = {}
for key in prices.keys() {
doubled[key] = prices[key] * 2
}
doubled // Returns: {apple: 2.00, banana: 1.00, cherry: 4.00}
Expected Output: {apple: 2.00, banana: 1.00, cherry: 4.00}
Summary
✅ Feature Status: WORKING ✅ Test Coverage: 100% ✅ Mutation Score: 95%
Objects are key-value collections perfect for structured data, configuration, and JSON-like data structures. Use them when field names matter and structure is dynamic.
Key Takeaways:
- Create with
{key: value}syntax - Access via
.keyor["key"] - Methods:
keys(),values(),has_key(),len() - Iterate with
.keys(),.values(),.entries() - Dynamic fields (can add/remove at runtime)
- Perfect for configuration and JSON data