Function parameters are const or immutable?

I’m reading Introduction to Zig and at section 2.2, it says that function parameters are immutable.

I think that is should be constant.

In Zig Language Reference, section Functions / Pass-by-value Parameters, also use immutable. Is this correct?

Thanks

they are const, and that cant be changed. Either make a local var copy, or pass a pointer, depending on your needs.

This is explained here, at the end of the second paragraph, prefaced by its reasoning

1 Like

Thanks.

But my point was that if:
“This is made possible, in part, by the fact that parameters are immutable.”
Then the text should be fixed.

Using const means the thing you’re attributing with it is immutable. I think the docs are correct: parameters are always immutable with no option to change that – the const keyword isn’t involved.

If it used the term “const” to talk about parameters, that would be imprecise and could introduce confusion about the use of the keyword and the concept of immutability. Using the two words interchangeably is imprecise, but highly common in programmer discourse, and usually doesn’t lead to confusion (except when it does).

It’s common to see people speak or write “const pointer” when they’re actually talking about “pointer to immutable data”, leading to confusion about whether the pointer variable is const or the pointee is const.

2 Likes

Here is an example:

const std = @import("std");
const testing = std.testing;

const Workout = struct {
    const Step = struct {
        power: u32,
    };

    steps: []Step,
};

fn workout(wko: Workout) !void {
    // Mutate the data is allowed.
    wko.steps[0].power = 250;

    try testing.expectEqual(wko.steps[0].power, 250);
}

test "parameter is mutable" {
    const step = Workout.Step{ .power = 200 };

    // Convert an array to a slice
    var array = [_]Workout.Step{step};
    const slice = array[0..array.len];

    const wko = Workout{ .steps = slice };
    try workout(wko);
}
All 1 tests passed.

It uses pointers, but does really matter?

Update: yes, use of pointer matter, so the example incorrect.

When slicing you can ommit the end to include the rest of the data e.g a[0..]

And if you want a slice of the whole array, you can just do &a, as pointers to arrays coerce to slices.

Thanks, I had forgotten it.

I think trying to describe those in terms of “constant” or not leads someone to an incorrect mental model.

If I have some function like this, it’s not that my function is receiving a constant, it’s that my function is receiving a value.

fn doubleIt(input: u64) u64 {
    return input * 2;
}

_ = doubleIt(n);

If you have use it like this, my function isn’t receiving n, it’s receiving whatever value n refers to at that time. So if n = 32, my function is receiving a 32.

how is it incorrect

const n = 32;
const another_n = n;

Has the same semantics.

Immutable, and value, are more precise terminology with less bagage from other languages. So I agree I should have used those.

The mental model of “a function receives my variable” is incorrect.

Yeah, this is similar to what I’m trying to convey. You’re not assigning n to another_n, you’re assigning the value of n.

var n: u8 = 10;
const another_n = n;
n += 1;
// n is 11, another_n is still 10

This works the same if another_n is var or const.

This is basically what I’m trying to say.