Hi @Sze, thank you for your answer.
I don’t understand why you dislike your index_of
function, can you clarify why you don’t just use that function?
I like my function and I am using it. I think you do not get the point of what I am trying to show. Let me illustrate with a new function:
fn is_digit (char: u8) bool
{
return switch (char)
{
'0' ... '9' => true,
else => false,
};
}
This function is awesome and I can use it in my code. However, it already exists a function to achieve this: std.ascii.isDigit ()
. So even if my function can do the job, it is better to use the std library’s function. The std library handles common usages and secures them over time.
To come back to my index_of
function, this is the same thing: I have this “utility” function in most of my Zig projects because the std.mem.indexOf
functions do not handle this use case. Maybe I am not alone, so maybe its place is not in my projects but in the std library. And maybe it could be handle in the std.mem.indexOf
set of functions.
Also if it is difficult to express, maybe you could show some uses of the function that illustrate what you would prefer to be different.
With what I already explained, this is what I have now:
# utils.zig
const std = @import ("std");
pub fn index_of (comptime T: type, slice: []const T, value: T) ?usize
{
for (slice, 0 ..) |element, index| { if (std.meta.eql (value, element)) return index; }
else return null;
}
# main.zig
const std = @import ("std");
const utils = @import ("utils.zig");
const MyStruct = struct
{
x: u8 = undefined,
y: u8 = undefined,
};
pub fn main () void
{
const array = [_] MyStruct
{
.{ .x = 5, .y = 2 },
.{ .x = 3, .y = 7 },
.{ .x = 6, .y = 1 },
.{ .x = 8, .y = 4 },
};
std.debug.print ("{}\n{?}\n", .{ utils.index_of (MyStruct, &array, .{ .x = 6, .y = 1 }).?,
utils.index_of (MyStruct, &array, .{ .x = 6, .y = 10 }), });
}
and what I want instead:
# main.zig
const std = @import ("std");
const MyStruct = struct
{
x: u8 = undefined,
y: u8 = undefined,
};
pub fn main () void
{
const array = [_] MyStruct
{
.{ .x = 5, .y = 2 },
.{ .x = 3, .y = 7 },
.{ .x = 6, .y = 1 },
.{ .x = 8, .y = 4 },
};
std.debug.print ("{}\n{?}\n", .{ std.mem.indexOfScalar (MyStruct, &array, .{ .x = 6, .y = 1 }).?,
std.mem.lastIndexOfAny (MyStruct, &array, &[_] MyStruct
{
.{ .x = 6, .y = 10 },
.{ .x = 6, .y = 12 },
}), });
}
One thing I am wondering is why do you need to find it, would it be possible to restructure the code so that it is more declarative and you already just know, without having to search first?
Yeah for sure, I can. I can also use an std.AutoHashMap
, use the contains ()
and get ()
methods to solve all of this. But:
- it is bringing new problems (now I have to manage an allocator because now I am using a heap memory allocated object instead of an array)
- that does not answer the real question: Why can I use
std.mem.indexOf ()
functions with primitive types and not with end-user types ?
Hmm after looking at std.mem.indexOf
I see that it does something quite different than your index_of
function
Yes you are right, std.mem.indexOf ()
can not be made for this use case. But for all these functions it could be:
std.mem.indexOfAny
std.mem.indexOfDiff
std.mem.indexOfNone
std.mem.indexOfScalar
- their
Pos
and last
counter-parts.
Hi @maksverver, thank you for your answer: even if I am not only talking about std.mem.indexOfScalar
, it is exactly what I tried to mean.