Zig: Turning single item pointer into slice of length 1

Created on 2 Sep 2019  路  1Comment  路  Source: ziglang/zig

Trying to pass a one-item slice to read(), I struggled to figure out how to cast a single item pointer to a slice.

Currently the compiler error is

expected type '[]u8', found '*u8'`.

Perhaps it could gain a note:

did you want a slice of length 1? cast via '*[1]u8'"

Related IRC discussion on adding an implicit cast:

daurnimator how can I turn a *T into a slice of length one?
daurnimator @ptrCast([*]u8, &c)[0..1] works I guess...
andrewrk better to avoid ptr cast. you can do it with 2 implicit casts
andrewrk ([]T)(*[1]T)(&x)
daurnimator andrewrk: how about a cast directly: ([]T)(&x)?
andrewrk making *T cast to []T is not off the table, I'll still consider it
andrewrk but I want to make sure there are no footguns associated with that
andrewrk better to have some awkwardness than an (even rare) footgun
daurnimator FWIW it's not super bad. the []T is already in the function signature, so I only have to write: self.stream.read((*[1]u8)(&c)))

proposal

Most helpful comment

I'd like to double this. Actually, I was just checking to see if this already existed before submitting myself.
My Vulkan code (which uses this otherwise-awesome Vulkan binding) has plenty of places where I'm calling a function that expects a slice, just in case I actually want to perform an operation on many items at once, although I only actually have one item that needs to be worked on. That leads to some annoyingly verbose expressions like &[_]vulkan.CommandBuffer{command_buffer}, &[_]vulkan.Buffer{mesh.buffer.buffer} and &[_]vulkan.DeviceSize{0} that don't actually add to the readability of my code.
Another plus for making this cast implicit, or at least more convenient, is that it'd encourage programmers to write functions that operate on many items at once, potentially increasing performance. As an (admittedly bad) example, let's say that we want to make a function that swaps numbers. Of course, swapping many numbers at once can allow for better performance, since we may utilize things like SIMD and cache optimization. However, any lazy programmer who, in his case, mostly just needs to swap a single pair of numbers at a time, may conciser having his function take slices as parameters to be wasteful, as he now needs to write swapFn(@ptrCast([*]u8, &a)[0..1], @ptrCast([*]u8, &b)[0..1]) every time, when he could just write swapFn(&a, &b), only at the cost of a for-expression in the relatively few places where he actually needs to swap many numbers at once. This both goes against Zig's ideology of not having the programmer spending too much time and energy thinking about coding style, and may result in the programmer going for the performance-wise inferior option out of pure laziness. If, on the other hand, he could expect pointers to cast to slices, he could make swapFn take slices as parameters, and the syntax for adding just two numbers would still be swapFn(&a. &b). Even if he didn't want to employ SIMD right away, that'd still give him the opportunity to do so later.

>All comments

I'd like to double this. Actually, I was just checking to see if this already existed before submitting myself.
My Vulkan code (which uses this otherwise-awesome Vulkan binding) has plenty of places where I'm calling a function that expects a slice, just in case I actually want to perform an operation on many items at once, although I only actually have one item that needs to be worked on. That leads to some annoyingly verbose expressions like &[_]vulkan.CommandBuffer{command_buffer}, &[_]vulkan.Buffer{mesh.buffer.buffer} and &[_]vulkan.DeviceSize{0} that don't actually add to the readability of my code.
Another plus for making this cast implicit, or at least more convenient, is that it'd encourage programmers to write functions that operate on many items at once, potentially increasing performance. As an (admittedly bad) example, let's say that we want to make a function that swaps numbers. Of course, swapping many numbers at once can allow for better performance, since we may utilize things like SIMD and cache optimization. However, any lazy programmer who, in his case, mostly just needs to swap a single pair of numbers at a time, may conciser having his function take slices as parameters to be wasteful, as he now needs to write swapFn(@ptrCast([*]u8, &a)[0..1], @ptrCast([*]u8, &b)[0..1]) every time, when he could just write swapFn(&a, &b), only at the cost of a for-expression in the relatively few places where he actually needs to swap many numbers at once. This both goes against Zig's ideology of not having the programmer spending too much time and energy thinking about coding style, and may result in the programmer going for the performance-wise inferior option out of pure laziness. If, on the other hand, he could expect pointers to cast to slices, he could make swapFn take slices as parameters, and the syntax for adding just two numbers would still be swapFn(&a. &b). Even if he didn't want to employ SIMD right away, that'd still give him the opportunity to do so later.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DavidYKay picture DavidYKay  路  3Comments

jorangreef picture jorangreef  路  3Comments

andrewrk picture andrewrk  路  3Comments

bronze1man picture bronze1man  路  3Comments

dobkeratops picture dobkeratops  路  3Comments