Introduction to Functions
Functions are reusable blocks of code that perform a specific task. They are a fundamental building block of Harneet programs and support advanced features like returning other functions, closures, and higher-order programming.
Declaration Syntax
The basic syntax for declaring a function is as follows:
| Function Declaration Syntax |
|---|
| package main
function functionName(param1 type1, param2 type2) returnType {
// function body
return value
}
|
function: The keyword to declare a function. functionName: The name of the function. (param1 type1, param2 type2): The list of parameters with their types. returnType: The type of the value returned by the function. { ... }: The body of the function containing the code to be executed. return: The keyword to return a value from the function.
Basic Examples
Function with a single return value
| Single Return Value |
|---|
| package main
import fmt
function square(x int) int {
return x * x
}
var result = square(5)
fmt.Println(result) // Output: 25
|
Function with no parameters
| No Parameters |
|---|
| package main
import fmt
function getAnswer() int {
return 42
}
var answer = getAnswer()
fmt.Println(answer) // Output: 42
|
Function with no return value
| No Return Value |
|---|
| package main
import fmt
function printMessage() {
fmt.Println("Hello, Harneet!")
}
printMessage() // Output: Hello, Harneet!
|
Returning Functions
Harneet supports returning functions from other functions, enabling powerful functional programming patterns like closures and higher-order functions.
Basic Function Return
| Basic Function Return |
|---|
| package main
import fmt
function getGreeter() function(string) string {
function greet(name string) string {
return "Hello, " + name + "!"
}
return greet
}
var greeter = getGreeter()
var message = greeter("World")
fmt.Println(message) // Output: Hello, World!
|
Closures with Variable Capture
Functions can capture variables from their enclosing scope, creating closures:
| Closure with Variable Capture |
|---|
| package main
import fmt
function createAdder(x int) function(int) int {
function inner(y int) int {
return x + y // Captures 'x' from outer scope
}
return inner
}
var add5 = createAdder(5)
var result = add5(3)
fmt.Println(result) // Output: 8
|
Returning Arrow Functions
You can also return arrow functions for more concise syntax:
| Return Arrow Function |
|---|
| package main
import fmt
function createMultiplier(factor int) function(int) int {
return x => x * factor
}
var double = createMultiplier(2)
var triple = createMultiplier(3)
fmt.Printf("Double 5: %d\n", double(5)) // Output: Double 5: 10
fmt.Printf("Triple 4: %d\n", triple(4)) // Output: Triple 4: 12
|
Higher-Order Functions
Functions can return functions that themselves return functions, enabling complex functional patterns:
| Higher-Order Function |
|---|
| package main
import fmt
function createCalculator() function(string) function(int, int) int {
function getOperation(op string) function(int, int) int {
if op == "add" {
return (a int, b int) int => a + b
} else if op == "subtract" {
return (a int, b int) int => a - b
} else {
return (a int, b int) int => a * b
}
}
return getOperation
}
var calculator = createCalculator()
var addFunc = calculator("add")
var subFunc = calculator("subtract")
fmt.Printf("10 + 5 = %d\n", addFunc(10, 5)) // Output: 10 + 5 = 15
fmt.Printf("10 - 5 = %d\n", subFunc(10, 5)) // Output: 10 - 5 = 5
|
Conditional Function Returns
Functions can return different functions based on runtime conditions:
| Conditional Function Returns |
|---|
| package main
import fmt
function createMathOperation(operation string) function(int, int) int {
if operation == "add" {
function add(a int, b int) int {
return a + b
}
return add
} else {
function multiply(a int, b int) int {
return a * b
}
return multiply
}
}
var addOp = createMathOperation("add")
var multiplyOp = createMathOperation("multiply")
fmt.Printf("Add: %d\n", addOp(10, 20)) // Output: Add: 30
fmt.Printf("Multiply: %d\n", multiplyOp(4, 5)) // Output: Multiply: 20
|
Function Type Annotations
Harneet provides comprehensive support for function type annotations, enabling strong type safety for higher-order functions and functional programming patterns.
Function Parameters with Function Types
You can specify function types as parameters, enabling type-safe higher-order functions:
| Function Parameter Types |
|---|
| package main
import fmt
// Function that takes another function as a parameter
function apply(f function(int) int, value int) int {
return f(value)
}
// Function that takes multiple function parameters
function compose(f function(int) int, g function(int) int, value int) int {
return f(g(value))
}
// Test functions
function double(x int) int {
return x * 2
}
function addTen(x int) int {
return x + 10
}
// Usage with full type validation
var result1 = apply(double, 5) // Output: 10
var result2 = compose(double, addTen, 5) // Output: 30
fmt.Printf("apply(double, 5) = %d\n", result1)
fmt.Printf("compose(double, addTen, 5) = %d\n", result2)
|
Function Variables with Type Annotations
Variables can be declared with specific function types:
| Function Variable Declaration |
|---|
| package main
import fmt
// Declare a function variable with a specific signature
var handler function(int) int
// Helper function
function increment(x int) int {
return x + 1
}
// Assign function to typed variable
handler = increment
// Use the function variable
var result = handler(7)
fmt.Printf("handler(7) = %d\n", result) // Output: 8
|
Multiple Parameter Function Types
Function types can specify multiple parameters and different return types:
| Multiple Parameter Function Types |
|---|
| package main
import fmt
// Function expecting a binary operation
function calculate(op function(int, int) int, a int, b int) int {
return op(a, b)
}
// Function expecting a string transformation
function transform(fn function(string) string, text string) string {
return fn(text)
}
// Test functions
function add(x int, y int) int {
return x + y
}
function toUpper(s string) string {
return "[UPPER]" + s
}
// Usage with type validation
var sum = calculate(add, 10, 5)
var upper = transform(toUpper, "hello")
fmt.Printf("calculate(add, 10, 5) = %d\n", sum) // Output: 15
fmt.Printf("transform(toUpper, \"hello\") = %s\n", upper) // Output: [UPPER]hello
|
Arrow Functions with Type Annotations
Arrow functions work seamlessly with function type annotations:
| Arrow Functions with Types |
|---|
| package main
import fmt
// Function expecting a function parameter
function processNumbers(processor function(int) int, numbers []int) []int {
var results []int
for _, var num = range numbers {
results = append(results, processor(num))
}
return results
}
// Arrow functions can be passed directly
var doubled = processNumbers(x => x * 2, [1, 2, 3, 4])
var squared = processNumbers(x => x * x, [1, 2, 3, 4])
fmt.Printf("Doubled: %v\n", doubled) // Output: [2, 4, 6, 8]
fmt.Printf("Squared: %v\n", squared) // Output: [1, 4, 9, 16]
|
Type Safety and Error Detection
Harneet's function type system provides comprehensive compile-time validation:
| Type Safety Examples |
|---|
| package main
import fmt
function apply(f function(int) int, value int) int {
return f(value)
}
function double(x int) int {
return x * 2
}
function toUpper(s string) string {
return "[UPPER]" + s
}
// ✅ This works - correct types
var result1 = apply(double, 5)
// ❌ These would cause compile-time errors:
// apply(toUpper, 5) // Error: toUpper expects string, not int
// apply(5, 10) // Error: 5 is not a function
// apply(double, "text") // Error: double expects int, not string
|
Advanced Function Type Patterns
Factory Functions with Type Safety
| Factory Function Validator |
|---|
| package main
import fmt
// Factory function returning typed function
function createValidator(minLength int) function(string) bool {
function validate(input string) bool {
// In practice, you'd check string length
return input != ""
}
return validate
}
// Type-safe usage
var passwordValidator = createValidator(8)
var isValid = passwordValidator("mypassword")
fmt.Printf("Password valid: %t\n", isValid)
|
Callback Pattern with Type Validation
| Callback Pattern |
|---|
| package main
import fmt
// Function with callback parameter
function processData(data int, callback function(int) int, errorHandler function(string)) int {
if data < 0 {
errorHandler("Invalid data: negative number")
return 0
}
return callback(data)
}
// Callback functions
function processValue(x int) int {
return x * 2
}
function handleError(msg string) {
fmt.Printf("Error: %s\n", msg)
}
// Type-safe callback usage
var result = processData(10, processValue, handleError)
fmt.Printf("Processed result: %d\n", result)
|
Key Benefits
🔒 Type Safety
- Compile-time validation of function signatures
- Prevention of runtime type errors
- Clear error messages for type mismatches
- No runtime type checking overhead
- Optimized function calls
- Early error detection
📖 Code Clarity
- Self-documenting function interfaces
- Clear expectations for function parameters
- Better IDE support and tooling
🔧 Flexibility
- Works with all function types (named, anonymous, arrow)
- Supports complex nested function signatures
- Compatible with existing code patterns
The function type system in Harneet provides the perfect balance of type safety and flexibility, enabling robust functional programming while maintaining code clarity and performance.