Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't return generated generic/type-taking functions #1375

Closed
tgschultz opened this issue Aug 12, 2018 · 2 comments
Closed

Can't return generated generic/type-taking functions #1375

tgschultz opened this issue Aug 12, 2018 · 2 comments
Labels
bug Observed behavior contradicts documented or intended behavior
Milestone

Comments

@tgschultz
Copy link
Contributor

const IsTypeFn = fn(type) bool;

fn generateIsType(comptime T: type) IsTypeFn
{
    const Closure = struct
    {
        pub fn is(comptime Other: type) bool
        {
            return T == Other;
        }
    };
    return Closure.is;
}

const isU32 = generateIsType(u32);

test "generic fn generation"
{
    debug.assert(isU32(u32));
}
error: expected type 'fn(type) bool', found 'fn(type)var'

This appears to be because of the kind of type-erasure zig performs as a result of being able to do things like this fn func(comptime T: type, x: T) T, where any type after the first generic (or type) argument could be inferred. Since var does not work as a return type (#447), the only way around this is to return the Closure struct, itself a workaround for the inability to nest functions directly within other functions (#229), and take the Fn at the callsite:

const IsTypeFn = fn(type) bool;

fn generateIsType(comptime T: type) type
{
    const Closure = struct
    {
        pub fn is(comptime Other: type) bool
        {
            return T == Other;
        }
    };
    return Closure;
}

const isU32 = generateIsType(u32).is;

test "generic fn generation"
{
    debug.assert(isU32(u32));
}
Test 1/1 generic fn generation...OK
All tests passed.
@tgschultz
Copy link
Contributor Author

tgschultz commented Aug 12, 2018

It turns out that it is possible, you just have to trick the compiler a little bit:

fn typeFnWorkaround(comptime T: type) bool { return false; }
const IsTypeFn = @typeOf(typeFnWorkaround);

fn generateIsType(comptime T: type) IsTypeFn
{
    const Closure = struct
    {
        pub fn is(comptime Other: type) bool
        {
            return T == Other;
        }
    };
    return Closure.is;
}

const isU32 = generateIsType(u32);

test "generic fn generation"
{
    debug.assert(isU32(u32));
}
Test 1/1 generic fn generation...OK
All tests passed.

@andrewrk andrewrk added this to the 0.3.0 milestone Aug 13, 2018
@andrewrk andrewrk added the bug Observed behavior contradicts documented or intended behavior label Aug 13, 2018
@andrewrk andrewrk modified the milestones: 0.3.0, 0.4.0 Aug 28, 2018
@andrewrk andrewrk modified the milestones: 0.4.0, 0.5.0 Mar 16, 2019
@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Aug 27, 2019
@Vexu
Copy link
Member

Vexu commented Nov 13, 2019

All these examples work currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

No branches or pull requests

3 participants