Hacker News new | ask | show | jobs
by AndyKelley 2329 days ago
Here's the C++ example from the article:

    template <class T>
    concept SignedIntegral = std::is_integral_v<T> &&
                            std::is_signed_v<T>;
    template <SignedIntegral T> // no SFINAE here!
    void signedIntsOnly(T val) { }
Here's the equivalent Zig code. You can run this with `zig test example.zig`.

    const std = @import("std");
    const assert = std.debug.assert;

    fn signedIntsOnly(val: var) void {
        comptime assert(std.meta.trait.isSignedInt(@TypeOf(val)));
    }

    test "concepts example" {
        var x: u32 = 1234;
        signedIntsOnly(x);
    }
This produces the compile error:

    ../lib/std/debug.zig:221:14: error: unable to evaluate constant expression
        if (!ok) unreachable; // assertion failure
                 ^
    ./example.zig:5:20: note: called from here
        comptime assert(std.meta.trait.isSignedInt(@TypeOf(val)));
                       ^
    ./example.zig:10:19: note: called from here
        signedIntsOnly(x);
                      ^
    ./example.zig:8:26: note: called from here
    test "concepts example" {
                            ^
    
It accomplishes the same thing, just a bit more verbose, since it is using the general tools of the language rather than special syntax.
1 comments

> assert(std.meta.trait.isSignedInt(@TypeOf(val)));

well yes, that's my point. You could also write

    void signedIntsOnly(auto val) {
        static_assert(std::is_integral_v<T> && std::is_signed_v<T>); 
    }
in C++ but it's quite preferable to refactor this inside the types themselves (for the same reason that you want to refactor any other kind of code in general - besides you don't want to go read the implementation of your functions every time do you ? IDEs show us only prototypes for a reason).

How would you for instance specialize a generic function in Zig ? Does zig accept

    fn complexmathoperation(val: var) void {
        if(isInt(@TypeOf(val))) { 
        }
    }
and in another module

    fn complexmathoperation(val: var) void {
        if(isSomeKindOfLibrarySpecificMatrix(@TypeOf(val))) { 
        }
    }
and properly dispatches between both ?

I'd be hard pressed to say that it is "as powerful" given what I'm seeing for now.

> besides you don't want to go read the implementation of your functions every time do you ? IDEs show us only prototypes for a reason

The IDE can be changed to show you assertions in addition to the signature, just as it also shows doc comments. That the signature is special isn't some law of nature, it's just habit (and users of untyped languages don't even have those).

> How would you for instance specialize a generic function in Zig ? ... and properly dispatches between both ?

No, you'd need a single definition with a comptime branch.

> I'd be hard pressed to say that it is "as powerful" given what I'm seeing for now.

What you're seeing is personal taste. In my taste, that Zig doesn't allow overloading and has clear dispatch is clearer is more preferable (in fact, it's touted as one of Zig's biggest strengths); in yours, it is less preferable. That's perfectly OK, but it's got nothing to do with expressive power (which has a pretty good and precise definition: https://youtu.be/43XaZEn2aLc). There is a reason why some languages are more complicated while others are simple -- some people aesthetically prefer the more complex languages while others prefer simpler ones. What is impressive about Zig is that despite being simple, it's not giving up power, at least in those aspects I mentioned. C, another simple language, cannot do those things.