Functions in Soplang
Functions are reusable blocks of code that perform specific tasks. In Soplang, functions are defined using the howl
keyword and can take parameters, return values, and be composed in various ways.
// Basic function definition howl greet() { qor("Hello, World!") } // Calling the function greet() // Outputs: "Hello, World!"
Function Basics
In Soplang, functions are defined using the howl
keyword, followed by the function name, parentheses for parameters, and a block of code enclosed in curly braces:
// Basic function definition howl greet() { qor("Hello, World!") } // Calling the function greet() // Outputs: "Hello, World!"
Functions should be named according to what they do, typically using verbs or verb phrases. In Soplang, function names conventionally use camelCase:
// Good function names howl calculateSum(a, b) { soo_celi a + b } howl getFirstName(names) { soo_celi names[0] } howl addData(data, section) { section.kudar(data) }
Parameters and Arguments
Functions can accept parameters, which are variables listed in the function definition. When you call a function with specific values, those values are called arguments.
Basic Parameters
// Function with parameters howl greet(name) { qor("Hello, " + name + "!") } // Calling with arguments greet("Farah") // Outputs: "Hello, Farah!" greet("Halima") // Outputs: "Hello, Halima!"
Multiple Parameters
// Function with multiple parameters howl add(num1, num2, num3) { soo_celi num1 + num2 + num3 } door result = add(10, 20, 30) qor(result) // Outputs: 60
Default Parameter Values
You can provide default values for parameters, which are used if no argument is provided:
// Function with default parameter values howl calculateTax(amount, taxPercent = 15) { door tax = (taxPercent / 100) * amount soo_celi tax } qor(calculateTax(1000)) // Uses default 15%, Outputs: 150 qor(calculateTax(1000, 10)) // Uses provided 10%, Outputs: 100
Named Arguments
For better readability, especially with multiple parameters, you can use named arguments:
// Function definition howl createArticle(title, author, date, description = "") { // Function body soo_celi { "title": title, "author": author, "date": date, "description": description } } // Using named arguments door article = createArticle( title = "Learning Soplang", author = "Farah", date = "2023-10-24", description = "A great new language" ) // You can change the order with named arguments door anotherArticle = createArticle( author = "Halima", description = "Making programming easier to learn", date = "2023-10-20", title = "Soplang and Its Benefits" )
Variable Number of Arguments
You can create functions that accept a variable number of arguments using the rest parameter syntax (denoted by ...
):
// Function with variable number of arguments howl addAll(...numbers) { door total = 0 ku_celi num ku dhex jira numbers { total += num } soo_celi total } qor(addAll(1, 2, 3)) // Outputs: 6 qor(addAll(10, 20, 30, 40, 50)) // Outputs: 150 qor(addAll()) // Outputs: 0
Return Values
Functions can return values using the soo_celi
keyword. If no return statement is specified, the function returns waxba
(null) by default.
Basic Return Values
// Function returning a value howl square(num) { soo_celi num * num } door result = square(5) qor(result) // Outputs: 25 // Function with no explicit return howl printMessage(message) { qor("LOG: " + message) // No return statement, implicitly returns waxba (null) } door output = printMessage("Hello") qor(output) // Outputs: null
Early Returns
// Early return example howl getDivision(a, b) { haddii (b == 0) { qor("Error: Cannot divide by zero") soo_celi waxba } soo_celi a / b } qor(getDivision(10, 2)) // Outputs: 5 qor(getDivision(10, 0)) // Outputs: "Error: Cannot divide by zero" and then null
Returning Multiple Values
You can return multiple values using tuples or objects:
// Returning multiple values using a tuple howl getNameParts(fullName) { door parts = fullName.split(" ") soo_celi [parts[0], parts.length > 1 ? parts[1] : ""] } door [firstName, lastName] = getNameParts("John Smith") qor(firstName) // Outputs: "John" qor(lastName) // Outputs: "Smith" // Returning multiple values using an object howl getPersonStats(person) { soo_celi { "age": person.age, "height": person.height, "weight": person.weight } } door person = { "name": "Sarah", "age": 28, "height": 165, "weight": 60 } door stats = getPersonStats(person) qor(stats.age) // Outputs: 28 qor(stats.height) // Outputs: 165
Function Scope
Functions create their own scope, which means variables defined inside a function are not accessible outside of it:
// Function scope example howl calculateArea(width, height) { door area = width * height // Local variable soo_celi area } door rectArea = calculateArea(5, 10) qor(rectArea) // Outputs: 50 // This would cause an error: // qor(area) // Error: 'area' is not defined // Variables with the same name don't conflict door area = "This is a global area variable" door functionArea = calculateArea(3, 4) // This uses its own local 'area' qor(area) // Outputs: "This is a global area variable" qor(functionArea) // Outputs: 12
Closures
Functions in Soplang can form closures, which means they can remember the environment in which they were created:
// Closure example howl createCounter(startValue = 0) { door count = startValue // Return a function that has access to the 'count' variable howl increment() { count += 1 soo_celi count } soo_celi increment } door counter1 = createCounter(10) door counter2 = createCounter(5) qor(counter1()) // Outputs: 11 qor(counter1()) // Outputs: 12 qor(counter2()) // Outputs: 6 qor(counter1()) // Outputs: 13 - counter1 maintained its own state qor(counter2()) // Outputs: 7 - counter2 maintained its own state
Anonymous Functions
Anonymous functions are functions without a name. They can be assigned to variables or passed as arguments to other functions:
// Anonymous function assigned to a variable door greet = howl(name) { soo_celi "Hello, " + name + "!" } qor(greet("John")) // Outputs: "Hello, John!" // Anonymous function as an argument door numbers = [1, 2, 3, 4, 5] door squaredNumbers = numbers.map(howl(num) { soo_celi num * num }) qor(squaredNumbers) // Outputs: [1, 4, 9, 16, 25] // Shorthand syntax for simple functions (arrow functions) door cubes = numbers.map(num => num * num * num) qor(cubes) // Outputs: [1, 8, 27, 64, 125]
Higher-Order Functions
Higher-order functions are functions that take other functions as arguments or return functions. They are powerful for functional programming patterns:
// Higher-order function that takes a function as an argument howl applyToEach(array, func) { door results = [] ku_celi item ku dhex jira array { results.push(func(item)) } soo_celi results } door numbers = [1, 2, 3, 4, 5] door doubled = applyToEach(numbers, num => num * 2) qor(doubled) // Outputs: [2, 4, 6, 8, 10] // Higher-order function that returns a function howl multiplier(factor) { soo_celi howl(number) { soo_celi number * factor } } door double = multiplier(2) door triple = multiplier(3) qor(double(5)) // Outputs: 10 qor(triple(5)) // Outputs: 15 // Chaining higher-order functions howl filterMap(array, predicate, transform) { door results = [] ku_celi item ku dhex jira array { haddii (predicate(item)) { results.push(transform(item)) } } soo_celi results } // Get squares of even numbers door numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] door evenSquares = filterMap( numbers, num => num % 2 == 0, // Filter for even numbers num => num * num // Transform by squaring ) qor(evenSquares) // Outputs: [4, 16, 36, 64, 100]
Recursion
Recursion is a technique where a function calls itself. This is useful for solving problems that can be broken down into smaller, similar subproblems:
// Factorial function using recursion howl factorial(n) { haddii (n <= 1) { soo_celi 1 } soo_celi n * factorial(n - 1) } qor(factorial(5)) // Outputs: 120 (5 * 4 * 3 * 2 * 1) // Fibonacci sequence using recursion howl fibonacci(n) { haddii (n <= 0) { soo_celi 0 } laq_heli (n == 1) { soo_celi 1 } soo_celi fibonacci(n - 1) + fibonacci(n - 2) } qor(fibonacci(7)) // Outputs: 13 // Tree traversal using recursion howl createNode(value, left = null, right = null) { soo_celi { value, left, right } } // Creating a simple binary tree door root = createNode(1, createNode(2, createNode(4), createNode(5) ), createNode(3, createNode(6), createNode(7) ) ) // In-order traversal (Left -> Root -> Right) howl inorder_traverse(node) { haddii (node == null) { soo_celi [] } door results = [] results = results.concat(inorder_traverse(node.left)) results.push(node.value) results = results.concat(inorder_traverse(node.right)) soo_celi results } qor(inorder_traverse(root)) // Outputs: [4, 2, 5, 1, 6, 3, 7]
Note: Be cautious with recursion, as deep recursion can lead to stack overflow errors. For deep recursion, consider using tail-call optimization or iterative approaches.
Best Practices for Functions
- •
Single Responsibility: Each function should do one thing and do it well.
- •
Descriptive Names: Name functions with verbs that describe what they do.
- •
Limit Parameters: Functions with many parameters are harder to use. Consider using objects for multiple parameters.
- •
Consistent Return Values: Functions should return consistent types to avoid confusion.
- •
Pure Functions: When possible, use pure functions (no side effects, same output for same input).
- •
Comments: Add comments to explain complex logic, but aim for self-documenting code.
Next Steps
Now that you understand functions in Soplang, you can explore these related topics: