Language Guide
Variables & Types

Variables & Data Types

Flowa is a dynamically-typed language where variables can hold any type and change at runtime.

Variable Declaration

All variables are declared with the let keyword:

let name = "Alice";
let age = 30;
let pi = 3.14159;
let active = true;
let data = null;

Variable Rules

  • Must start with a letter or underscore
  • Can contain letters, digits, underscores
  • Case-sensitive (myVarmyvar)
  • Cannot use reserved keywords

Reserved Keywords

let, func, if, else, while, for, return, true, false, null, break, continue

Data Types

Strings

Strings are sequences of characters enclosed in double quotes:

let greeting = "Hello, World!";
let multiline = "Line 1
Line 2
Line 3";
let empty = "";

String Operations

// Concatenation
let first = "Hello";
let last = "World";
let combined = first + " " + last;  // "Hello World"
 
// Length
let length = len("Hello");  // 5
 
// Case conversion
let upper_str = upper("hello");   // "HELLO"
let lower_str = lower("WORLD");   // "world"
 
// Substring extraction
let str = "Hello, World!";
let sub = substring(str, 0, 5);   // "Hello"
 
// Contains check
let has_world = contains(str, "World");  // true
 
// Trim whitespace
let trimmed = trim("  hello  ");  // "hello"
 
// Check prefix/suffix
let starts = startsWith("Hello", "He");  // true
let ends = endsWith("Hello", "lo");      // true
 
// Get character at index
let char = charAt("Hello", 1);           // "e"
 
// Replace
let replaced = replace("Hello World", "World", "Flowa");  // "Hello Flowa"
 
// Split
let parts = split("a,b,c", ",");  // ["a", "b", "c"]

Numbers

Flowa supports both integers and floating-point numbers:

let integer = 42;
let negative = -10;
let float_num = 3.14159;
let scientific = 1.5e10;

Arithmetic Operations

let a = 10;
let b = 3;
 
let add = a + b;    // 13
let sub = a - b;    // 7
let mul = a * b;    // 30
let div = a / b;    // 3.333...
let mod = a % b;    // 1 (modulo/remainder)

Math funcs

// Power
let pow_result = power(2, 8);     // 256
 
// Square root
let sqrt_val = sqrt(16);          // 4
 
// Rounding
let floor_val = floor(3.7);       // 3
let ceil_val = ceil(3.2);         // 4
let round_val = round(3.5);       // 4
 
// Absolute value
let abs_val = abs(-5);            // 5
 
// Min/Max
let min_val = min(10, 5);         // 5
let max_val = max(10, 5);         // 10

Booleans

Boolean values represent true or false:

let is_active = true;
let is_completed = false;

Boolean Operations

let x = true;
let y = false;
 
// Logical AND
let and_result = x && y;  // false
 
// Logical OR
let or_result = x || y;   // true
 
// Logical NOT
let not_result = !x;      // false

Comparison Operators

let a = 5;
let b = 10;
 
let eq = a == b;      // false (equal)
let neq = a != b;     // true (not equal)
let lt = a < b;       // true (less than)
let lte = a <= b;     // true (less than or equal)
let gt = a > b;       // false (greater than)
let gte = a >= b;     // false (greater than or equal)

Null

null represents the absence of a value:

let empty_value = null;
 
if (empty_value == null) {
    print("Value is null");
}

Arrays

Arrays are ordered collections of values:

// Empty array
let arr = [];
 
// Array with values
let numbers = [1, 2, 3, 4, 5];
 
// Mixed types
let mixed = [1, "two", 3.0, true, null];

Array Access

let numbers = [10, 20, 30, 40, 50];
 
// Access by index (0-based)
let first = numbers[0];       // 10
let third = numbers[2];       // 30
 
// Modify elements
numbers[1] = 25;              // [10, 25, 30, 40, 50]

Array Operations

let arr = [1, 2, 3];
 
// Add element to end
arr = push(arr, 4);           // [1, 2, 3, 4]
 
// Remove last element
let last = pop(arr);          // 4, arr = [1, 2, 3]
 
// Remove first element
let first = shift(arr);       // 1, arr = [2, 3]
 
// Reverse array
let reversed = reverse([1, 2, 3]);  // [3, 2, 1]
 
// Sort array
let sorted = sort([3, 1, 4, 1, 5]); // [1, 1, 3, 4, 5]
 
