Chapter 04 Functions and Modules - Bryantad/Sona GitHub Wiki

๐ŸŒŸ Chapter 4: Organizing Your Code - Functions and Modules

"Functions are like having a team of specialists. Instead of doing everything yourself, you can say 'Hey, Calculator function, add these numbers' or 'Password Validator, check if this is secure.' It's programming teamwork for everyone, ages 12-55+!"

Welcome to Code Organization Mastery! ๐Ÿง 

You've learned to make programs that think and make decisions. Now it's time to learn the art of organizing code like a professional developer. In this chapter, we'll discover how to break large problems into smaller, manageable pieces using functions and modules.

This chapter serves all learning styles and accessibility needs:

  • ๐Ÿง  For ADHD minds: Clear structure with thinking blocks to organize thoughts
  • ๐ŸŽฏ For autistic minds: Predictable patterns and consistent function structures
  • ๐Ÿ“– For dyslexic minds: Plain English function names and clear explanations
  • ๐Ÿ’ก For executive function: Built-in organization and planning tools
  • ๐Ÿ‘ฅ For all ages: Examples from teen homework to professional projects

Think of this chapter as learning how to build with LEGO blocks instead of trying to carve everything from a single piece of stone. Each function is a specialized block that does one thing really well, and you can combine them to build amazing applications.

By the end of this chapter, you'll be able to:

  • โœ… Write custom functions that solve specific problems elegantly
  • โœ… Understand when to create functions vs. writing inline code
  • โœ… Use function parameters and return values like a pro
  • โœ… Create functions with default parameters and flexible arguments
  • โœ… Organize related functions into modules for larger projects
  • โœ… Build a comprehensive personal utility library you can use in any project
  • โœ… Use accessibility features to make function organization easier

Why Functions Matter: The "Don't Repeat Yourself" Principle

The Problem with Repetitive Code

Let's start with a real example. Imagine you're building a program to calculate grades for different subjects:

think "The repetitive way - hard to maintain and error-prone"
show "=== Math Grade ==="
math_total = 95 + 87 + 92 + 88
math_average = math_total / 4
when math_average >= 90:
    show "Math grade: A (" + math_average + "%)"
when math_average >= 80:
    show "Math grade: B (" + math_average + "%)"
when math_average >= 70:
    show "Math grade: C (" + math_average + "%)"
when math_average >= 60:
    show "Math grade: D (" + math_average + "%)"
else:
    show "Math grade: F (" + math_average + "%)"

show "=== English Grade ==="
english_total = 78 + 84 + 79 + 91
english_average = english_total / 4
when english_average >= 90:
    show "English grade: A (" + english_average + "%)"
when english_average >= 80:
    show "English grade: B (" + english_average + "%)"
when english_average >= 70:
    show "English grade: C (" + english_average + "%)"
when english_average >= 60:
    show "English grade: D (" + english_average + "%)"
else:
    show "English grade: F (" + english_average + "%)"

think "This pattern repeats for every subject - lots of duplicate code!"

๐Ÿง  Why This Approach Causes Problems

For ADHD minds:

  • Too much repetitive code is overwhelming
  • Hard to track what's the same vs. what's different
  • Easy to make copy-paste errors

For autistic minds:

  • Inconsistent patterns when you need to change something
  • Difficult to maintain when logic needs updating
  • Breaks the expectation of consistent, predictable structure

For everyone:

  • Error-prone: If you need to change the grading scale, you have to update it in multiple places
  • Hard to maintain: Adding a new subject means copying and pasting all that code
  • Difficult to read: The important logic gets buried in repetition

This approach has serious problems:

  1. Lots of duplicate code - the grading logic is copied everywhere
  2. Hard to modify - if you want to change the grading scale, you have to update it in multiple places
  3. Error-prone - easy to make mistakes when copying and pasting
  4. Not reusable - can't easily use this logic in other programs

The Function Solution: Write Once, Use Everywhere

Here's how functions solve this elegantly:

think "โœ… The function way - clean and reusable"

function calculate_letter_grade(scores):
    think "This function calculates both average and letter grade"
    
    think "Step 1: Calculate average"
    total = 0
    for score in scores:
        total = total + score
    average = total / len(scores)

    think "Step 2: Determine letter grade"
    letter_grade = ""
    when average >= 90:
        letter_grade = "A"
    when average >= 80:
        letter_grade = "B"
    when average >= 70:
        letter_grade = "C"
    when average >= 60:
        letter_grade = "D"
    else:
        letter_grade = "F"

    think "Step 3: Return both pieces of information"
    return {"average": average, "letter": letter_grade}

function display_grade(subject_name, scores):
    think "This function handles displaying the grade nicely"
    
    result = calculate_letter_grade(scores)
    show "=== " + subject_name + " Grade ==="
    show subject_name + " grade: " + result["letter"] + " (" + result["average"] + "%)"

think "Now using our functions is simple and clean!"
display_grade("Math", [95, 87, 92, 88])
display_grade("English", [78, 84, 79, 91])
display_grade("Science", [92, 89, 94, 90])
display_grade("History", [85, 88, 82, 87])

๐ŸŽฏ What Just Happened?

The Magic of Functions:

  1. Write once, use many times: We defined the grading logic once, then used it for different subjects
  2. Easy to change: If we need to modify the grading scale, we only change it in one place
  3. Clear purpose: Each function has one job and does it well
  4. Readable code: The main program is now easy to understand

For different learning styles:

  • Visual learners: Think of functions like a recipe card you can use whenever you need to cook that dish
  • Kinesthetic learners: Functions are like tools in your toolbox - you pick the right tool for the job
  • Analytical minds: Functions follow the principle of "separation of concerns" - each function handles one specific task

For neurodivergent minds:

  • ADHD support: Functions break complex tasks into smaller, manageable pieces
  • Autism support: Functions provide consistent, predictable patterns you can rely on
  • Executive function support: Functions help organize code into logical, reusable chunks

// Now using the function is simple and clean let math_scores = [95, 87, 92, 88] let math_result = calculate_letter_grade(math_scores) print("Math grade: ${math_result.letter} (${math_result.average}%)")

let english_scores = [78, 84, 79, 91] let english_result = calculate_letter_grade(english_scores) print("English grade: ${english_result.letter} (${english_result.average}%)")

let science_scores = [92, 88, 94, 96, 90] let science_result = calculate_letter_grade(science_scores) print("Science grade: ${science_result.letter} (${science_result.average}%)")


Notice how much cleaner this is! We defined the grading logic once, and now we can use it for any subject with any number of scores.

## Anatomy of a Function: Understanding the Parts

### ๐Ÿ—๏ธ Basic Function Structure (For All Learning Styles)

