Is there any plan to add an ord function for T and []T at std library?

There is two kinds of ord function in std library of zig 0.13.0:

  1. std.math.ord for T
  2. std.mem.ord for []T

Is can provide other ord function for both T and []T? The reason for that is some scenario need a comparable field being key when implement some structure like ord Tree:

pub fn Tree(comptime K: type, comptime V: type) type {
    return struct {
        root: ?*Node,
        allocator: std.mem.Allocator,
   
        const Self = @This();

        const Node = struct {
            key: K,  // the key must be comparable, but now can't use either std.mem.order or std.math.order directly.
            value: V,
            left: ?*Node,
            right: ?*Node,
            allocator: std.mem.Allocator,

            fn insert(node: *Node) (older_value: ?V, root: *Node) {
                const order = // an order function for both T and []T;
                switch (order) {
                  .eq => // emit
                  .lt => // emit
                  .gt => // emit
                }

            }
        }

    }
}

It is great if std library have an implementation like this:

fn Ord(comptime K: type) type {
    return struct {
        pub fn ord(a: K, b: K) std.math.Order {
            if (comptime is_array_or_slice(K)) {
                const typeinfo = @typeInfo(K);
                const child_type = if (typeinfo == .Array) typeinfo.Array.child else if (typeinfo == .Pointer) typeinfo.Pointer.child else unreachable;
                return std.mem.order(child_type, a, b);
            } else {
                return std.math.order(a, b);
            }
        }

        fn is_array_or_slice(comptime T: type) bool {
            const typeinfo = @typeInfo(T);
            if (typeinfo == .Array) {
                return true;
            } else if (typeinfo == .Pointer) {
                const pointer = typeinfo.Pointer;
                return pointer.size == .Slice or pointer.size == .Many;
            }
            return false;
        }
    };
}

test Ord {
    const ord = Ord([]const u8);
    assert(ord.ord("A", "A") == .eq);
    assert(ord.ord("A", "B") == .lt);

    const ord2 = Ord(i32);
    assert(ord2.ord(1, 1) == .eq);
    assert(ord2.ord(1, 2) == .lt);
}
1 Like

That’s a very specific need, I don’t think the std library should bother with this. Perhaps it would be better to receive the ordering function as a parameter:

pub fn Tree(comptime K: type, comptime V: type, comptime order: fn(K, K) std.math.Order) 
3 Likes

A great idea and make sense for me.

Take a look at how std.PriorityQueue implements comparison, it should help.

The nice thing about Order it it’s just an enum, you can reuse it however you’d like.

1 Like

Thanks! I learned the idiotic way how zig handle the ord by std.PriorityQueue you referred.
The reason of I raise the question is that the zig is not had an ord function can handle both string and primitive type, that is confused for some new zig learner from other modern language like rust or go.
Again, thanks!

1 Like

Ordering strings is complex. While many languages offer a default ordering, which is good enough for implementing data structures and simple lookups, but useless for dozens of other applications of ordering text.

1 Like

There is no such thing as a universal ordering of “string”. The sooner you come to grips with that, the better.

The ordering of “string” is dependent upon things like use case, language and location. For example, collation of strings can differ even for the same language depending upon which country is doing it (see: Aachen).