Skip to content

Data Types

CacaoLang supports several core data types. Type inference means you don't need to explicitly declare types - the interpreter figures it out automatically.

Number

Numbers can be integers or floating-point values. There's no distinction between int and float at the language level.

let integer = 42;
let negative = -15;
let decimal = 3.14159;
let scientific = 2.5;

print typeof(integer);  // number
print typeof(decimal);  // number

Number Operations

let a = 10;
let b = 3;

print a + b;   // 13 (addition)
print a - b;   // 7 (subtraction)
print a * b;   // 30 (multiplication)
print a / b;   // 3.333... (division)
print a % b;   // 1 (modulo)

String

Strings are sequences of characters enclosed in double quotes.

let greeting = "Hello, World!";
let empty = "";
let multiword = "This is a longer string";

String Interpolation

Use #{} to embed expressions in strings:

let name = "Alice";
let age = 30;
let message = "My name is #{name} and I am #{age} years old";
print message;  // My name is Alice and I am 30 years old

Escape Sequences

let newline = "Line 1\nLine 2";
let tab = "Column1\tColumn2";
let quote = "She said \"Hello\"";
let backslash = "Path: C:\\Users\\Name";

String Operations

let str1 = "Hello";
let str2 = "World";

// Concatenation
let combined = str1 + " " + str2;
print combined;  // Hello World

// Length
print len(str1);  // 5

// Indexing
print str1[0];  // H
print str1[4];  // o

// Case conversion
print uppercase(str1);  // HELLO
print lowercase(str2);  // world

Boolean

Boolean values represent true or false.

let isActive = true;
let isComplete = false;

print typeof(isActive);  // bool

Boolean Operations

let a = true;
let b = false;

// Logical AND
print a && b;  // false

// Logical OR
print a || b;  // true

// Logical NOT
print !a;  // false
print !b;  // true

Truthiness

In conditional contexts:

  • Truthy: true, non-zero numbers, non-empty strings
  • Falsy: false, 0, empty strings ("")
if 1 {
    print "Numbers are truthy";
}

if "hello" {
    print "Non-empty strings are truthy";
}

Array

Arrays are ordered collections of values. They can contain mixed types.

let numbers = [1, 2, 3, 4, 5];
let strings = ["apple", "banana", "cherry"];
let mixed = [42, "hello", true, 3.14];
let nested = [[1, 2], [3, 4], [5, 6]];

print typeof(numbers);  // array

Array Operations

let arr = [10, 20, 30, 40, 50];

// Access by index (0-based)
print arr[0];  // 10
print arr[2];  // 30

// Length
print len(arr);  // 5

// Modify arrays (via functions)
arr = push(arr, 60);
print arr;  // [10, 20, 30, 40, 50, 60]

let last = pop(arr);
print last;  // 60

Array Iteration

let numbers = [1, 2, 3, 4, 5];

// Using indices
for i in 0..len(numbers) {
    print numbers[i];
}

Struct

Structs are user-defined composite types with named fields.

// Define a struct type
struct Person {
    name,
    age,
    city
}

// Create an instance
let alice = Person {
    name: "Alice",
    age: 30,
    city: "NYC"
};

print typeof(alice);  // Person

// Access fields
print alice.name;  // Alice
print alice.age;   // 30
print alice.city;  // NYC

Nested Structs

struct Address {
    street,
    city,
    zip
}

struct Person {
    name,
    address
}

let addr = Address {
    street: "123 Main St",
    city: "Boston",
    zip: "02101"
};

let person = Person {
    name: "Bob",
    address: addr
};

print person.address.city;  // Boston

Lambda

Lambdas are anonymous functions that can be stored in variables and passed as arguments.

let double = |x| => { return x * 2; };

print typeof(double);  // lambda

let result = double(5);
print result;  // 10

Lambda with Multiple Parameters

let add = |a, b| => { return a + b; };
print add(10, 20);  // 30

See Lambdas for more details.

Nil

Nil represents the absence of a value. Variables don't start as nil by default, but nil can be used explicitly.

fn maybe_return(condition) {
    if condition == true {
        return 42;
    }
    // Implicitly returns nil
}

let result = maybe_return(false);
print typeof(result);  // nil

Type Checking

Use typeof() to check the type of any value:

print typeof(42);          // number
print typeof("hello");     // string
print typeof(true);        // bool
print typeof([1, 2, 3]);   // array
print typeof(|x| => {});   // lambda

Type Conversion

To String

let num = 42;
let str = str(num);
print str;  // "42"
print typeof(str);  // string

To Number

let text = "123";
let num = int(text);
print num;  // 123

let floatText = "3.14";
let decimal = float(floatText);
print decimal;  // 3.14

Type Coercion

In Arithmetic

let result = 10 + 5.5;
print result;  // 15.5 (coerced to float)

In Concatenation

// String concatenation requires both sides to be strings
let text = "Number: ";
let num = 42;
let combined = text + str(num);
print combined;  // Number: 42

// Or use interpolation
let message = "Number: #{num}";
print message;  // Number: 42

Summary

Type Example Literal Syntax Mutable
Number 42, 3.14 Digits with optional decimal Yes (via reassignment)
String "hello" Double quotes No (immutable)
Boolean true, false Keywords Yes (via reassignment)
Array [1, 2, 3] Square brackets Yes (via functions)
Struct Person { ... } Struct literal No (fields immutable)
Lambda \|x\| => {} Pipe syntax No
Nil - Implicit/explicit -

Best Practices

  1. Use descriptive variable names that indicate type
  2. Leverage type inference - don't worry about explicit types
  3. Check types with typeof() when needed
  4. Convert explicitly when mixing types
  5. Use structs for related data that belongs together