```sona
function function_name(parameter1, parameter2):
    think "Function body - the code that does the work"
    result = parameter1 + parameter2
    return result  think "Send the answer back"

think "Using (calling) the function"
answer = function_name(5, 3)  think "answer will be 8"

๐Ÿงฉ Breaking It Down Piece by Piece

Think of functions like a machine:

  • Input: Parameters go in (like putting ingredients in a blender)
  • Process: The function body does the work (like blending)
  • Output: Return value comes out (like getting a smoothie)

Each part explained:

  • function: The keyword that tells Sona we're creating a reusable piece of code
  • function_name: The name we'll use to call this function later (choose descriptive names!)
  • (parameter1, parameter2): The inputs the function expects (like ingredients for a recipe)
  • :: Marks the start of the function body
  • Indented code: The function's work happens here
  • return: Sends a result back to whoever called the function

๐ŸŽฏ Functions Without Parameters

Not all functions need inputs - some just do a specific job:

function greet_user():
    show "Welcome to our amazing app!"
    show "We're so glad you're here!"
    show "Let's get started!"

think "Call the function - no parameters needed"
greet_user()

๐Ÿ”„ Functions Without Return Values

Some functions just do something instead of calculating a result:

function celebrate_success(achievement):
    show "๐ŸŽ‰ Congratulations! ๐ŸŽ‰"
    show "You achieved: " + achievement
    show "Keep up the great work!"

think "This function displays messages but doesn't return anything"
celebrate_success("Finished your first function!")

๐Ÿง  Memory Aids for Different Learning Styles

For visual learners:

Function = Recipe Card
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Recipe: Make Smoothieโ”‚
โ”‚ Ingredients: fruit,  โ”‚
โ”‚             liquid   โ”‚
โ”‚                     โ”‚
โ”‚ Steps:              โ”‚
โ”‚ 1. Blend fruit      โ”‚
โ”‚ 2. Add liquid       โ”‚
โ”‚ 3. Mix well         โ”‚
โ”‚                     โ”‚
โ”‚ Result: Smoothie    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

For kinesthetic learners: Think of functions like using a power drill:

  1. Set it up (define the function)
  2. Load the bit (pass parameters)
  3. Pull the trigger (call the function)
  4. Get the result (hole is drilled)

For analytical minds: Functions follow the mathematical concept f(x) = y:

  • f = function name
  • x = input parameters
  • y = return value print("We're glad you're here!") }

Parameters and Arguments: The Function's Ingredients

๐Ÿ“ The Difference Between Parameters and Arguments

This is a common source of confusion, so let's make it crystal clear:

Parameters = The placeholder names in the function definition (like variables waiting for values) Arguments = The actual values you pass when calling the function

think "Parameters are like empty boxes with labels"
function add_numbers(first_number, second_number):  think "first_number and second_number are PARAMETERS"
    result = first_number + second_number
    return result

think "Arguments are the actual values you put in the boxes"
sum = add_numbers(5, 3)  think "5 and 3 are ARGUMENTS"

๐Ÿ”„ Multiple Parameters: Building Flexible Functions

Functions can accept multiple inputs to be more useful:

function calculate_rectangle_area(length, width):
    think "This function needs two pieces of information"
    area = length * width
    return area

function introduce_person(name, age, hobby):
    think "This function needs three pieces of information"
    show "Hi! My name is " + name
    show "I am " + age + " years old"
    show "I love " + hobby + "!"

think "Using functions with multiple parameters"
room_area = calculate_rectangle_area(12, 8)
show "Room area: " + room_area + " square feet"

introduce_person("Alex", 16, "coding")

๐ŸŽฏ Parameter Order Matters!

Important for everyone, especially those with ADHD or executive function challenges:

function divide_numbers(dividend, divisor):
    think "Order is crucial here!"
    result = dividend / divisor
    return result

think "These give very different results:"
result1 = divide_numbers(10, 2)  think "10 divided by 2 = 5"
result2 = divide_numbers(2, 10)  think "2 divided by 10 = 0.2"

show "Result 1: " + result1
show "Result 2: " + result2

๐Ÿ’ก Pro tip: Use descriptive parameter names to make order obvious:

function calculate_discount(original_price, discount_percentage):
    think "Clear names make the order obvious"
    discount_amount = original_price * (discount_percentage / 100)
    final_price = original_price - discount_amount
    return final_price

sale_price = calculate_discount(100, 20)  think "Easy to understand: $100 with 20% off"

๐Ÿง  Memory Techniques for Parameters

For visual learners: Think of parameters like labeled containers:

Function: make_sandwich
Container 1: [bread_type]
Container 2: [filling]
Container 3: [condiment]

Call: make_sandwich("wheat", "turkey", "mayo")

For kinesthetic learners: Parameters are like slots in a machine - you need to put the right things in the right slots in the right order.

For analytical minds: Parameters define the function's signature - they specify exactly what inputs the function expects and in what order.

Return Values: Getting Results Back

๐Ÿ”„ What Are Return Values?

A return value is the result that a function sends back to the code that called it. Think of it like this:

Real-world analogy:

  • You go to a bakery (call a function)
  • You order a cake (pass parameters)
  • The baker makes it (function executes)
  • You get the cake (return value)
function bake_cake(flavor, size):
    think "Function does the work"
    cake = "A delicious " + size + " " + flavor + " cake"
    return cake  think "Send the result back"

think "Call the function and store the result"
my_cake = bake_cake("chocolate", "medium")
show "I got: " + my_cake

๐ŸŽฏ Functions With vs Without Return Values

Functions that return values:

function calculate_tip(bill_amount, tip_percentage):
    tip = bill_amount * (tip_percentage / 100)
    return tip  think "Send the calculated tip back"

function get_full_name(first_name, last_name):
    full_name = first_name + " " + last_name
    return full_name  think "Send the combined name back"

think "Use the returned values"
tip_amount = calculate_tip(50, 18)
customer_name = get_full_name("Sarah", "Johnson")
show customer_name + " should tip $" + tip_amount

Functions that don't return values (they just do things):

function print_receipt(customer_name, total_amount):
    show "=== RECEIPT ==="
    show "Customer: " + customer_name
    show "Total: $" + total_amount
    show "Thank you for your business!"
    think "No return statement - this function just prints"

function save_user_preferences(theme, language, notifications):
    think "Save settings to file (implementation details omitted)"
    show "Preferences saved:"
    show "  Theme: " + theme
    show "  Language: " + language
    show "  Notifications: " + notifications
    think "No return statement - this function just saves data"

think "Call these functions - they do their job but don't return anything"
print_receipt("Alex Smith", 75.50)
save_user_preferences("dark", "English", "enabled")

๐Ÿง  Understanding Return Values for Different Learning Styles

For visual learners:

Function Call:        [Input] โ†’ [Function] โ†’ [Output]
calculate_tip(50, 18):  [50, 18] โ†’ [tip calculator] โ†’ [9.0]

For kinesthetic learners: Think of return values like using a vending machine:

  1. Put in money (parameters)
  2. Press a button (call function)
  3. Get your snack (return value)

For analytical minds: Return values allow functions to transform input data into output data, enabling functional composition and data flow through your program.

๐Ÿ’ก Multiple Return Values

Sometimes you need to return more than one piece of information:

function analyze_text(text):
    word_count = len(text.split())
    character_count = len(text)
    first_word = text.split()[0]
    
    think "Return multiple values as a dictionary"
    return {
        "words": word_count,
        "characters": character_count,
        "first_word": first_word
    }

think "Use the returned dictionary"
text_analysis = analyze_text("Hello world from Sona!")
show "Word count: " + text_analysis["words"]
show "Character count: " + text_analysis["characters"]
show "First word: " + text_analysis["first_word"]

๐Ÿšจ Common Mistakes with Return Values

Mistake 1: Forgetting to capture the return value

function double_number(num):
    return num * 2

think "โŒ Wrong - the result is lost"
double_number(5)  think "Result goes nowhere"

think "โœ… Correct - capture the result"
result = double_number(5)
show "Double of 5 is: " + result

Mistake 2: Using return in the wrong place

function process_numbers(numbers):
    for num in numbers:
        when num < 0:
            return "Found negative number"  think "This exits the function immediately"
        show "Processing: " + num
    return "All numbers processed"

think "This function stops at the first negative number"
result = process_numbers([1, 2, -3, 4, 5])
## Variable Scope: Where Variables Live

### ๐Ÿ  Understanding Scope: Local vs Global Variables

**Scope** determines where in your program a variable can be accessed. Think of it like rooms in a house:

**Global scope** = The main living area (accessible everywhere)
**Local scope** = Individual bedrooms (only accessible inside that room)

```sona
think "Global variable - accessible everywhere"
game_score = 0  think "This lives in the 'main living area'"

