Advanced Language Features
Now that we have a solid foundation, let's add powerful features that make Lux practical: enhanced list operations, string manipulation, advanced loop constructs, and more.
Lists in Depth
We already have basic lists. Let's explore their full capabilities.
List Creation
let empty = [];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, nil, [1, 2]]; // Heterogeneous
let nested = [[1, 2], [3, 4], [5, 6]];
List Indexing
let items = ["a", "b", "c", "d"];
print items[0]; // "a"
print items[3]; // "d"
print items[10]; // Error: List index 10 out of bounds
List Modification
let numbers = [1, 2, 3];
// Add elements
push(numbers, 4);
push(numbers, 5);
print numbers; // [1, 2, 3, 4, 5]
// Remove elements
let last = pop(numbers);
print last; // 5
print numbers; // [1, 2, 3, 4]
List Iteration
let fruits = ["apple", "banana", "cherry"];
for fruit in fruits {
print "I like " + fruit;
}
// Output:
// I like apple
// I like banana
// I like cherry
List Operations with Higher-Order Functions
// Map
fn map(list, f) {
let result = [];
for item in list {
push(result, f(item));
}
return result;
}
let numbers = [1, 2, 3, 4, 5];
let squares = map(numbers, fn(x) { return x * x; });
print squares; // [1, 4, 9, 16, 25]
// Filter
fn filter(list, predicate) {
let result = [];
for item in list {
if predicate(item) {
push(result, item);
}
}
return result;
}
let evens = filter(numbers, fn(x) { return x % 2 == 0; });
print evens; // [2, 4]
// Find
fn find(list, predicate) {
for item in list {
if predicate(item) {
return item;
}
}
return nil;
}
let first_big = find(numbers, fn(x) { return x > 3; });
print first_big; // 4
// Any/Some
fn any(list, predicate) {
for item in list {
if predicate(item) {
return true;
}
}
return false;
}
print any(numbers, fn(x) { return x > 10; }); // false
print any(numbers, fn(x) { return x > 3; }); // true
// All
fn all(list, predicate) {
for item in list {
if not predicate(item) {
return false;
}
}
return true;
}
print all(numbers, fn(x) { return x > 0; }); // true
print all(numbers, fn(x) { return x > 3; }); // false
List Building Patterns
// Range function (utility)
fn range(start, end) {
let result = [];
let i = start;
while i < end {
push(result, i);
i = i + 1;
}
return result;
}
let nums = range(0, 10);
print nums; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// List comprehension (manual)
fn comprehension(limit, transform, condition) {
let result = [];
let i = 0;
while i < limit {
if condition(i) {
push(result, transform(i));
}
i = i + 1;
}
return result;
}
let even_squares = comprehension(10,
fn(x) { return x * x; },
fn(x) { return x % 2 == 0; }
);
print even_squares; // [0, 4, 16, 36, 64]
String Operations
Strings in Lux are immutable sequences of characters.
String Concatenation
let first = "Hello";
let last = "World";
let full = first + ", " + last + "!";
print full; // "Hello, World!"
// Concatenate with numbers
let age = 30;
print "I am " + str(age) + " years old"; // "I am 30 years old"
String Indexing
let word = "Hello";
print word[0]; // "H"
print word[4]; // "o"
print word[5]; // Error: String index 5 out of bounds
String Length
let message = "Hello, World!";
print len(message); // 13
String Iteration
let word = "Lux";
let i = 0;
while i < len(word) {
print word[i];
i = i + 1;
}
// Output:
// L
// u
// x
String Building
fn join(list, separator) {
if len(list) == 0 {
return "";
}
let result = str(list[0]);
let i = 1;
while i < len(list) {
result = result + separator + str(list[i]);
i = i + 1;
}
return result;
}
let words = ["one", "two", "three"];
print join(words, ", "); // "one, two, three"
String Utilities
// Repeat string
fn repeat_string(s, n) {
let result = "";
let i = 0;
while i < n {
result = result + s;
i = i + 1;
}
return result;
}
print repeat_string("*", 5); // "*****"
// Reverse string
fn reverse_string(s) {
let result = "";
let i = len(s) - 1;
while i >= 0 {
result = result + s[i];
i = i - 1;
}
return result;
}
print reverse_string("Hello"); // "olleH"
// Check if string contains substring
fn contains(haystack, needle) {
let hay_len = len(haystack);
let needle_len = len(needle);
if needle_len > hay_len {
return false;
}
let i = 0;
while i <= hay_len - needle_len {
let match = true;
let j = 0;
while j < needle_len {
if haystack[i + j] != needle[j] {
match = false;
}
j = j + 1;
}
if match {
return true;
}
i = i + 1;
}
return false;
}
print contains("Hello, World!", "World"); // true
print contains("Hello, World!", "Goodbye"); // false
Enhanced For Loops
Our for loop already works with lists. Let's see more patterns.
Iterating with Index
fn for_each_with_index(list, action) {
let i = 0;
for item in list {
action(item, i);
i = i + 1;
}
}
let items = ["a", "b", "c"];
for_each_with_index(items, fn(item, idx) {
print str(idx) + ": " + item;
});
// Output:
// 0: a
// 1: b
// 2: c
Nested Iteration
let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
for row in matrix {
for cell in row {
print cell;
}
}
// Output: 1 2 3 4 5 6 7 8 9
Early Exit Pattern
fn find_in_nested(lists, target) {
for list in lists {
for item in list {
if item == target {
return true;
}
}
}
return false;
}
let data = [[1, 2], [3, 4], [5, 6]];
print find_in_nested(data, 4); // true
print find_in_nested(data, 7); // false
Practical Examples
Example 1: FizzBuzz
fn fizzbuzz(n) {
let i = 1;
while i <= n {
if i % 15 == 0 {
print "FizzBuzz";
} else if i % 3 == 0 {
print "Fizz";
} else if i % 5 == 0 {
print "Buzz";
} else {
print i;
}
i = i + 1;
}
}
fizzbuzz(15);
Example 2: Prime Numbers
fn is_prime(n) {
if n <= 1 {
return false;
}
if n == 2 {
return true;
}
if n % 2 == 0 {
return false;
}
let i = 3;
while i * i <= n {
if n % i == 0 {
return false;
}
i = i + 2;
}
return true;
}
fn primes_up_to(max) {
let result = [];
let n = 2;
while n <= max {
if is_prime(n) {
push(result, n);
}
n = n + 1;
}
return result;
}
print primes_up_to(50);
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
Example 3: Sorting (Bubble Sort)
fn bubble_sort(list) {
let n = len(list);
let swapped = true;
while swapped {
swapped = false;
let i = 1;
while i < n {
if list[i - 1] > list[i] {
// Swap (requires list indexing assignment - not yet implemented)
// For now, we'd need to rebuild the list
swapped = true;
}
i = i + 1;
}
}
return list;
}
// Note: Without index assignment (list[i] = value), we can't modify lists in place
// This would require extending our language - see "What's Next" section
Example 4: Word Count
fn word_count(text) {
// Split on spaces (simplified)
let words = [];
let current = "";
let i = 0;
while i < len(text) {
let char = text[i];
if char == " " {
if len(current) > 0 {
push(words, current);
current = "";
}
} else {
current = current + char;
}
i = i + 1;
}
if len(current) > 0 {
push(words, current);
}
return len(words);
}
print word_count("The quick brown fox jumps"); // 5
Example 5: Calculator
fn calculate() {
print "Simple Calculator";
print "Enter first number:";
let a = num(input(""));
print "Enter operator (+, -, *, /):";
let op = input("");
print "Enter second number:";
let b = num(input(""));
if op == "+" {
print "Result: " + str(a + b);
} else if op == "-" {
print "Result: " + str(a - b);
} else if op == "*" {
print "Result: " + str(a * b);
} else if op == "/" {
if b == 0 {
print "Error: Division by zero";
} else {
print "Result: " + str(a / b);
}
} else {
print "Error: Unknown operator";
}
}
// Uncomment to run:
// calculate();
Type Checking Utilities
fn is_number(value) {
return type(value) == "number";
}
fn is_string(value) {
return type(value) == "string";
}
fn is_bool(value) {
return type(value) == "bool";
}
fn is_list(value) {
return type(value) == "list";
}
fn is_function(value) {
return type(value) == "function";
}
fn is_nil(value) {
return type(value) == "nil";
}
// Usage
print is_number(42); // true
print is_string("hello"); // true
print is_list([1, 2, 3]); // true
Standard Library Pattern
Build a "standard library" of utilities:
// math.lux
fn max(a, b) {
if a > b {
return a;
}
return b;
}
fn min(a, b) {
if a < b {
return a;
}
return b;
}
fn abs(n) {
if n < 0 {
return -n;
}
return n;
}
fn clamp(value, low, high) {
return min(high, max(low, value));
}
print clamp(5, 0, 10); // 5
print clamp(-5, 0, 10); // 0
print clamp(15, 0, 10); // 10
Features Not Yet Implemented
Some features would require language extensions:
1. List Index Assignment
// Desired:
let list = [1, 2, 3];
list[0] = 10; // Not yet supported
// Workaround: rebuild list
fn set_index(list, index, value) {
let result = [];
let i = 0;
while i < len(list) {
if i == index {
push(result, value);
} else {
push(result, list[i]);
}
i = i + 1;
}
return result;
}
2. String Slicing
// Desired:
let word = "Hello";
print word[1:4]; // "ell"
// Workaround: manual extraction
fn slice_string(s, start, end) {
let result = "";
let i = start;
while i < end and i < len(s) {
result = result + s[i];
i = i + 1;
}
return result;
}
3. Break and Continue
// Desired:
while true {
let x = num(input("Enter number: "));
if x == 0 {
break; // Not yet supported
}
print x * 2;
}
// Workaround: use flags
let running = true;
while running {
let x = num(input("Enter number: "));
if x == 0 {
running = false;
} else {
print x * 2;
}
}
These features are implemented in Chapter 10 "What's Next".
Performance Tips
1. Avoid Rebuilding Strings in Loops
// ❌ Slow: creates new string each iteration
let result = "";
let i = 0;
while i < 1000 {
result = result + "x"; // Creates new string 1000 times
i = i + 1;
}
// ✅ Better: use list then join (if you had join as native function)
let parts = [];
let i = 0;
while i < 1000 {
push(parts, "x"); // Just adds to list
i = i + 1;
}
// Then join would combine efficiently
2. Minimize Closure Allocations
// ❌ Creates closure every call
fn process_items(items) {
for item in items {
apply(item, fn(x) { return x * 2; }); // New closure each iteration
}
}
// ✅ Define closure once
fn process_items(items) {
fn double(x) { return x * 2; }
for item in items {
apply(item, double); // Reuse same function
}
}
Summary
Lux now supports:
| Feature | Description |
|---|---|
| Lists | Dynamic arrays with push/pop |
| List iteration | For loops over lists |
| List operations | Map, filter, reduce via functions |
| Strings | Immutable character sequences |
| String concatenation | + operator |
| String indexing | str[i] |
| Type checking | type() function |
| User input | input() function |
What's Next?
We have a powerful language! But error messages could be better. Let's add comprehensive error handling.
→ Continue to Chapter 7: Error Handling