ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.8k stars 2.47k forks source link

Proposal: xor operator for bool type #5805

Closed data-man closed 4 years ago

data-man commented 4 years ago

Many languages support it. It would be nice if Zig will support this operator, too.

test "bool operators" {
    expect(!(!true));
    expect(!false);

    expect(true and true);
    expect(!(true and false));
    expect(!(false and true));
    expect(!(false and false));

    expect(true or true);
    expect(true or false);
    expect(false or true);
    expect(!(false or false));

    expect(!(true xor true));
    expect(true xor false);
    expect(false xor true);
    expect(!(false xor false));
}

I implemented it (mostly) in xor_bool branch. Except for documentation and code generation. I hope that core developers can finished my work.

data-man commented 4 years ago

Results of voting in Telegram channel:

xor is needed? %
yes 87
no 0
why? 13

Yes, the small community (voted by 8 users) :smile:

rohlem commented 4 years ago

Just wanted to point out some things: So far Zig uses keywords instead of operands if they influence control flow; in the case of boolean operators, they short-circuit: false and and true or never evaluate the second operand. Xor cannot short-circuit, so if we stick to above rule, an operator symbol would be more appropriate.

Also note that boolean-xor is equivalent in behaviour to !=, which is already implemented for bool operands. This makes it feel superfluous to me personally (one way to do things).

data-man commented 4 years ago

one way to do things

That's always a funny point.

What's your choice? @sin or math.sin? @cos or math.cos? ... and so on.

data-man commented 4 years ago

Also note that boolean-xor is equivalent in behaviour to !=

const std = @import("std");
const warn = std.debug.warn;
const Vector = std.meta.Vector;

pub fn main () void {
    const v1: Vector(4, bool) = [_]bool{ true, false, true, false };
    const v2: Vector(4, bool) = [_]bool{ false, false, true, false };
//      const v3 = v1 ^ v2; //it isn't compiles
    const v4 = v1 != v2;
//                ^ this

    warn("v1 = {}\n", .{ v1 });
    warn("v2 = {}\n", .{ v2 });
//      warn("v3 = {}\n", .{ v3 });
    warn("v4 = {}\n", .{ v4 });
}
Sobeston commented 4 years ago

That's always a funny point.

We will never be able to actually only have one way of doing things - that would be ridiculous; no programming language could do this. But do not let perfection get in the way of good - we can still confidently aim towards this (impossible) goal. We should at the very least try not to go in the opposite direction.

Introducing an operator that does the exact same thing as != doesn't make sense.

I also do not see the problem with your example - v4 works fine.

data-man commented 4 years ago

v4 works fine

Yes. But users expect comparison of vectors, so it's one vector equal to another or not.

Snektron commented 4 years ago

I believe vector equality comparison to check whether all elements are equal rather than performing the operation lane-wise is handled by #2698.

SpexGuy commented 4 years ago

It shouldn't be unexpected that != on Vector is per-component. It represents a SIMD vector. All operations are per-component by design. Having != be per-component will likely not change. Maybe we should rename Vector to something else like Parallel or Multi to eliminate this confusion.

data-man commented 4 years ago

It shouldn't be unexpected that != on Vector is per-component.

Why?

(1 != 2) == true (true != false) == true (v1 != v2) == true // oops!

SpexGuy commented 4 years ago

A SIMD vector is not one value. It is a bundle of parallel values. Applying any operator to a SIMD vector applies it to each element in the bundle. This includes +, -, *, /, %, !, [x] (when x is a Vector), ==, !=, >, <, >=, and <=. There are no base operators on a SIMD vector that can combine information from multiple lanes. Which makes sense based on the design of SIMD - it carries multiple channels of independent data (Multiple Data), where each channel has the same meaning (Single Instruction). Checking that all elements of a SIMD vector are a certain value is a rare operation, much more rare than generating a mask of channels where a condition applies.

As another argument, consider != vs >=. It's clear that x >= y should produce a vector when x and y are vectors, because there isn't a good way to define this operator to return a single value. Why should != and == be different from >= and <?

Finally, an xor operation would only resolve this case for Vector(N, bool). If != were changed to check all channels, how would you do a per-element != for a Vector(N, u32)?

data-man commented 4 years ago

Checking that all elements of a SIMD vector are a certain value is a rare operation

Because of its "rarity", I implemented comparison of vectors in meta and testing. ;)

Finally, an xor operation would only resolve this case for Vector(N, bool).

Maybe not a new operator, but an implementation ^ for boolean vectors.

andrewrk commented 4 years ago

Maybe not a new operator, but an implementation ^ for boolean vectors.

I think there is a good case to be made for allowing bitwise operators on bool, or at least on vectors of bool. I thought there might have been a separate proposal for that, but I did not find one. Would you like to make that proposal, @data-man?