function add_points(points):
    think "Local variable - only accessible inside this function"
    bonus = points * 2  think "This lives in the 'function's bedroom'"
    
    think "We can access global variables from inside functions"
    global game_score
    game_score = game_score + bonus
    
    show "Added " + bonus + " points!"
    show "New score: " + game_score

function reset_game():
    think "Another function - has its own local scope"
    global game_score
    game_score = 0
    show "Game reset! Score is now: " + game_score

think "Using the functions"
add_points(10)  think "bonus variable exists only during this function call"
add_points(5)   think "bonus variable is created fresh each time"
reset_game()

think "โŒ This would cause an error - bonus doesn't exist outside the function"
think "show bonus  # This would fail!"

๐ŸŽฏ Why Scope Matters (Especially for Neurodivergent Minds)

For ADHD support:

  • Reduces overwhelm: You only need to think about variables that are relevant to your current function
  • Prevents confusion: Variables with the same name in different functions don't interfere with each other
  • Clearer focus: Each function has its own "workspace" that's separate from everything else

For autistic support:

  • Predictable boundaries: Variables have clear, consistent rules about where they can be accessed
  • Reduced interference: Changes in one function don't unexpectedly affect another function
  • Logical organization: Code is organized into clear, separate sections

๐Ÿ—๏ธ Local Variables: Function-Specific Storage

function calculate_pizza_cost(size, toppings):
    think "These variables only exist inside this function"
    base_price = 0
    
    when size == "small":
        base_price = 10
    when size == "medium":
        base_price = 15
    when size == "large":
        base_price = 20
    
    topping_cost = len(toppings) * 2
    total_cost = base_price + topping_cost
    
    think "base_price, topping_cost, and total_cost are LOCAL variables"
    return total_cost

function calculate_burger_cost(size, extras):
    think "These variables are separate from the pizza function"
    base_price = 0  think "This is a DIFFERENT base_price variable"
    
    when size == "small":
        base_price = 8
    when size == "medium":
        base_price = 12
    when size == "large":
        base_price = 16
    
    extra_cost = len(extras) * 1.5
    total_cost = base_price + extra_cost
    
    return total_cost

think "Each function has its own separate variables"
pizza_price = calculate_pizza_cost("medium", ["pepperoni", "mushrooms"])
burger_price = calculate_burger_cost("large", ["cheese", "bacon"])

show "Pizza: $" + pizza_price
show "Burger: $" + burger_price

๐ŸŒ Global Variables: Shared Storage

think "Global variables - accessible from anywhere"
restaurant_name = "Sona's Coding Cafe"
total_orders = 0
daily_revenue = 0

function process_order(item, price):
    think "Access global variables from inside the function"
    global total_orders, daily_revenue
    
    total_orders = total_orders + 1
    daily_revenue = daily_revenue + price
    
    show "Order #" + total_orders + ": " + item + " - $" + price
    show "Daily revenue: $" + daily_revenue

function display_restaurant_info():
    think "Global variables are accessible here too"
    show "Welcome to " + restaurant_name
    show "Orders processed today: " + total_orders
    show "Revenue today: $" + daily_revenue

think "Using global variables"
display_restaurant_info()
process_order("Pizza", 15)
process_order("Burger", 12)
display_restaurant_info()

๐Ÿ’ก Best Practices for Scope

For beginners (ages 12-18):

  1. Start with local variables - they're easier to understand and debug
  2. Use global variables sparingly - only for data that truly needs to be shared
  3. Give variables clear names - user_score is better than score

For experienced developers (ages 19-55+):

  1. Prefer local scope - it makes code more predictable and testable
  2. Use global variables for constants - like PI = 3.14159
  3. Consider function parameters - instead of global variables for data sharing

๐Ÿšจ Common Scope Mistakes

Mistake 1: Forgetting to declare global variables

counter = 0

function increment():
    think "โŒ This creates a NEW local variable instead of modifying the global one"
    counter = counter + 1  think "This will cause an error!"

function increment_correct():
    think "โœ… This correctly modifies the global variable"
    global counter
    counter = counter + 1

increment_correct()
show "Counter: " + counter

Mistake 2: Assuming local variables persist

function do_something():
    temp_value = 42
    show "Inside function: " + temp_value

do_something()
think "โŒ This would cause an error - temp_value no longer exists"
think "show temp_value  # This would fail!"

// Using them
display_welcome_banner()
save_user_preferences("dark", "english", true)

Writing Your First Custom Functions

Function 1: Text Utilities

// Function to format a name properly
func format_name(first_name, last_name) {
    // Capitalize first letter of each name, lowercase the rest
    let formatted_first = first_name.substring(0, 1).upper() + first_name.substring(1).lower()
    let formatted_last = last_name.substring(0, 1).upper() + last_name.substring(1).lower()
    return formatted_first + " " + formatted_last
}

// Function to create initials
func get_initials(first_name, last_name) {
    let first_initial = first_name.substring(0, 1).upper()
    let last_initial = last_name.substring(0, 1).upper()
    return first_initial + "." + last_initial + "."
}

// Function to validate email format (simplified)
func is_valid_email(email) {
    let has_at = email.contains("@")
    let has_dot = email.contains(".")
    let not_too_short = email.length >= 5

    return has_at && has_dot && not_too_short
}

// Testing our text utilities
let formatted = format_name("JOHN", "smith")
print("Formatted name: ${formatted}")  // "John Smith"

let initials = get_initials("Alice", "Johnson")
print("Initials: ${initials}")  // "A.J."

let email_valid = is_valid_email("[email protected]")
print("Email valid: ${email_valid}")  // true

Function 2: Math Utilities

// Function to calculate compound interest
func calculate_compound_interest(principal, rate, time, compounds_per_year) {
    let base = 1 + (rate / compounds_per_year)
    let exponent = compounds_per_year * time
    let final_amount = principal * (base ^ exponent)
    let interest_earned = final_amount - principal

    return {
        "final_amount": final_amount,
        "interest_earned": interest_earned,
        "principal": principal
    }
}

// Function to determine if a number is prime
func is_prime(number) {
    if number < 2 {
        return false
    }

    for i in range(2, number) {
        if number % i == 0 {
            return false  // Found a divisor, not prime
        }
    }

    return true  // No divisors found, it's prime
}

// Function to convert temperature
func convert_temperature(temp, from_unit, to_unit) {
    // First convert to Celsius
    let celsius = 0
    if from_unit == "fahrenheit" {
        celsius = (temp - 32) * 5 / 9
    } else if from_unit == "kelvin" {
        celsius = temp - 273.15
    } else {
        celsius = temp  // Already in Celsius
    }

    // Then convert to target unit
    if to_unit == "fahrenheit" {
        return celsius * 9 / 5 + 32
    } else if to_unit == "kelvin" {
        return celsius + 273.15
    } else {
        return celsius  // Return Celsius
    }
}

// Testing our math utilities
let investment = calculate_compound_interest(1000, 0.05, 10, 12)
print("Investment result: $${investment.final_amount}")

print("Is 17 prime? ${is_prime(17)}")  // true
print("Is 20 prime? ${is_prime(20)}")  // false

let temp_f = convert_temperature(25, "celsius", "fahrenheit")
print("25ยฐC = ${temp_f}ยฐF")  // 77ยฐF

Function 3: Date and Time Utilities

// Function to calculate age from birth year
func calculate_age(birth_year) {
    let current_year = 2024  // In a real app, this would be dynamic
    return current_year - birth_year
}

