# Parameter Syntax

### Function Parameters

Function parameters are the inputs of a function.

They allow functions to work with different values instead of hardcoded data.

Without parameters, functions are limited:

```zig
fn printNumber() void {
    std.debug.print("{}\n", .{42});
}
```

This function can only print `42`.

With parameters:

```zig
fn printNumber(value: i32) void {
    std.debug.print("{}\n", .{value});
}
```

Now the function can print any integer.

```zig
printNumber(10);
printNumber(99);
printNumber(-5);
```

Output:

```text
10
99
-5
```

Parameters make functions reusable.

## Parameter Syntax

A parameter has two parts:

```zig
name: type
```

Example:

```zig
value: i32
```

- `value` is the parameter name
- `i32` is the parameter type

A function with one parameter:

```zig
fn square(x: i32) i32 {
    return x * x;
}
```

Here:

- parameter name: `x`
- parameter type: `i32`
- return type: `i32`

## Multiple Parameters

Functions can have multiple parameters.

```zig
fn add(a: i32, b: i32) i32 {
    return a + b;
}
```

Calling it:

```zig
const result = add(10, 20);
```

The values are passed in order:

```text
a = 10
b = 20
```

Parameters are separated by commas.

```zig
fn move(x: i32, y: i32, speed: f32) void {

}
```

## Arguments vs Parameters

These words are related but different.

| Term | Meaning |
|---|---|
| Parameter | variable in the function definition |
| Argument | actual value passed during the call |

Example:

```zig
fn add(a: i32, b: i32) i32 {
    return a + b;
}
```

Here `a` and `b` are parameters.

```zig
add(5, 8);
```

Here `5` and `8` are arguments.

Programmers sometimes use the words interchangeably in casual conversation, but technically they are different.

## Parameters Create Local Variables

Inside the function, parameters behave like local variables.

Example:

```zig
fn double(value: i32) i32 {
    const result = value * 2;

    return result;
}
```

`value` exists only inside the function.

Outside the function, it does not exist.

```zig
pub fn main() void {
    double(10);

    // ERROR
    // value does not exist here
}
```

This isolation helps keep programs organized.

## Type Checking

Zig checks parameter types strictly.

Example:

```zig
fn multiply(a: i32, b: i32) i32 {
    return a * b;
}
```

Correct:

```zig
multiply(3, 4);
```

Incorrect:

```zig
multiply("hello", "world");
```

The compiler rejects invalid types before the program runs.

This is one reason Zig programs are reliable.

## Integer Parameters

Common integer parameter types:

| Type | Meaning |
|---|---|
| `u8` | unsigned 8-bit integer |
| `u32` | unsigned 32-bit integer |
| `i32` | signed 32-bit integer |
| `usize` | size/index integer |

Example:

```zig
fn setVolume(level: u8) void {
    std.debug.print("Volume: {}\n", .{level});
}
```

`u8` allows values from `0` to `255`.

## Floating Point Parameters

Floating-point types store decimal numbers.

Common types:

| Type | Meaning |
|---|---|
| `f32` | 32-bit float |
| `f64` | 64-bit float |

Example:

```zig
fn area(radius: f64) f64 {
    return 3.14159 * radius * radius;
}
```

Calling:

```zig
const result = area(5.0);
```

## Boolean Parameters

Booleans store `true` or `false`.

Example:

```zig
fn setEnabled(enabled: bool) void {
    if (enabled) {
        std.debug.print("Enabled\n", .{});
    } else {
        std.debug.print("Disabled\n", .{});
    }
}
```

Calling:

```zig
setEnabled(true);
setEnabled(false);
```

Output:

```text
Enabled
Disabled
```

## String Parameters

Strings in Zig are usually slices of bytes.

Example:

```zig
fn greet(name: []const u8) void {
    std.debug.print("Hello, {s}!\n", .{name});
}
```

Calling:

```zig
greet("Alice");
```

Output:

```text
Hello, Alice!
```

This type:

```zig
[]const u8
```

means:

- `[]` → slice
- `const` → read-only
- `u8` → bytes

You will learn slices in detail later.

For now, think of this as Zig’s standard string type.

## Passing Structs

Functions can receive structs.

Example:

```zig
const Point = struct {
    x: i32,
    y: i32,
};

fn printPoint(point: Point) void {
    std.debug.print("({}, {})\n", .{
        point.x,
        point.y,
    });
}
```

Calling:

```zig
const p = Point{
    .x = 10,
    .y = 20,
};

printPoint(p);
```

Output:

```text
(10, 20)
```

Functions can work with complex data, not just primitive values.

## Passing Pointers

Sometimes copying data is expensive.

Instead of passing the whole value, you pass a pointer.

Example:

```zig
fn increment(value: *i32) void {
    value.* += 1;
}
```

Calling:

```zig
var number: i32 = 10;

increment(&number);
```

After the call:

```text
number = 11
```

The operator:

```zig
&number
```

gets the address of `number`.

The type:

```zig
*i32
```

means “pointer to i32.”

Pointers are extremely important in Zig.

## Parameters Are Immutable by Default

Function parameters cannot normally be reassigned.

Example:

```zig
fn test(value: i32) void {
    // ERROR
    // value = 5;
}
```

This prevents accidental modification.

If you need a mutable variable, create a new one:

```zig
fn test(value: i32) void {
    var local = value;

    local += 1;
}
```

This rule improves clarity.

## Parameter Shadowing

Avoid reusing parameter names.

Bad example:

```zig
fn test(value: i32) void {
    const value = 10;
}
```

This creates confusion.

Use distinct names instead.

## Too Many Parameters

Functions with too many parameters become hard to use.

Bad:

```zig
fn createUser(
    name: []const u8,
    age: u8,
    height: f32,
    weight: f32,
    country: []const u8,
    city: []const u8,
    active: bool,
) void {

}
```

This is difficult to read and easy to misuse.

Often a struct is better:

```zig
const User = struct {
    name: []const u8,
    age: u8,
    height: f32,
    weight: f32,
    country: []const u8,
    city: []const u8,
    active: bool,
};

fn createUser(user: User) void {

}
```

This approach scales better.

## A Complete Example

```zig
const std = @import("std");

fn calculateArea(width: f64, height: f64) f64 {
    return width * height;
}

fn printArea(area: f64) void {
    std.debug.print("Area: {}\n", .{area});
}

pub fn main() void {
    const area = calculateArea(5.0, 3.0);

    printArea(area);
}
```

Output:

```text
Area: 15
```

Notice how each function has a focused job:

- `calculateArea` computes
- `printArea` displays
- `main` coordinates the flow

This separation is one of the core ideas of clean software design.

