Skip to content

Tuples

Tuples are ordered, immutable collections of elements that can be of different types. In Harneet, tuples are primarily used for multiple return values from functions.

Overview

Tuples in Harneet: - Immutable - cannot be modified after creation - Heterogeneous - can contain elements of different types - Function returns - primary use case is multiple return values - Destructuring - can be unpacked into multiple variables - Method-rich - built-in .length() and .toArray() methods - Indexable - elements can be accessed by zero-based index

Tuple Creation

Tuples in Harneet are created implicitly by functions that return multiple values:

Tuple from Function Returns
1
2
3
4
5
6
7
8
9
package main

// Function that returns multiple values (creates a tuple)
function getUserInfo() (string, int, bool) {
    return "Alice", 30, true
}

// Tuple is created when not immediately destructured
var userTuple = getUserInfo()  // Tuple: ("Alice", 30, true)

Tuple Destructuring

The most common way to work with tuples is to destructure them:

Tuple Destructuring
1
2
3
4
5
6
7
8
9
package main

func getUserInfo() (string, int, bool) {
    return "Alice", 30, true
}

// Destructure into individual variables
var name, age, isActive = getUserInfo()
// name = "Alice", age = 30, isActive = true

Tuple Instance Methods

length()

Returns the number of elements in the tuple:

length()
1
2
3
4
5
6
7
8
package main

function getCoordinates() (int, int, int) {
    return 10, 20, 30
}

var coords = getCoordinates()
var len = coords.length()  // 3

toArray()

Converts the tuple to an array:

toArray()
package main

function getValues() (int, string, bool) {
    return 42, "hello", true
}

var tuple = getValues()
var arr = tuple.toArray()  // [42, "hello", true]

// Now you can use array methods
var arrLen = len(arr)  // 3
var first = arr[0]     // 42

Tuple Indexing

Tuples can be accessed by zero-based index:

Tuple Indexing
package main

function getColors() (string, string, string) {
    return "red", "green", "blue"
}

var colors = getColors()
var first = colors[0]   // "red"
var second = colors[1]  // "green"
var third = colors[2]   // "blue"

Common Tuple Patterns

Error Handling

Many functions return tuples with (result, error):

Error Handling with Tuples
package main

var arr = [1, 2, 3]

// pop() returns (value, error)
var value, err = arr.pop()
if err == None {
    fmt.Println("Popped value:", value)
} else {
    fmt.Println("Error:", err)
}

// Can also capture the tuple
var result = arr.pop()
var resultLen = result.length()  // 2 (value and error)

Multiple Return Values

Functions can return any number of values:

Multiple Return Values
package main

function getDimensions() (int, int, int) {
    return 100, 50, 25  // width, height, depth
}

// Destructure
var width, height, depth = getDimensions()

// Or keep as tuple
var dimensions = getDimensions()
var dimArray = dimensions.toArray()

None-Receiver Safety

Tuple instance methods enforce None-receiver safety:

None-Receiver Safety
1
2
3
4
5
6
package main
var t tuple = None

// These will raise runtime errors:
// t.length()   // ERROR: type null does not have method 'length'
// t.toArray()  // ERROR: type null does not have method 'toArray'

Working with Tuple Methods

Converting to Array for Processing

Convert to Array
package main

func getScores() (int, int, int, int) {
    return 95, 87, 92, 88
}

var scoresTuple = getScores()
var scoresArray = scoresTuple.toArray()

// Now use array methods
var total = 0
for score in scoresArray {
    total = total + score
}
var average = total / len(scoresArray)

Iterating Over Tuple Elements

Iterate Tuple
package main

func getData() (string, int, bool) {
    return "test", 42, true
}

var dataTuple = getData()
var dataArray = dataTuple.toArray()

for i, elem in dataArray {
    fmt.Printf("Element %d: %v\n", i, elem)
}
// Output:
// Element 0: test
// Element 1: 42
// Element 2: true

Complete Example

Complete Example
package main
import fmt

// Array methods return tuples for error handling
var numbers = [10, 20, 30, 40, 50]

// pop() returns a tuple (value, error)
var popResult = numbers.pop()
fmt.Println("Pop tuple length:", popResult.length())  // 2

// Destructure the tuple
var poppedValue, popErr = numbers.pop()
if popErr == None {
    fmt.Println("Popped:", poppedValue)  // 40
}

// shift() also returns a tuple
var shiftResult = numbers.shift()
var shiftArray = shiftResult.toArray()
fmt.Println("Shift result as array:", shiftArray)  // [10, None]

// Destructure shift result
var shiftedValue, shiftErr = numbers.shift()
if shiftErr == None {
    fmt.Println("Shifted:", shiftedValue)  // 20
}

fmt.Println("Remaining array:", numbers)  // [30]

Use Cases

Safe Array Operations

Safe Array Operations
package main

var stack = [1, 2, 3]

// Pop with error checking
var value, err = stack.pop()
if err != None {
    fmt.Println("Error: stack is empty")
} else {
    fmt.Println("Value:", value)
}

Multi-Value Configuration

Multi-Value Configuration
1
2
3
4
5
6
7
8
package main

function getServerConfig() (string, int, bool) {
    return "localhost", 8080, true
}

var host, port, useSSL = getServerConfig()
fmt.Printf("Server: %s:%d (SSL: %v)\n", host, port, useSSL)

Batch Processing Results

Batch Processing
package main

function processItem(id int) (string, bool, int) {
    // Returns (status, success, processingTime)
    return "completed", true, 150
}

var results = []
for i = 0; i < 5; i = i + 1 {
    var result = processItem(i)
    results.push(result)
}

// Process results
for result in results {
    var arr = result.toArray()
    fmt.Printf("Status: %v, Success: %v, Time: %vms\n", 
               arr[0], arr[1], arr[2])
}

Tuple vs Array

Feature Tuple Array
Mutability Immutable Mutable
Type Heterogeneous (mixed types) Can be heterogeneous or typed
Creation Function returns Literal [...]
Indexing ✅ Zero-based ✅ Zero-based
Methods .length(), .toArray() Many instance methods
Primary Use Multiple return values General collections

Best Practices

1. Destructure When Possible

Destructure Tuples
1
2
3
4
5
6
7
// Preferred: Clear and readable
var name, age, active = getUserInfo()

// Less preferred: Requires indexing
var user = getUserInfo()
var name = user[0]
var age = user[1]

2. Use Error Checking Pattern

Error Checking
1
2
3
4
5
6
7
8
9
// Good: Check error before using value
var value, err = arr.pop()
if err == None {
    // Use value safely
    fmt.Println(value)
}

// Risky: Ignoring error
var value, _ = arr.pop()  // If error, value is None

3. Convert to Array for Complex Processing

Convert for Processing
1
2
3
4
5
6
7
// When you need array methods or iteration
var tuple = someFunction()
var arr = tuple.toArray()

// Now use array methods
arr.reverse()
arr.slice(0, 2)

See Also