// Function to determine day of week (simplified)
func get_day_of_week(day_number) {
    let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
    return days[day_number - 1]  // day_number is 1-7
}

// Function to format time in 12-hour format
func format_time_12hour(hour, minute) {
    let am_pm = "AM"
    let display_hour = hour

    if hour == 0 {
        display_hour = 12
    } else if hour > 12 {
        display_hour = hour - 12
        am_pm = "PM"
    } else if hour == 12 {
        am_pm = "PM"
    }

    let minute_str = minute
    if minute < 10 {
        minute_str = "0" + minute
    }

    return "${display_hour}:${minute_str} ${am_pm}"
}

// Testing date/time utilities
let age = calculate_age(1995)
print("Born in 1995, current age: ${age}")

let day = get_day_of_week(3)
print("Day 3 is: ${day}")  // Wednesday

let formatted_time = format_time_12hour(14, 30)
print("14:30 in 12-hour format: ${formatted_time}")  // 2:30 PM

Advanced Function Techniques

Default Parameters: Making Functions More Flexible

Sometimes you want to provide default values for parameters:

// Function with default parameters
func greet_user(name, greeting = "Hello", punctuation = "!") {
    return "${greeting}, ${name}${punctuation}"
}

// Using the function with different parameter combinations
print(greet_user("Alice"))                           // "Hello, Alice!"
print(greet_user("Bob", "Hi"))                       // "Hi, Bob!"
print(greet_user("Charlie", "Welcome", "."))         // "Welcome, Charlie."
print(greet_user("Diana", punctuation = "!!!"))      // "Hello, Diana!!!"

Variable Number of Arguments

Sometimes you don't know how many arguments you'll receive:

// Function that accepts any number of numbers
func calculate_statistics(numbers...) {
    if numbers.length == 0 {
        return {"error": "No numbers provided"}
    }

    let total = 0
    let min_value = numbers[0]
    let max_value = numbers[0]

    for num in numbers {
        total = total + num
        if num < min_value {
            min_value = num
        }
        if num > max_value {
            max_value = num
        }
    }

    let average = total / numbers.length

    return {
        "count": numbers.length,
        "total": total,
        "average": average,
        "min": min_value,
        "max": max_value
    }
}

// Using with different numbers of arguments
let stats1 = calculate_statistics(10, 20, 30)
let stats2 = calculate_statistics(5, 15, 25, 35, 45, 55)
let stats3 = calculate_statistics(100)

print("Stats for [10, 20, 30]: Average = ${stats1.average}")
print("Stats for larger set: Min = ${stats2.min}, Max = ${stats2.max}")

Functions That Return Functions (Advanced)

This is getting fancy, but it's useful for creating specialized functions:

// Function factory - creates customized greeting functions
func create_greeter(greeting_style) {
    if greeting_style == "formal" {
        return func(name) {
            return "Good day, ${name}. How may I assist you?"
        }
    } else if greeting_style == "casual" {
        return func(name) {
            return "Hey ${name}! What's up?"
        }
    } else if greeting_style == "professional" {
        return func(name) {
            return "Hello ${name}, welcome to our service."
        }
    } else {
        return func(name) {
            return "Hi ${name}!"
        }
    }
}

// Creating specialized greeting functions
let formal_greeter = create_greeter("formal")
let casual_greeter = create_greeter("casual")

print(formal_greeter("Dr. Smith"))  // "Good day, Dr. Smith. How may I assist you?"
print(casual_greeter("Alex"))       // "Hey Alex! What's up?"

Understanding Variable Scope: Where Variables Live

Local Scope: Variables Inside Functions

Variables created inside functions only exist within that function:

func calculate_tax(income, tax_rate) {
    let tax_amount = income * tax_rate  // This variable only exists in this function
    let after_tax = income - tax_amount

    print("Tax calculation:")
    print("  Income: $${income}")
    print("  Tax: $${tax_amount}")
    print("  After tax: $${after_tax}")

    return after_tax
}

let net_income = calculate_tax(50000, 0.25)

// โŒ This would cause an error - tax_amount doesn't exist outside the function
// print(tax_amount)

Global Scope: Variables Available Everywhere

Variables created outside functions are available everywhere:

let company_name = "Acme Corp"  // Global variable
let tax_rate = 0.25             // Global variable

func generate_paycheck(employee_name, salary) {
    let gross_pay = salary / 12  // Local variable
    let tax = gross_pay * tax_rate  // Uses global tax_rate
    let net_pay = gross_pay - tax

    return {
        "company": company_name,     // Uses global company_name
        "employee": employee_name,
        "gross": gross_pay,
        "tax": tax,
        "net": net_pay
    }
}

let paycheck = generate_paycheck("Alice Johnson", 60000)
print("${paycheck.company} paycheck for ${paycheck.employee}")
print("Net pay: $${paycheck.net}")

Best Practices for Scope

  1. Keep variables as local as possible - easier to debug and understand
  2. Use global variables sparingly - only for truly global configuration
  3. Pass data through parameters instead of relying on global variables
  4. Return values explicitly rather than modifying global state
// โœ… Good: Clear parameter passing
func calculate_discount(price, customer_type) {
    let discount_rate = 0
    if customer_type == "premium" {
        discount_rate = 0.15
    } else if customer_type == "regular" {
        discount_rate = 0.05
    }

    return price * (1 - discount_rate)
}

// โŒ Not as good: Relies on global state
let global_discount_rate = 0.10
func calculate_discount_global(price) {
    return price * (1 - global_discount_rate)  // What if global_discount_rate changes?
}

Organizing Functions with Modules: Your Code Toolbox

๐Ÿ“ฆ What Are Modules?

Imagine you have a toolbox with different compartments:

  • Hammer compartment: All your hammers and nail tools
  • Screwdriver compartment: All your screwdrivers and screw-related tools
  • Measuring compartment: All your rulers, levels, and measuring tools

Modules are like these compartments for your code! They help you organize related functions together.

think "Instead of having all functions in one huge file..."
think "We organize them into logical groups (modules)"

think "Example: math_tools.sona - All math-related functions"
function add(a, b):
    return a + b

function multiply(a, b):
    return a * b

function calculate_area(length, width):
    return length * width

think "Example: text_tools.sona - All text-related functions"
function make_uppercase(text):
    return text.upper()

function count_words(text):
    return len(text.split())

function make_title_case(text):
    words = text.split()
    title_words = []
    for word in words:
        title_word = word[0].upper() + word[1:].lower()
        title_words.append(title_word)
    return " ".join(title_words)

๐Ÿง  Why Modules Are Essential for All Learning Styles

For ADHD minds:

  • Reduces overwhelm: Instead of scrolling through hundreds of functions, you find what you need quickly
  • Clear organization: Related functions are grouped together logically
  • Easier focus: You can work on one module at a time without distractions

For autistic minds:

  • Predictable structure: You know where to find specific types of functions
  • Consistent patterns: Each module follows the same organizational principles
  • Logical categories: Functions are grouped by their purpose, not randomly

For everyone:

  • Easier maintenance: When you need to fix a text function, you know to look in the text module
  • Code reuse: You can use the same modules in multiple projects
  • Team collaboration: Different people can work on different modules

๐Ÿ—๏ธ How to Think About Modules

Real-world analogy:

  • Library: Books are organized by subject (fiction, science, history)
  • Grocery store: Items are organized by category (produce, dairy, meat)
  • School: Classes are organized by subject (math, English, science)

Code modules work the same way:

  • math_utils.sona: Mathematical functions
  • string_utils.sona: Text manipulation functions
  • validation_utils.sona: Input validation functions
  • file_utils.sona: File handling functions

