GitHub

Variables

Stable Variable syntax and data types are stable in Levython 1.0.

Levython uses the <- operator for variable assignment, providing clear visual distinction between assignment and comparison operations.

Assignment Syntax#

Levython uses the <- (left arrow) operator for variable assignment. This distinctive syntax provides visual clarity by showing the direction of data flow and eliminates confusion between assignment and equality comparison.

variable_name <- expression
levython
# Variable assignment
name <- "Levython"
version <- 1.0
is_fast <- true

# Variables are dynamically typed
x <- 42        # x is a number
x <- "text"    # x is now a string (reassignment)

# Reassignment and mutation
counter <- 0
counter <- counter + 1
counter <- counter + 1

say(name)           # Output: Levython
say(str(version))   # Output: 1.0
say(str(counter))   # Output: 2

Variable Naming Rules

  • Must start with a letter (a-z, A-Z) or underscore (_)
  • Can contain letters, digits (0-9), and underscores
  • Case-sensitive: myVar and myvar are different
  • Cannot use reserved keywords (act, if, for, while, etc.)
levython
# Valid variable names
user_name <- "Alice"
total_count <- 100
_private <- "hidden"
MAX_SIZE <- 1000

# Invalid variable names (will cause errors)
# 123abc <- "nope"      # Cannot start with digit
# my-var <- "nope"      # Cannot contain hyphens
# if <- "nope"          # Cannot use keywords

Compound Assignment Operators

Levython supports compound assignment operators for convenience:

levython
# Compound assignment operators
x <- 10
x <- x + 5    # Standard form
x += 5        # Compound form (equivalent)

# Available operators
counter <- 0
counter += 1   # Addition: counter = counter + 1
counter -= 1   # Subtraction: counter = counter - 1
counter *= 2   # Multiplication: counter = counter * 2
counter /= 2   # Division: counter = counter / 2
Design Rationale: The <- arrow operator was chosen for several reasons:
  • Visual Clarity: Shows data flowing from right (value) to left (variable)
  • No Confusion: Eliminates mix-ups between assignment (<-) and comparison (==)
  • Consistency: Pairs with return operator (->) which shows data flowing out
  • Readability: Makes variable assignments stand out in code

Data Types#

Levython supports the following data types:

Type Description Example
string Text data "Hello"
number Integer or float 42, 3.14
boolean True or false true, false
list Ordered collection [1, 2, 3]
null No value null

Strings#

Strings are sequences of characters enclosed in double quotes:

levython
# String literals
greeting <- "Hello, World!"
empty <- ""

# String concatenation
first <- "Levy"
last <- "thon"
full <- first + last
say(full)  # Output: Levython

# String length
say(str(len(greeting)))  # Output: 13

Numbers#

Levython supports both integers and floating-point numbers (doubles) with automatic type handling. All numeric values are internally represented using NaN-boxing for efficient 8-byte storage.

levython
# Integer literals
count <- 42
negative <- -10
large <- 1000000

# Floating-point literals
pi <- 3.14159
temperature <- -40.5
scientific <- 1.5e-10

# Arithmetic operations
sum <- 10 + 5        # Addition: 15
diff <- 10 - 5       # Subtraction: 5
product <- 10 * 5    # Multiplication: 50
quotient <- 10 / 5   # Division: 2.0
remainder <- 10 % 3  # Modulo: 1
power <- 2 ** 8      # Exponentiation: 256

say(str(sum))      # Output: 15
say(str(product))  # Output: 50
say(str(power))    # Output: 256

Operator Precedence

Levython follows standard mathematical precedence rules:

  1. ** (Exponentiation) - highest precedence
  2. *, /, % (Multiplication, Division, Modulo)
  3. +, - (Addition, Subtraction) - lowest precedence
levython
# Precedence examples
result <- 2 + 3 * 4     # 14 (not 20)
result <- (2 + 3) * 4   # 20 (parentheses override)
result <- 2 ** 3 ** 2   # 512 (right-associative)
result <- 10 / 2 * 3    # 15 (left-to-right)

Type Conversion

Convert between numeric types and strings:

levython
# String to number
text <- "42"
num <- int(text)      # 42 (integer)
num <- float(text)    # 42.0 (float)

# Number to string
value <- 123
text <- str(value)    # "123"

# For display (str() is required)
x <- 100
say("Value: " + str(x))  # Correct
# say("Value: " + x)      # Error: cannot concatenate number

Special Numeric Values

Levython handles special IEEE 754 floating-point values:

  • Infinity: Result of overflow (e.g., 1.0 / 0.0)
  • NaN (Not a Number): Result of undefined operations (e.g., 0.0 / 0.0)
Performance Note: Integer operations are optimized for the common case where values fit in 48 bits (±140 trillion range). Larger integers and all floating-point operations use native x86-64 FPU instructions for maximum speed.

Booleans#

Boolean values represent true or false:

levython
# Boolean literals
is_active <- true
is_complete <- false

# Comparison results
x <- 10
is_greater <- x > 5      # true
is_equal <- x == 10      # true
is_not_equal <- x != 5   # true

if is_active {
    say("Active!")
}

Lists#

Lists are ordered, mutable collections:

levython
# List creation
numbers <- [1, 2, 3, 4, 5]
mixed <- ["hello", 42, true]
empty_list <- []

# Accessing elements (0-indexed)
first <- numbers[0]    # 1
second <- numbers[1]   # 2

# Adding elements
append(numbers, 6)

# List length
say(str(len(numbers)))  # Output: 6

See Lists for more details.

Null#

The null value represents the absence of a value:

levython
value <- null

if value == null {
    say("No value set")
}

Type Conversion#

Levython provides built-in functions for converting between different data types:

Available Conversion Functions

Function Description Example Result
str(value) Convert to string str(42) "42"
int(value) Convert to integer int("42") 42
float(value) Convert to float float("3.14") 3.14
type(value) Get type name type(42) "integer"
levython
# String conversion (required for output)
number <- 42
boolean <- true
list <- [1, 2, 3]

say("Number: " + str(number))   # Number: 42
say("Boolean: " + str(boolean)) # Boolean: true
say("List: " + str(list))       # List: [1, 2, 3]

# Numeric conversion
text <- "123"
num <- int(text)        # 123
decimal <- float(text)  # 123.0

# Type checking
value <- 42
say("Type: " + type(value))  # Type: integer

# Conversion in expressions
user_input <- "10"
doubled <- int(user_input) * 2
say("Result: " + str(doubled))  # Result: 20

Type Introspection

Use the type() function to inspect value types at runtime:

levython
say(type(42))        # "integer"
say(type(3.14))      # "float"
say(type("hello"))   # "string"
say(type(true))      # "boolean"
say(type([1, 2]))    # "list"
say(type(null))      # "null"
Important: The str() function must be used when concatenating non-string values with strings. Attempting to concatenate without conversion will result in a runtime type error.

Common Patterns

levython
# Pattern: User input conversion
age_str <- ask("Enter your age: ")
age <- int(age_str)

if age >= 18 {
    say("You are an adult")
} else {
    say("You are " + str(18 - age) + " years away from adulthood")
}

# Pattern: Numeric calculations
price_str <- "29.99"
quantity_str <- "3"
total <- float(price_str) * int(quantity_str)
say("Total: $" + str(total))  # Total: $89.97

# Pattern: Dynamic type handling
values <- [42, "hello", 3.14, true]
for val in values {
    say("Value: " + str(val) + ", Type: " + type(val))
}
# Output:
# Value: 42, Type: integer
# Value: hello, Type: string
# Value: 3.14, Type: float
# Value: true, Type: boolean