Etch supports global variables with compile-time initialization and strict safety guarantees.
// Global constants
let PI = 3.14159;
let MAX_USERS = 1000;
let APP_NAME = "MyApp";
// Global variables (mutable)
var globalCounter = 0;
var isInitialized = false;
fn main() {
print(PI); // Access globals
globalCounter = globalCounter + 1; // Modify mutable globals
print(globalCounter);
}
// Immutable global (preferred)
let CONSTANT_NAME = value;
// Mutable global (use sparingly)
var globalName = value;
All globals must be initialized at declaration:
// ✅ Valid: initialized
let MAX_SIZE = 100;
var counter = 0;
// ❌ Invalid: uninitialized
let MAX_SIZE; // ERROR
var counter: int; // ERROR
Global initializers must be compile-time constants:
// ✅ Valid: compile-time constants
let SIZE = 100;
let MESSAGE = "Hello";
let VALUES = [1, 2, 3, 4, 5];
// ❌ Invalid: runtime computation
var input = readLine(); // ERROR: not compile-time
let random = rand(); // ERROR: not compile-time
let computed = calculate(10); // ERROR: function call not allowed
// ✅ Valid: simple compile-time expressions
let SIZE = 100;
let DOUBLE_SIZE = SIZE * 2; // 200
let TOTAL = SIZE + DOUBLE_SIZE; // 300
let BUFFER_SIZE = 1024 * 1024; // 1 MB
// String concatenation
let PREFIX = "app";
let VERSION = "1.0";
let APP_ID = PREFIX + "_" + VERSION; // "app_1.0"
// Array operations
let NUMBERS = [1, 2, 3];
let MORE = NUMBERS + [4, 5]; // [1, 2, 3, 4, 5]
The Etch compiler evaluates global initializers during compilation:
// All of these are computed at compile time
let A = 10;
let B = 20;
let SUM = A + B; // 30 (computed at compile time)
let PRODUCT = A * B; // 200 (computed at compile time)
let MESSAGE = "Count: " + string(SUM); // "Count: 30"
Result: No runtime overhead for accessing these globals.
Some builtin functions can be evaluated at compile time in global context:
// String operations
let UPPER = "hello";
let TEXT = UPPER; // String operations TBD
// Array operations
let NUMS = [1, 2, 3];
let SIZE = #NUMS; // 3 (compile-time)
Cannot use runtime operations in global initializers:
// ❌ Cannot use I/O
let CONFIG = readFile("config.txt"); // ERROR
// ❌ Cannot call non-const functions
var START_TIME = getCurrentTime(); // ERROR
// ❌ Cannot use rand()
var SEED = rand(); // ERROR
Globals are initialized in dependency order:
let A = 10;
let B = A * 2; // OK: A is available
let C = B + A; // OK: Both A and B are available
let A = B + 1; // ❌ ERROR: B not yet defined
let B = A + 1; // ❌ ERROR: circular dependency
Global variables in Etch are not thread-safe by default. If your program uses concurrency (future feature), protect global access with locks.
Use let for globals whenever possible:
// ✅ Preferred: immutable
let CONFIG_PATH = "/etc/app/config";
let MAX_RETRIES = 3;
// ⚠️ Use sparingly: mutable
var requestCount = 0;
var isRunning = false;
// ✅ Good: immutable constants
let MAX_CONNECTIONS = 100;
let TIMEOUT_MS = 5000;
let API_VERSION = "v2";
// ❌ Bad: mutable when not needed
var MAX_CONNECTIONS = 100; // Why mutable?
var TIMEOUT_MS = 5000; // Should be const
// ✅ Clear: these are constants
let MAX_SIZE = 1024;
let API_KEY = "secret";
let DEFAULT_PORT = 8080;
// ⚠️ Less clear: looks like variables
let maxSize = 1024;
let apiKey = "secret";
// Configuration
let CONFIG_PATH = "/etc/app/config";
let CONFIG_FORMAT = "json";
let CONFIG_VERSION = 2;
// Limits
let MAX_USERS = 1000;
let MAX_CONNECTIONS = 100;
let MAX_RETRIES = 3;
// Timeouts
let CONNECT_TIMEOUT = 5000;
let READ_TIMEOUT = 10000;
let WRITE_TIMEOUT = 10000;
// ❌ Bad: too much mutable global state
var userCount = 0;
var connectionCount = 0;
var errorCount = 0;
var successCount = 0;
// ✅ Better: pass state through function parameters
fn processRequest(stats: Stats) -> Stats {
return {
userCount: stats.userCount + 1,
// ...
};
}
// Maximum number of concurrent connections allowed
let MAX_CONNECTIONS = 100;
// Path to application configuration file
let CONFIG_PATH = "/etc/app/config.json";
// Global request counter (mutable)
// WARNING: Not thread-safe
var requestCount = 0;
// ❌ Hard to understand
let COMPUTED = ((A * B) + (C / D)) * E - F + (G % H);
// ✅ Clear and simple
let PRODUCT = A * B;
let QUOTIENT = C / D;
let RESULT = (PRODUCT + QUOTIENT) * E;
// Application configuration
let APP_NAME = "MyApp";
let APP_VERSION = "1.0.0";
let APP_ENV = "production";
// Server configuration
let SERVER_HOST = "0.0.0.0";
let SERVER_PORT = 8080;
let SERVER_WORKERS = 4;
// Database configuration
let DB_HOST = "localhost";
let DB_PORT = 5432;
let DB_NAME = "myapp_db";
// ❌ Bad: magic numbers
fn processBuffer(data: array[int]) -> bool {
if #data > 4096 { // What is 4096?
return false;
}
// ...
}
// ✅ Good: named constants
let MAX_BUFFER_SIZE = 4096;
fn processBuffer(data: array[int]) -> bool {
if #data > MAX_BUFFER_SIZE {
return false;
}
// ...
}
// Input validation limits
let MIN_USERNAME_LENGTH = 3;
let MAX_USERNAME_LENGTH = 20;
let MIN_PASSWORD_LENGTH = 8;
// System limits
let MAX_UPLOAD_SIZE = 10485760; // 10 MB
let MAX_REQUEST_SIZE = 1048576; // 1 MB
let MAX_RESULTS_PER_PAGE = 100;
// Minimal mutable global state
var isInitialized = false;
fn initialize() {
if isInitialized {
return;
}
// ... initialization code
isInitialized = true;
}
fn main() {
initialize();
// ...
}
// Build arrays at compile time
let POWERS_OF_TWO = [1, 2, 4, 8, 16, 32, 64, 128];
let FIBONACCI = [1, 1, 2, 3, 5, 8, 13, 21, 34];
// Concatenate arrays
let SMALL = [1, 2, 3];
let LARGE = [4, 5, 6, 7, 8, 9];
let ALL = SMALL + LARGE; // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Build strings at compile time
let PREFIX = "app";
let VERSION = "v2";
let ENVIRONMENT = "prod";
let FULL_ID = PREFIX + "_" + VERSION + "_" + ENVIRONMENT;
// Result: "app_v2_prod"
// C/C++
#define MAX_SIZE 1024
extern int globalCounter;
static const char* APP_NAME = "MyApp";
// Etch equivalent
let MAX_SIZE = 1024;
var globalCounter = 0;
let APP_NAME = "MyApp";
# Python
MAX_SIZE = 1024
APP_NAME = "MyApp"
counter = 0
# Etch equivalent
let MAX_SIZE = 1024;
let APP_NAME = "MyApp";
var counter = 0;
// Rust
const MAX_SIZE: i32 = 1024;
static mut COUNTER: i32 = 0;
// Etch equivalent
let MAX_SIZE = 1024;
var COUNTER = 0; // Note: not thread-safe like Rust's static
Next: Learn about Compile-Time Safety to understand how Etch’s prover ensures your code is safe.