๐Ÿ’ก Module Best Practices

For beginners (ages 12-18):

  1. Start small: Group 3-5 related functions together
  2. Use clear names: math_helpers.sona is better than stuff.sona
  3. Keep it simple: Don't overcomplicate the organization

For experienced developers (ages 19-55+):

  1. Single responsibility: Each module should have one clear purpose
  2. Logical grouping: Group by functionality, not by when you wrote them
  3. Consistent naming: Use the same naming conventions across all modules

Building Your Personal Utility Library

Now let's create a comprehensive utility library that you can use in all your future projects. We'll build it step by step, explaining each function clearly.

Part 1: String Utilities Module

think "string_utils.sona - String manipulation utilities"

function title_case(text):
    think "Convert 'hello world' to 'Hello World'"
    words = text.split(" ")
    title_words = []

    for word in words:
        when len(word) > 0:
            title_word = word[0].upper() + word[1:].lower()
            title_words.append(title_word)

    return " ".join(title_words)

function slug_from_title(title):
    think "Convert 'My Blog Post Title!' to 'my-blog-post-title'"
    clean = title.lower()
    allowed_chars = "abcdefghijklmnopqrstuvwxyz0123456789 "
    filtered = ""

    for char in clean:
        when char in allowed_chars:
            filtered = filtered + char

    return filtered.strip().replace(" ", "-")

function truncate_text(text, max_length, suffix = "..."):
    when len(text) <= max_length:
        return text

    truncated = text[:max_length - len(suffix)]
    return truncated + suffix

function count_words(text):
    words = text.strip().split(" ")
    non_empty_words = []

    for word in words:
        when len(word) > 0:
            non_empty_words.append(word)

    return len(non_empty_words)

function mask_sensitive_data(text, visible_chars = 4):
    when len(text) <= visible_chars:
        return "*" * len(text)

    visible_part = text[:visible_chars]
    hidden_part = "*" * (len(text) - visible_chars)
    return visible_part + hidden_part

think "Testing our string utilities"
show title_case("hello world from sona")  think "Hello World From Sona"
show slug_from_title("My First Blog Post!")  think "my-first-blog-post"
show truncate_text("This is a very long sentence", 10)  think "This is..."
show count_words("Hello world from Sona")  think "4"
show mask_sensitive_data("1234567890")  think "1234******"
let visible_part = text.substring(text.length - visible_chars)
let mask_length = text.length - visible_chars
return "*" * mask_length + visible_part

}

// Example usage of string utilities print("Title case: " + title_case("hello world programming")) print("Slug: " + slug_from_title("My Amazing Blog Post!")) print("Truncated: " + truncate_text("This is a very long text that needs truncating", 20)) print("Word count: " + count_words("Hello world, this is a test")) print("Masked card: " + mask_sensitive_data("4532123456789012"))


### Part 2: Math Utilities Module

```sona
think "math_utils.sona - Mathematical utilities"

function calculate_compound_interest(principal, rate, time, compound_frequency = 1):
    think "Calculate compound interest: A = P(1 + r/n)^(nt)"
    amount = principal * ((1 + rate / compound_frequency) ** (compound_frequency * time))
    interest = amount - principal
    return {"final_amount": amount, "interest_earned": interest}

function is_prime(number):
    think "Check if a number is prime"
    when number < 2:
        return False
    
    for i in range(2, int(number ** 0.5) + 1):
        when number % i == 0:
            return False
    
    return True

function factorial(n):
    think "Calculate factorial: n! = n ร— (n-1) ร— (n-2) ร— ... ร— 1"
    when n <= 1:
        return 1
    
    result = 1
    for i in range(2, n + 1):
        result = result * i
    
    return result

function convert_temperature(celsius, to_unit):
    think "Convert Celsius to other temperature units"
    when to_unit == "fahrenheit":
        return celsius * 9 / 5 + 32
    when to_unit == "kelvin":
        return celsius + 273.15
    else:
        return celsius  think "Return Celsius if unknown unit"

function calculate_distance(x1, y1, x2, y2):
    think "Calculate distance between two points using Pythagorean theorem"
    dx = x2 - x1
    dy = y2 - y1
    return (dx * dx + dy * dy) ** 0.5

function percentage_change(old_value, new_value):
    think "Calculate percentage change between two values"
    when old_value == 0:
        return 0  think "Avoid division by zero"
    
    change = ((new_value - old_value) / old_value) * 100
    return change

think "Testing our math utilities"
investment = calculate_compound_interest(1000, 0.05, 10, 12)
show "Investment result: $" + str(investment["final_amount"])

show "Is 17 prime? " + str(is_prime(17))  think "True"
show "Is 20 prime? " + str(is_prime(20))  think "False"

temp_f = convert_temperature(25, "fahrenheit")
show "25ยฐC = " + str(temp_f) + "ยฐF"  think "77ยฐF"

### Part 3: Validation Utilities Module

```sona
think "validation_utils.sona - Input validation utilities"

function is_valid_email(email):
    think "Basic email validation - checks for @ symbol and dot"
    when "@" not in email:
        return False
    
    parts = email.split("@")
    when len(parts) != 2:
        return False
    
    local_part = parts[0]
    domain_part = parts[1]
    
    when len(local_part) == 0 or len(domain_part) == 0:
        return False
    
    when "." not in domain_part:
        return False
    
    return True

function is_valid_phone(phone):
    think "Validate phone number format (basic check)"
    digits_only = ""
    
    for char in phone:
        when char.isdigit():
            digits_only = digits_only + char
    
    think "Phone should have 10 digits"
    return len(digits_only) == 10

function is_strong_password(password):
    think "Check if password meets security requirements"
    when len(password) < 8:
        return False
    
    has_upper = False
    has_lower = False
    has_digit = False
    has_special = False
    special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
    
    for char in password:
        when char.isupper():
            has_upper = True
        when char.islower():
            has_lower = True
        when char.isdigit():
            has_digit = True
        when char in special_chars:
            has_special = True
    
    return has_upper and has_lower and has_digit and has_special

function validate_age(age):
    think "Check if age is valid"
    try:
        age_num = int(age)
        return 0 <= age_num <= 150
    except:
        return False

function is_valid_username(username):
    think "Username should be 3-20 characters, letters, numbers, underscore only"
    when len(username) < 3 or len(username) > 20:
        return False
    
    allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
    
    for char in username:
        when char not in allowed_chars:
            return False
    
    return True

think "Testing our validation utilities"
show "Valid email? " + str(is_valid_email("[email protected]"))  think "True"
show "Valid phone? " + str(is_valid_phone("(555) 123-4567"))  think "True"
show "Strong password? " + str(is_strong_password("MyPass123!"))  think "True"
show "Valid age? " + str(validate_age("25"))  think "True"
### Part 4: Data Utilities Module

