The any Type
Harneet supports the any type as a top type (supertype of all types) with strict, one-way assignability rules. This design preserves Harneet's strong typing while enabling flexibility at dynamic boundaries like JSON, OS, regex, and external APIs.
Quick Start
| Any Type Quick Start |
|---|
| package main
import fmt
import cast
// ✅ Upcast to any - ALLOWED
var x any = 42
var y any = "hello"
fmt.Println(x) // Prints: 42
// ✅ Explicit narrowing - REQUIRED
var num, err = cast.ToInt(x)
if err == None {
fmt.Printf("Number: %d\n", num)
}
|
Core Principles
Strict Assignability Rules
The any type follows these fundamental rules:
| Direction | Allowed? | Description |
| T → any | ✅ YES | Any concrete type can be assigned to any (upcast) |
| any → T | ❌ NO | Cannot assign any to concrete type without explicit cast (downcast) |
This one-way assignability prevents type safety violations while allowing flexibility where needed.
Basic Usage
Variable Declaration
| Any Variable Declaration |
|---|
| // Declare any variables - accepts all types
var dynamic any = 100
var flexible any = "can be anything"
// Any type accepts all values
dynamic = "now a string"
dynamic = true
dynamic = [1, 2, 3]
dynamic = {"name": "Alice"}
|
Function Parameters
| Any Function Parameters |
|---|
| package main
import fmt
// Function accepting any type
function printValue(val any) {
fmt.Printf("Value: %v\n", val)
}
// Works with all types
printValue(42)
printValue("hello")
printValue(true)
printValue([1, 2, 3])
printValue({"key": "value"})
|
Function Returns
| Any Function Returns |
|---|
| package main
import fmt
import cast
// Function returning any
function getDynamic(flag bool) any {
if flag {
return 42
} else {
return "forty-two"
}
}
// Must narrow with explicit cast
var result = getDynamic(true)
var num, err = cast.ToInt(result)
if err == None {
fmt.Printf("Number: %d\n", num)
}
|
Explicit Narrowing
The cast module provides type-safe narrowing from any to concrete types.
Available Cast Functions
| Function | Purpose | Example |
cast.ToInt(any) | Convert to integer | var n, err = cast.ToInt(x) |
cast.ToString(any) | Convert to string | var s, err = cast.ToString(x) |
cast.ToBool(any) | Convert to boolean | var b, err = cast.ToBool(x) |
cast.ToFloat(any) | Convert to float | var f, err = cast.ToFloat(x) |
cast.ToArray(any) | Convert to array | var a, err = cast.ToArray(x) |
cast.ToMap(any) | Convert to map | var m, err = cast.ToMap(x) |
cast.CanCast(any, type) | Check if possible | var ok, _ = cast.CanCast(x, "int") |
Narrowing Examples
| Type Narrowing |
|---|
| package main
import fmt
import cast
var mystery any = "12345"
// Method 1: Direct conversion
var num, err = cast.ToInt(mystery)
if err == None {
fmt.Printf("Converted: %d\n", num)
}
// Method 2: Preflight check
var canConvert, _ = cast.CanCast(mystery, "int")
if canConvert {
var num, _ = cast.ToInt(mystery)
fmt.Printf("Safe to use: %d\n", num)
}
|
Best Practices
✅ When to Use any
Use any at dynamic boundaries:
1. JSON Parsing
| JSON Parsing |
|---|
| import json
import cast
var jsonStr = "{\"name\": \"Alice\", \"age\": 25}"
var data, _ = json.Unmarshal(jsonStr)
// Narrow immediately
var obj, _ = cast.ToMap(data)
var name, _ = cast.ToString(obj["name"])
var age, _ = cast.ToInt(obj["age"])
|
2. External APIs
| External APIs |
|---|
| package main
import fmt
function processAPIResponse(response any) {
var data, err = cast.ToMap(response)
if err != None {
fmt.Println("Invalid response format")
return
}
// Process typed data...
}
|
3. Configuration Management
| Configuration Management |
|---|
| var config = {
"port": 8080,
"host": "localhost",
"debug": true,
"timeout": 30.5
}
function getConfigValue(key string) any {
return config[key]
}
// Narrow when retrieving
var port, _ = cast.ToInt(getConfigValue("port"))
|
4. Generic Utilities
| Generic Utilities |
|---|
| package main
import fmt
function logValue(key string, value any) {
fmt.Printf("%s: %v\n", key, value)
}
logValue("count", 42)
logValue("name", "Alice")
logValue("active", true)
|
❌ When to Avoid any
Don't use any for:
-
Internal Business Logic
| // ❌ Bad - loses type safety
function calculateTotal(items any) any { ... }
// ✅ Good - maintains type safety
function calculateTotal(items []Item) float64 { ... }
|
-
Public APIs
| // ❌ Bad - unclear contract
function createUser(data any) any { ... }
// ✅ Good - clear contract
function createUser(name string, age int) User { ... }
|
-
Data Structures
| // ❌ Bad - no type safety
var users []any
// ✅ Good - typed collection
var users []User
|
Design Patterns
Pattern 1: Early Narrowing
Narrow at the boundary, keep core typed:
| Early Narrowing |
|---|
| package main
import fmt
import cast
function processConfig(config any) {
// Narrow immediately at boundary
var configMap, err = cast.ToMap(config)
if err != None {
fmt.Println("Error: config must be a map")
return
}
// Extract and narrow individual fields
var port, _ = cast.ToInt(configMap["port"])
var host, _ = cast.ToString(configMap["host"])
var debug, _ = cast.ToBool(configMap["debug"])
// Core logic uses concrete types
startServer(host, port, debug)
}
|
Pattern 2: Type Guards
Try each type in order:
| Type Guard Pattern |
|---|
| package main
import fmt
import cast
function handleDynamic(val any) {
// Try integer first
var asInt, intErr = cast.ToInt(val)
if intErr == None {
fmt.Printf("Handling integer: %d\n", asInt)
return
}
// Try string next
var asString, strErr = cast.ToString(val)
if strErr == None {
fmt.Printf("Handling string: %s\n", asString)
return
}
// Try boolean
var asBool, boolErr = cast.ToBool(val)
if boolErr == None {
fmt.Printf("Handling boolean: %v\n", asBool)
return
}
fmt.Println("Unsupported type")
}
|
Pattern 3: API Response Processing
Process dynamic JSON data:
| Dynamic JSON Processing |
|---|
| import json
import cast
function fetchUserData(apiResponse string) {
// Parse JSON (returns any)
var data, err = json.Unmarshal(apiResponse)
if err != None {
return
}
// Narrow to map
var userMap, mapErr = cast.ToMap(data)
if mapErr != None {
return
}
// Extract and narrow fields
var id, _ = cast.ToInt(userMap["id"])
var name, _ = cast.ToString(userMap["name"])
var email, _ = cast.ToString(userMap["email"])
var active, _ = cast.ToBool(userMap["active"])
// Use typed data in core logic
processUser(id, name, email, active)
}
|
Type Safety Guarantees
Compile-Time Enforcement
| Compile-Time Safety |
|---|
| var x any = 42
var y int = x // ❌ COMPILE ERROR: cannot assign any to int
// Must use explicit cast
var y, err = cast.ToInt(x) // ✅ OK
|
Runtime Validation
| Runtime Validation |
|---|
| package main
import fmt
var x any = "not a number"
var y, err = cast.ToInt(x) // ✅ Returns error, doesn't panic
if err != None {
fmt.Println(err)
// Output: cast.ToInt: cannot convert string "not a number" to integer
}
|
No Implicit Conversions
| No Implicit Conversions |
|---|
| var config any = {"port": "8080"}
var configMap, _ = cast.ToMap(config)
// ❌ This would fail - port is string, not int
var port, err = cast.ToInt(configMap["port"])
// ✅ This works - convert string to int
var portStr, _ = cast.ToString(configMap["port"])
var port, err = cast.ToInt(portStr)
|
Real-World Examples
Example 1: Configuration System
| Configuration System |
|---|
| package main
import fmt
import cast
import os
function loadConfig() {
var config = {
"port": 8080,
"host": "0.0.0.0",
"debug": false,
"timeout": 30.5
}
// Override from environment
var portEnv, _ = os.Getenv("PORT")
if portEnv != "" {
var port, err = cast.ToInt(portEnv)
if err == None {
config["port"] = port
}
}
return config
}
function startApp() {
var cfg = loadConfig()
// Narrow configuration values
var port, _ = cast.ToInt(cfg["port"])
var host, _ = cast.ToString(cfg["host"])
var debug, _ = cast.ToBool(cfg["debug"])
fmt.Printf("Starting server on %s:%d (debug: %v)\n", host, port, debug)
}
|
Example 2: Dynamic Command Handler
| Command Handler |
|---|
| package main
import fmt
import cast
function executeCommand(cmd string, args any) {
if cmd == "add" {
var nums, err = cast.ToArray(args)
if err != None {
fmt.Println("add command requires array of numbers")
return
}
var sum = 0
for num in nums {
var n, _ = cast.ToInt(num)
sum = sum + n
}
fmt.Printf("Sum: %d\n", sum)
} else if cmd == "greet" {
var name, err = cast.ToString(args)
if err != None {
fmt.Println("greet command requires string name")
return
}
fmt.Printf("Hello, %s!\n", name)
} else if cmd == "info" {
var data, err = cast.ToMap(args)
if err != None {
fmt.Println("info command requires map")
return
}
for key, value in data {
fmt.Printf("%s: %v\n", key, value)
}
}
}
// Usage
executeCommand("add", [1, 2, 3, 4, 5])
executeCommand("greet", "Alice")
executeCommand("info", {"version": "1.0", "author": "Harneet"})
|
Example 3: JSON API Client
| JSON API Client |
|---|
| package main
import fmt
import json
import cast
import http
function fetchUser(userId int) {
var url = fmt.Sprintf("https://api.example.com/users/%d", userId)
var response, _ = http.Get(url)
// Parse JSON response
var data, err = json.Unmarshal(response.Body)
if err != None {
fmt.Println("Failed to parse response")
return
}
// Narrow to map
var userMap, _ = cast.ToMap(data)
// Extract user fields
var id, _ = cast.ToInt(userMap["id"])
var name, _ = cast.ToString(userMap["name"])
var email, _ = cast.ToString(userMap["email"])
var age, _ = cast.ToInt(userMap["age"])
// Use typed data
fmt.Printf("User %d: %s <%s> (age: %d)\n", id, name, email, age)
}
|
Comparison with Other Languages
| Language | Type | Behavior |
Harneet any | Top type | Strict: requires explicit cast for downcast |
TypeScript any | Top type | Permissive: allows implicit conversions |
Go interface{} | Empty interface | Requires type assertion |
Python Any | Type hint | Runtime only, no compile-time enforcement |
Java Object | Root class | Requires explicit cast |
Harneet's approach: - ✅ Stricter than TypeScript (better safety) - ✅ Cleaner syntax than Go (no type assertions) - ✅ Compile-time enforcement unlike Python - ✅ Integrated cast module (easier than Java)
Summary
The any type in Harneet provides:
✅ Flexibility - Handle dynamic data at boundaries
✅ Type Safety - Explicit conversions required
✅ Clarity - Clear upcast/downcast rules
✅ Integration - Works seamlessly with cast module
✅ Best Practices - Documented patterns
✅ No Surprises - Predictable behavior
Remember: Use any at boundaries (JSON, OS, APIs), but keep core logic typed!
See Also