#literal [*:null]const ?[*:0]const u8
1 messages · Page 1 of 1 (latest)
specifically the interior const doesnt appear to be actually allowed. ```
/home/aep/kram/hello-world/src/main.zig:15:41: error: pointer modifier 'const' not allowed on array child type
std.os.execveZ("/bin/ls", &[_:0]const u8{ "/bin/ls", null }, null);
^~~~~
alright, so let's deconstruct this
[_]T{...} is an array literal. Arrays and array literals don't have qualifiers, because they're not pointers
the literal you're constructing isn't valid here in the first place either though, because what you want to pass is a pointer of pointers
and what [_:0]u8 is just an array of u8s
Thus, what you'd want is &[_:null]?[*:0]const u8{...}, which means "a null-terminated array of optional [*:0]const u8s"
the type of that expression is actually *const [n:null]?[*:0]const u8, but it just so happens that pointers to arrays coerce to slices and multi pointers, and thus it'll coerce to [*:null]const ?[*:0]const u8
uh wow. that's a lot to digest.
nope i still dont get it. where can i read more about the syntax or arrays?
right, i did read that one but was hoping for something less dense
well, then let me try to rephrase
This syntax also become a lot easier to grok, in my experience, if you make a cstring alias:
const cstring = ?[*:0]const u8;
Now it's just &[_:null]cstring{ "hello", "world" }.
-> "A null-terminated (:null) array ([_]) of cstrings."
[_]T{...} is an array of Ts.
[_:s]T{...} is a sentinel-terminated array of Ts, with the sentinel being s (which must be a valid value of type T).
Note that T can be any sized type, whether that be a simple integer like u8, or a more complex type like a pointer, e.g. []const u8, [*:0]i32, etc. Those are best learned aside from arrays.
In zig, arrays are treated as first class values, as opposed to C where they decay to pointers. That is to say, given an expression a = b, assuming these are arrays of the same type, the whole value of b will be copied into a. And much like other values, you can have pointers to arrays - that is, a pointer to [3]T is written *[3]T. Simple.
Now, pointers to arrays have some special properties, namely that they have some special coercion rules that make them easier to work with when inter-oping with pointers that don't have a comptime-known number of items.
For example, much like an i32 can coerce to a i64 without any special casting, *[3]u8 can coerce to []u8 or to [*]u8 without any special casting - so long as the qualifiers of the pointers are compatible. E.g., you're not allowed to cast from *const u16 to *u16, and you're also not allowed to cast from *const [3]T to []T - since you'd be discarding the const qualifier.
Given all that, it should now be noted that there aren't any slice or many-item-pointer literals in zig. As such, what we instead do is take pointers to array literals, which will coerce to both slices and many-item pointers. So what the expression &[_]T{...} does is say "declare this array literal, and take its address".
wrt to coercion rules, there is more to it, but it's not too much more nuanced
the general rule is "you can't coerce pointer A to pointer B if A has qualifiers that B doesn't"
this helps
what rule(s?) disallow the &.{} syntax?
none, just trying to explain the basic mechanics
'cause tuple pointers are then another rule that builds off of those basic mechanics, but in a funky kind of way
well it doesnt like when i try to do that with that function
does it not work?
no
note: a single pointer cannot cast into a many pointer
or maybe it's intentional that tuple pointers can't coerce to multi pointers, hard to say
theres an open issue on exactly this actually, "milestone 0.12.0" but its also changed 5 times lol so who knows
so uhh. you sayd coercion between sized and unsized should work
'[*:null]?[*:0]const u8', found '[2:null]?[*:0]const u8'
need to make sure you take its address
these are the same types arent they?
i tried that, but then
apparantly & turns it into *const [2...
instead of into [*
yes, and that ought to coerce
oh wait
I think I see the issue
it won't accept a literal
oh
see, the point about const vs non-const is important
it's expecting []T essentially
whilst *const [2]T would only coerce into []const T
so you'll have to declare a mutable array variable, and pass a pointer to that
28 const argv = [_:null]cstring{ "/bin/bash", null };
29 const bash = Unit{ .argv = &argv };
ye
/home/aep/kram/hello-world/src/main.zig:29:32: error: expected type '[*:null]?[*:0]const u8', found '*const [2:null]?[*:0]const u8'
const bash = Unit{ .argv = &argv };
^~~~~
make that var argv
oh mutable
that worked. i guess i should declare the field in the struct const tho
4 const Unit = struct {
5 argv: [*:null]cstring,
6 envp: [*:null]cstring,
7 };
so yeah
uuh apparantly you cant make them const?
[*:null]const cstring
uuhhh wow thats confusing
i got it to 
it makes sense when you get this idea nailed down: mutability is a property of memory, not of types
works fine now tho, including literal
this is to say, it doesn't make sense to say const u8
an integer is an integer, regardless of whether it's mutable or immutable
but that would mean it makes sense to say "const argv" since thats the memory location
that isn't the memory location
i feel like the right hand side of the array thingy should be the type?
that is the field which holds the pointer value
right
the pointer determines whether the pointed-to memory is const or mutable