```sona
think "data_utils.sona - Data manipulation utilities"

function sort_list(items, reverse = False):
    think "Simple bubble sort implementation"
    sorted_items = items.copy()
    n = len(sorted_items)
    
    for i in range(n):
        for j in range(0, n - i - 1):
            should_swap = False
            
            when reverse:
                should_swap = sorted_items[j] < sorted_items[j + 1]
            else:
                should_swap = sorted_items[j] > sorted_items[j + 1]
            
            when should_swap:
                temp = sorted_items[j]
                sorted_items[j] = sorted_items[j + 1]
                sorted_items[j + 1] = temp
    
    return sorted_items

function remove_duplicates(items):
    think "Remove duplicate items from a list"
    unique_items = []
    
    for item in items:
        when item not in unique_items:
            unique_items.append(item)
    
    return unique_items

function group_by_property(items, property_name):
    think "Group items by a specific property"
    groups = {}
    
    for item in items:
        key = item[property_name]
        when key not in groups:
            groups[key] = []
        groups[key].append(item)
    
    return groups

function calculate_average(numbers):
    think "Calculate the average of a list of numbers"
    when len(numbers) == 0:
        return 0
    
    total = sum(numbers)
    return total / len(numbers)

function find_min_max(numbers):
    think "Find minimum and maximum values in a list"
    when len(numbers) == 0:
        return {"min": None, "max": None}
    
    min_val = numbers[0]
    max_val = numbers[0]
    
    for num in numbers:
        when num < min_val:
            min_val = num
        when num > max_val:
            max_val = num
    
    return {"min": min_val, "max": max_val}

function filter_by_criteria(items, criteria_function):
    think "Filter items based on a criteria function"
    filtered_items = []
    
    for item in items:
        when criteria_function(item):
            filtered_items.append(item)
    
    return filtered_items

think "Testing our data utilities"
numbers = [64, 34, 25, 12, 22, 11, 90]
show "Sorted numbers: " + str(sort_list(numbers))

words = ["hello", "world", "hello", "sona", "world"]
show "Unique words: " + str(remove_duplicates(words))

students = [
    {"name": "Alice", "grade": "A"},
    {"name": "Bob", "grade": "B"},
    {"name": "Charlie", "grade": "A"},
    {"name": "Diana", "grade": "B"}
]
grouped = group_by_property(students, "grade")
show "Grouped by grade: " + str(grouped)

scores = [85, 92, 78, 96, 89]
show "Average score: " + str(calculate_average(scores))

min_max = find_min_max(scores)
show "Min: " + str(min_max["min"]) + ", Max: " + str(min_max["max"])

Part 3: Validation Utilities Module

// validation_utils.sona - Input validation utilities

func validate_email(email) {
    // Basic email validation
    let result = {
        "valid": false,
        "errors": []
    }

    if email.length == 0 {
        result.errors = result.errors + ["Email cannot be empty"]
        return result
    }

    if !email.contains("@") {
        result.errors = result.errors + ["Email must contain @ symbol"]
    }

    if email.count("@") != 1 {
        result.errors = result.errors + ["Email must contain exactly one @ symbol"]
    }

    let parts = email.split("@")
    if parts.length == 2 {
        let local_part = parts[0]
        let domain_part = parts[1]

        if local_part.length == 0 {
            result.errors = result.errors + ["Email local part cannot be empty"]
        }

        if domain_part.length == 0 {
            result.errors = result.errors + ["Email domain cannot be empty"]
        }

        if !domain_part.contains(".") {
            result.errors = result.errors + ["Email domain must contain a dot"]
        }
    }

    result.valid = result.errors.length == 0
    return result
}

func validate_password(password) {
    let result = {
        "valid": false,
        "errors": [],
        "strength": "weak"
    }

    if password.length < 8 {
        result.errors = result.errors + ["Password must be at least 8 characters"]
    }

    let has_upper = false
    let has_lower = false
    let has_number = false
    let has_special = false

    for char in password {
        if char >= "A" && char <= "Z" {
            has_upper = true
        } else if char >= "a" && char <= "z" {
            has_lower = true
        } else if char >= "0" && char <= "9" {
            has_number = true
        } else {
            has_special = true
        }
    }

    if !has_upper {
        result.errors = result.errors + ["Password must contain uppercase letters"]
    }

    if !has_lower {
        result.errors = result.errors + ["Password must contain lowercase letters"]
    }

    if !has_number {
        result.errors = result.errors + ["Password must contain numbers"]
    }

    // Determine strength
    let criteria_met = 0
    if password.length >= 8 { criteria_met = criteria_met + 1 }
    if has_upper { criteria_met = criteria_met + 1 }
    if has_lower { criteria_met = criteria_met + 1 }
    if has_number { criteria_met = criteria_met + 1 }
    if has_special { criteria_met = criteria_met + 1 }

    if criteria_met >= 5 {
        result.strength = "strong"
    } else if criteria_met >= 3 {
        result.strength = "medium"
    }

    result.valid = result.errors.length == 0
    return result
}

func validate_phone_number(phone) {
    // Remove common formatting characters
    let cleaned = phone.replace("-", "").replace(" ", "").replace("(", "").replace(")", "")

    let result = {
        "valid": false,
        "formatted": "",
        "errors": []
    }

    if cleaned.length != 10 {
        result.errors = result.errors + ["Phone number must be 10 digits"]
        return result
    }

    // Check if all characters are digits
    for char in cleaned {
        if char < "0" || char > "9" {
            result.errors = result.errors + ["Phone number must contain only digits"]
            return result
        }
    }

    // Format as (XXX) XXX-XXXX
    result.formatted = "(${cleaned.substring(0, 3)}) ${cleaned.substring(3, 6)}-${cleaned.substring(6, 10)}"
    result.valid = true
    return result
}

// Example usage of validation utilities
let email_check = validate_email("[email protected]")
print("Email valid: ${email_check.valid}")

let password_check = validate_password("MySecure123!")
print("Password strength: ${password_check.strength}")

let phone_check = validate_phone_number("555-123-4567")
print("Phone formatted: ${phone_check.formatted}")

Part 4: Data Utilities Module

// data_utils.sona - Data manipulation utilities

func remove_duplicates(array) {
    let unique_items = []

    for item in array {
        let already_exists = false
        for existing in unique_items {
            if item == existing {
                already_exists = true
                break
            }
        }

        if !already_exists {
            unique_items = unique_items + [item]
        }
    }

    return unique_items
}

func sort_array(array, ascending = true) {
    // Simple bubble sort (not efficient for large arrays, but works for learning)
    let sorted_array = array  // Make a copy
    let n = sorted_array.length

    for i in range(0, n - 1) {
        for j in range(0, n - i - 1) {
            let should_swap = false

            if ascending {
                should_swap = sorted_array[j] > sorted_array[j + 1]
            } else {
                should_swap = sorted_array[j] < sorted_array[j + 1]
            }

            if should_swap {
                let temp = sorted_array[j]
                sorted_array[j] = sorted_array[j + 1]
                sorted_array[j + 1] = temp
            }
        }
    }

    return sorted_array
}

func group_by_property(array, property_name) {
    let groups = {}

    for item in array {
        let key = item[property_name]

        if groups[key] == null {
            groups[key] = []
        }

        groups[key] = groups[key] + [item]
    }

    return groups
}

func filter_array(array, condition_func) {
    let filtered = []

    for item in array {
        if condition_func(item) {
            filtered = filtered + [item]
        }
    }

    return filtered
}

func map_array(array, transform_func) {
    let mapped = []

    for item in array {
        mapped = mapped + [transform_func(item)]
    }

    return mapped
}

func find_min_max(array) {
    if array.length == 0 {
        return {"error": "Array is empty"}
    }

    let min_val = array[0]
    let max_val = array[0]

    for item in array {
        if item < min_val {
            min_val = item
        }
        if item > max_val {
            max_val = item
        }
    }

    return {"min": min_val, "max": max_val}
}

// Example usage of data utilities
let numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
print("Original: " + numbers)
print("Unique: " + remove_duplicates(numbers))
print("Sorted: " + sort_array(numbers))

let students = [
    {"name": "Alice", "grade": "A", "age": 20},
    {"name": "Bob", "grade": "B", "age": 19},
    {"name": "Charlie", "grade": "A", "age": 21}
]

let by_grade = group_by_property(students, "grade")
print("Grouped by grade: " + by_grade)

let min_max = find_min_max(numbers)
print("Min: ${min_max.min}, Max: ${min_max.max}")

Project: Complete Personal Utility Library

Let's combine all our utilities into a comprehensive library with a demo application:

// personal_utilities.sona - Complete utility library demonstration

// Import all our utility modules (in a real Sona program with modules)
// import string_utils
// import math_utils
// import validation_utils
// import data_utils

func main() {
    print("๐Ÿ› ๏ธ  Personal Utility Library Demo ๐Ÿ› ๏ธ")
    print("=" * 50)

    // String utilities demo
    print("\n๐Ÿ“ String Utilities:")
    let sample_text = "hello world programming"
    print("Original: '${sample_text}'")
    print("Title case: '${title_case(sample_text)}'")
    print("Slug: '${slug_from_title(sample_text + "!")}'")
    print("Truncated: '${truncate_text("This is a very long sentence that needs to be shortened", 25)}'")
    print("Word count: ${count_words("The quick brown fox jumps over the lazy dog")}")
    print("Masked: '${mask_sensitive_data("1234567890123456", 4)}'")

    // Math utilities demo
    print("\n๐Ÿ”ข Math Utilities:")
    print("Factorial of 6: ${factorial(6)}")
    print("First 8 Fibonacci numbers: ${fibonacci(8)}")
    print("GCD of 56 and 42: ${greatest_common_divisor(56, 42)}")
    print("Is 496 a perfect number? ${is_perfect_number(496)}")
    print("Prime factors of 84: ${prime_factors(84)}")

    // Validation utilities demo
    print("\nโœ… Validation Utilities:")
    let test_email = "[email protected]"
    let email_result = validate_email(test_email)
    print("Email '${test_email}' is valid: ${email_result.valid}")

    let test_password = "SecureP@ss123"
    let password_result = validate_password(test_password)
    print("Password strength: ${password_result.strength}")

    let test_phone = "555-123-4567"
    let phone_result = validate_phone_number(test_phone)
    print("Phone formatted: ${phone_result.formatted}")

    // Data utilities demo
    print("\n๐Ÿ“Š Data Utilities:")
    let sample_data = [5, 2, 8, 2, 1, 9, 5, 3]
    print("Original data: ${sample_data}")
    print("Unique values: ${remove_duplicates(sample_data)}")
    print("Sorted ascending: ${sort_array(sample_data)}")
    print("Sorted descending: ${sort_array(sample_data, false)}")

    let min_max_result = find_min_max(sample_data)
    print("Min: ${min_max_result.min}, Max: ${min_max_result.max}")

    // Interactive utility tester
    run_interactive_tester()
}

func run_interactive_tester() {
    print("\n" + "=" * 50)
    print("๐ŸŽฎ Interactive Utility Tester")
    print("=" * 50)

    let running = true

    while running {
        print("\nChoose a utility to test:")
        print("1. ๐Ÿ“ String utilities")
        print("2. ๐Ÿ”ข Math utilities")
        print("3. โœ… Validation utilities")
        print("4. ๐Ÿ“Š Data utilities")
        print("5. ๐Ÿšช Exit")

        let choice = parse_number(input())

        if choice == 1 {
            test_string_utilities()
        } else if choice == 2 {
            test_math_utilities()
        } else if choice == 3 {
            test_validation_utilities()
        } else if choice == 4 {
            test_data_utilities()
        } else if choice == 5 {
            running = false
            print("๐Ÿ‘‹ Thanks for testing the utilities!")
        } else {
            print("โŒ Invalid choice. Please select 1-5.")
        }
    }
}

func test_string_utilities() {
    print("\n๐Ÿ“ String Utilities Tester")
    print("Enter some text to manipulate:")
    let text = input()

    print("\nResults:")
    print("Title case: '${title_case(text)}'")
    print("Slug: '${slug_from_title(text)}'")
    print("Truncated (20 chars): '${truncate_text(text, 20)}'")
    print("Word count: ${count_words(text)}")
    print("Masked (show last 3): '${mask_sensitive_data(text, 3)}'")
}

func test_math_utilities() {
    print("\n๐Ÿ”ข Math Utilities Tester")
    print("Enter a number:")
    let num = parse_number(input())

    print("\nResults:")
    print("Factorial: ${factorial(num)}")
    print("Is prime? ${is_prime(num)}")
    print("Is perfect? ${is_perfect_number(num)}")

    if num <= 20 {
        print("Prime factors: ${prime_factors(num)}")
    } else {
        print("Prime factors: (too large to display)")
    }

    if num <= 15 {
        print("Fibonacci sequence: ${fibonacci(num)}")
    } else {
        print("Fibonacci sequence: (too large to display)")
    }
}

func test_validation_utilities() {
    print("\nโœ… Validation Utilities Tester")
    print("What would you like to validate?")
    print("1. Email address")
    print("2. Password")
    print("3. Phone number")

    let choice = parse_number(input())

    if choice == 1 {
        print("Enter an email address:")
        let email = input()
        let result = validate_email(email)
        print("Valid: ${result.valid}")
        if !result.valid {
            print("Errors: ${result.errors}")
        }
    } else if choice == 2 {
        print("Enter a password:")
        let password = input()
        let result = validate_password(password)
        print("Valid: ${result.valid}")
        print("Strength: ${result.strength}")
        if !result.valid {
            print("Errors: ${result.errors}")
        }
    } else if choice == 3 {
        print("Enter a phone number:")
        let phone = input()
        let result = validate_phone_number(phone)
        print("Valid: ${result.valid}")
        if result.valid {
            print("Formatted: ${result.formatted}")
        } else {
            print("Errors: ${result.errors}")
        }
    }
}

func test_data_utilities() {
    print("\n๐Ÿ“Š Data Utilities Tester")
    print("Enter numbers separated by spaces (e.g., '5 2 8 2 1 9'):")
    let input_text = input()
    let number_strings = input_text.split(" ")
    let numbers = []

    for num_str in number_strings {
        numbers = numbers + [parse_number(num_str)]
    }

    print("\nResults:")
    print("Original: ${numbers}")
    print("Unique: ${remove_duplicates(numbers)}")
    print("Sorted: ${sort_array(numbers)}")
    print("Reverse sorted: ${sort_array(numbers, false)}")

    let stats = find_min_max(numbers)
    print("Min: ${stats.min}, Max: ${stats.max}")
}

// Run the demo
main()

Best Practices for Writing Functions

1. Single Responsibility Principle

Each function should do one thing well:

// โœ… Good: Each function has a single, clear purpose
func calculate_area(length, width) {
    return length * width
}

func format_currency(amount) {
    return "$" + amount.to_string(2)
}

func send_email(recipient, subject, body) {
    // Email sending logic
}

// โŒ Not as good: Function tries to do too many things
func process_order(items, customer_email, discount_code) {
    // Calculates total
    // Applies discount
    // Formats receipt
    // Sends email
    // Updates inventory
    // Logs transaction
    // Too many responsibilities!
}

2. Descriptive Function Names

Function names should clearly describe what they do:

// โœ… Good: Clear, descriptive names
func calculate_monthly_payment(principal, interest_rate, years)
func validate_credit_card_number(card_number)
func send_password_reset_email(user_email)

// โŒ Not as good: Vague or abbreviated names
func calc(p, r, y)  // What does this calculate?
func validate(num)  // Validate what?
func send(email)    // Send what?

3. Consistent Parameter Order

Establish conventions for parameter order:

// โœ… Good: Consistent patterns
func convert_temperature(value, from_unit, to_unit)
func convert_currency(amount, from_currency, to_currency)
func convert_distance(length, from_unit, to_unit)

// Common pattern: (data, from, to) or (subject, action, options)

4. Document Your Functions

Add comments explaining what functions do, especially for complex ones:

/**
 * Calculates the monthly payment for a loan using the standard formula
 * @param principal - The loan amount (e.g., 250000 for $250k house)
 * @param annual_rate - Annual interest rate as decimal (e.g., 0.045 for 4.5%)
 * @param years - Loan term in years (e.g., 30 for 30-year mortgage)
 * @returns Monthly payment amount
 */
func calculate_monthly_payment(principal, annual_rate, years) {
    let monthly_rate = annual_rate / 12
    let num_payments = years * 12

    if annual_rate == 0 {
        return principal / num_payments  // Simple division for 0% interest
    }

    let factor = (1 + monthly_rate) ^ num_payments
    return principal * (monthly_rate * factor) / (factor - 1)
}

Chapter 4 Summary

Congratulations! You've learned how to organize code like a professional developer. Functions are one of the most important concepts in programming, and you now understand how to use them effectively.

Key Concepts Mastered

โœ… Function Definition: Creating reusable code blocks with clear purposes โœ… Parameters and Return Values: Passing data in and getting results back โœ… Default Parameters: Making functions flexible with optional arguments โœ… Variable Scope: Understanding where variables can be accessed โœ… Function Organization: Grouping related functions into logical modules โœ… Best Practices: Writing clean, maintainable, and reusable code

Skills You Can Now Demonstrate

  • Write functions that solve specific problems elegantly
  • Choose appropriate parameter designs for flexibility
  • Organize related functions into coherent modules
  • Debug scope-related issues in your code
  • Create reusable utility libraries for common tasks
  • Document functions clearly for future use and collaboration

Real Projects You Built

  • Complete Utility Library: String, math, validation, and data utilities
  • Interactive Testing System: User-friendly interface for testing utilities
  • Modular Code Organization: Professional-style code structure
  • Comprehensive Examples: Real-world applications of function concepts

Professional Skills Developed

  • Code Reusability: Writing functions that can be used across multiple projects
  • Modular Design: Breaking complex problems into manageable pieces
  • API Design: Creating function interfaces that are intuitive to use
  • Documentation: Explaining code functionality clearly
  • Testing Strategy: Building systems to verify function behavior

Advanced Practice Challenges

Ready to push your function skills further? Try these challenges:

๐ŸŽฏ Chapter Summary: You're Now a Code Organization Pro!

What You've Mastered

๐Ÿ”ง Functions - Your Code Building Blocks:

  • โœ… Function Creation: Write reusable code that eliminates repetition
  • โœ… Parameters & Arguments: Pass information into functions effectively
  • โœ… Return Values: Get results back from your functions
  • โœ… Variable Scope: Understand where variables can be accessed
  • โœ… Problem Decomposition: Break complex problems into smaller, manageable functions

๐Ÿ“ฆ Modules - Your Code Organization System:

  • โœ… Logical Grouping: Organize related functions into coherent modules
  • โœ… Code Reusability: Create libraries that work across multiple projects
  • โœ… Maintainability: Write code that's easy to update and debug
  • โœ… Professional Structure: Organize code like experienced developers

๐Ÿง  Accessibility Achievements

For ADHD support:

  • โœ… Learned to break overwhelming problems into manageable function-sized pieces
  • โœ… Mastered organization techniques that reduce cognitive load
  • โœ… Developed systematic approaches to complex programming challenges

For autistic minds:

  • โœ… Created predictable, consistent code patterns
  • โœ… Established logical, rule-based organization systems
  • โœ… Built reliable, reusable code structures

For all learning styles:

  • โœ… Visual: Used diagrams and flowcharts to understand function relationships
  • โœ… Kinesthetic: Built hands-on utilities and tested them interactively
  • โœ… Analytical: Explored the logical principles behind code organization

๐Ÿ† Your Programming Superpowers

You now have the skills that separate professional developers from beginners:

  1. Code Organization: You can structure programs logically and maintainably
  2. Problem Decomposition: You can break complex challenges into manageable pieces
  3. Code Reusability: You can write functions that work in multiple contexts
  4. Debugging Skills: You understand scope and can trace function behavior
  5. Professional Practices: You write code that other developers can understand and maintain

๐ŸŽฏ Real-World Applications

With these skills, you can now build:

  • Personal utility libraries for tasks you do repeatedly
  • Modular applications that are easy to maintain and extend
  • Collaborative projects where different people work on different modules
  • Professional-quality code that follows industry best practices

๐Ÿš€ Advanced Challenges (Optional)

Ready for a challenge? Try building these advanced projects:

Challenge 1: Personal Finance Manager

Create a comprehensive financial toolkit with modules for:

  • Budget tracking with category-based spending analysis
  • Investment calculations including compound interest and portfolio analysis
  • Bill reminders with automated payment scheduling
  • Savings goal tracking with progress visualization
  • Expense reporting with detailed analytics

Challenge 2: Study Assistant System

Build an educational support system with modules for:

  • Flashcard management with spaced repetition algorithms
  • Note organization with tagging and search capabilities
  • Study schedule planning with adaptive time management
  • Progress tracking with performance analytics
  • Quiz generation from your notes and study materials

Challenge 3: Creative Writing Suite

Develop a writer's toolkit with modules for:

  • Story structure analysis with plot point tracking
  • Character development with relationship mapping
  • World building with consistency checking
  • Writing statistics with progress tracking
  • Creative prompts with randomized idea generation

๐ŸŽฏ Looking Ahead to Chapter 5

In the next chapter, "Data Structures - Arrays and Dictionaries," we'll learn how to work with collections of data effectively. You'll discover:

  • Arrays and lists for ordered data collections
  • Dictionaries for key-value relationships
  • Sona's unified property access system for seamless data manipulation
  • Performance considerations for different data structures
  • Building a complete personal media library application
  • Advanced data manipulation techniques

โœ… Before Moving On - Self-Check

Make sure you can confidently:

  1. Write functions that take parameters and return appropriate values
  2. Choose between writing a function vs. inline code based on reusability needs
  3. Understand scope rules and can predict where variables are accessible
  4. Organize code into logical modules with related functionality
  5. Debug function-related errors including scope and parameter issues
  6. Document functions clearly for future reference and collaboration

๐ŸŽ‰ Your Programming Journey Progress

๏ฟฝ Major Milestone Achieved: You now write code like a professional developer!

You've learned the fundamental skill that separates beginner programmers from professional developers: code organization. You can now:

  • Break complex problems into manageable functions
  • Write reusable code that saves time and reduces errors
  • Organize code into logical, maintainable structures
  • Create libraries that can be used across multiple projects
  • Think in terms of APIs and interfaces

This is a huge step forward. Many programmers work for years without mastering proper function design and code organization. You now have these skills from the beginning, which will make everything else much easier and more enjoyable.

Ready for Chapter 5? Let's learn how to manage collections of data like a pro!


๐Ÿ’ญ Reflection Questions

For ages 12-18:

  • What's your favorite function that you've written so far?
  • How might you use modules to organize a project about your hobbies?
  • What would you include in a gaming utility library?

For ages 19-55+:

  • How could you apply these organizational principles to your work or personal projects?
  • What professional utility libraries would be most valuable in your field?
  • How might these concepts apply to non-programming aspects of your life?

For everyone:

  • What was the most challenging concept in this chapter, and how did you work through it?
  • Which utility module would you want to expand first?
  • How do you plan to use these skills in your next programming project?

"Functions are the LEGO blocks of programming. Once you master them, you can build anything your imagination can conceive!" - Andre


๐ŸŽฏ Next Chapter Preview: Get ready to explore the exciting world of data structures, where we'll learn to organize and manipulate collections of information efficiently and elegantly!