Opinions on setBit Implementation: Pointer vs. Copy?

Hi everyone,

I’m working on a utility function in Zig to set a specific bit in a u64 bitboard. Currently, my implementation modifies the bitboard in place via a pointer and returns the updated value. Here’s the function:

pub fn setBit(bitboard: *u64, square: u6) u64 {
    bitboard.* |= (@as(u64, 1) << square);
    return bitboard.*;
}

While this approach works, I’ve been wondering if it would be better to avoid using a pointer and instead make a copy of the bitboard, modify it, and return the updated copy. For example:

pub fn setBit(bitboard: u64, square: u6) u64 {
    return bitboard | (@as(u64, 1) << square);
}

Some considerations I’ve been debating:

Performance - The pointer-based approach avoids copying the bitboard but introduces side effects, which could complicate debugging in certain cases.

Flexibility - Returning a copy promotes immutability and could make the function more reusable in contexts where side effects are undesirable.

Memory Safety: Using pointers directly raises questions about safety, especially in scenarios where the program might deal with untrusted inputs or environments.

For context, the program might run on a personal server (an Arch Linux box), and while it’s not exposed to the internet yet, I want to make sure I’m following best practices for both safety and design.

I’m curious to hear the community’s thoughts:

  • Do you prefer one approach over the other for utility functions like this, and why?
  • Are there specific scenarios where one approach clearly outshines the other?
  • Any insights into performance or safety implications I might be overlooking?

Looking forward to your opinions and suggestions, and thank you in advance.

1 Like

Hi @strydr
Welcome to ziggit :slight_smile:

I prefer to have immutable values, unless there are clear performance gains from the mutable approach.

Zig standard library have multiple implementations of bit sets. IntegerBitSet implementation is mutable, it stores the bits of the set in an integer called mask. The equivalent of setBit is IntegerBitSet.set:

pub fn set(self: *Self, index: usize) void {
    assert(index < bit_length);
    self.mask |= maskBit(index);
}
2 Likes