// Slice (extract portion)
let numbers = [1, 2, 3, 4, 5];
let subset = slice(numbers, 1, 3);  // [2, 3]
 
// Check if includes value
let has_three = includes([1, 2, 3], 3);  // true
 
// Find index of value
let idx = indexOf([1, 2, 3, 2], 2);      // 1 (first occurrence)
 
// Get length
let length = len(arr);
 
// Join array
let joined = join(["a", "b", "c"], "-");  // "a-b-c"

Hashes (Objects/Dictionaries)

Hashes store key-value pairs:

// Empty hash
let hash = {};
 
// Hash with values
let person = {
    "name": "Alice",
    "age": 30,
    "city": "New York"
};

Important: Always use quoted strings for hash keys.

Hash Access

let person = {
    "name": "Bob",
    "age": 25,
    "email": "bob@example.com"
};
 
// Access values
let name = person["name"];         // "Bob"
let age = person["age"];           // 25
 
// Modify values
person["age"] = 26;
 
// Add new keys
person["phone"] = "555-1234";

Nested Hashes

let user = {
    "name": "Alice",
    "address": {
        "street": "123 Main St",
        "city": "Boston",
        "zip": "02101"
    },
    "contacts": {
        "email": "alice@example.com",
        "phone": "555-5678"
    }
};
 
// Access nested values
let city = user["address"]["city"];           // "Boston"
let email = user["contacts"]["email"];        // "alice@example.com"

Type Conversion

To Number

let str = "42";
let num = tonumber(str);    // 42
 
let invalid = tonumber("abc");  // Returns null or 0

To String

let num = 42;
let str = tostring(num);    // "42"
 
let bool = true;
let str2 = tostring(bool);  // "true"

Type Checking

let value = "hello";
let type_name = type(value);  // "string"
 
// Possible return values:
// "string", "number", "boolean", "array", "hash", "func", "null"
 
if (type(value) == "string") {
    print("It's a string!");
}

Variable Scope

Global Scope

Variables declared outside funcs are global:

let global_var = "I'm global";
 
func test() {
    print(global_var);  // Can access global
}
 
test();

Local Scope

Variables declared inside funcs are local:

func test_scope() {
    let local_var = "I'm local";
    print(local_var);
}
 
test_scope();
// print(local_var);  // ERROR - out of scope

Closure

funcs can capture variables from outer scopes:

func create_counter() {
    let count = 0;
    
    func increment() {
        count = count + 1;
        return count;
    }
    
    return increment;
}
 
let counter = create_counter();
print(counter());  // 1
print(counter());  // 2
print(counter());  // 3

Best Practices

Meaningful Names

// Good
let user_count = 10;
let is_active = true;
let total_price = 99.99;
 
// Avoid
let x = 10;
let flag = true;
let temp = 99.99;

Initialize Variables

// Good
let count = 0;
let items = [];
let user = {};
 
// Avoid uninitialized variables
let data;  // undefined behavior

Use Appropriate Types

// Use arrays for collections
let numbers = [1, 2, 3, 4, 5];
 
// Use hashes for structured data
let user = {
    "id": 123,
    "name": "Alice",
    "email": "alice@example.com"
};
 
// Use null for absent values
let optional_value = null;

Examples

Working with User Data

let user = {
    "id": 1,
    "username": "alice",
    "email": "alice@example.com",
    "age": 30,
    "is_active": true,
    "tags": ["developer", "admin"],
    "preferences": {
        "theme": "dark",
        "language": "en"
    }
};
 
// Access and modify
print("User: " + user["username"]);
user["age"] = user["age"] + 1;
user["tags"] = push(user["tags"], "moderator");
 
// Type checking
if (type(user["tags"]) == "array") {
    print("Tags count: " + tostring(len(user["tags"])));
}

Data Processing

let prices = [19.99, 29.99, 39.99, 49.99];
let total = 0;
let i = 0;
 
while (i < len(prices)) {
    total = total + prices[i];
    i = i + 1;
}
 
print("Total: $" + tostring(total));
print("Average: $" + tostring(total / len(prices)));

Next Steps

  • Control Flow - Learn about if/else, loops, and more
  • funcs - Explore funcs and closures
  • Control Flow - Learn about if/else, loops, and more
  • funcs - Explore funcs and closures