Replace `anytype` with `infer T`(or `@Infer(T)`)

infer T and @Infer(T) are completely equivalent, taking infer T as an example only:

Feature

The difference from other schemes is that this allows the result position semantics to also take effect in the user function:

fn userFunc() infer T {
    // `T`, like an `anytype` parameter, depends on the location of the function call.
}

Moreover, treating infer T as a type placeholder can achieve the effect of type deconstruction:

fn func(a: []infer T) void {
    ...
}

particulars

Its basic characteristics satisfy @TypeOf(infer T) == type. The content of T is derived from the context. (Only @TypeOf(infer _) can be compiled, and @TypeOf(infer _) == type or prohibit the independent appearance of infer.)

Specifically, as a type placeholder, infer T itself is a type (similar to u32 which is also a type). After successful deduction, T is a concrete type that can be used as a type value at compile time (e.g. var x: T=...). infer T cannot be used as a parameter for @TypeOf()(if not allow @TypeOf(infer _)) because it is not an expression.

Since infer T is considered as a type as a whole, infer has the highest priority in the type expression. (@Infer(T) does not have this issue.)

In theory, only infer _ can compile and pass when the type cannot be deduced (because it has already been discarded). Semantically speaking, infer _ and the current anytype are equivalent.

infer _ should be used as a placeholder for the discarded part of the type. For example:

fn func(a: struct{infer _, infer T}) void {
    ...
}
func(.{10, @as(u32, 20)}); -> T == u32

In many cases, it can provide clearer parameter requirements than anytype/anyvalue/or others. For example, the function interface of the allocator:

pub fn destroy(self: Allocator, ptr: anytype) void {
    ...
}

pub fn free(self: Allocator, memory: anytype) void {
    ...
}

:backhand_index_pointing_down:

pub fn destroy(self: Allocator, ptr: *infer T) void {
    ...
}

pub fn free(self: Allocator, memory: []infer T) void {
    ...
}

Other

Identifier reuse

For example:
The compiler checks whether the inference results of inference types with the same name are consistent.

pub fn swap(a: *infer T, b: *infer T) void {
    ...
}

Or
Prohibit duplicate names and manually check in the code. (More in line with Zig.)

pub fn swap(a: *infer T, b: *infer U) void {
    std.debug.assert(T == U);
    ...
}

Allow the position of infer

Only Function Signatures OR Function Signature and Expression.

If available in the expression, infer T may be a more intuitive way of type deconstruction than @typeInfo(T):

fn func(a: u32) f32 {
    ...
}

// @typeInfo
const T = @typeInfo(@TypeOf(func)).@"fn".return_type.?;

// infer
fn(u32)infer T = @TypeOf(func);

Alternative solutions for expression deconstruction:
Package this feature as a function:

fn func(a: u32) f32 {
    ...
}

fn GetRetType(f: fn(u32) infer T) type {
    return T;
}

const U = GetRetType(func); -> U == f32

Inverse inference of generic functions

For example:

fn Gen(comptime T: type) type {
    return struct {...};
}

fn func(gen: Gen(infer T)) void {
    ...
}

func(Gen(u32));       -> T == u32
func(Gen(Gen(u32)));  -> T == Gen(u32)

This function cannot be achieved through @typeInfo.

Due to the fact that one result of a function may correspond to multiple inputs, this feature cannot be implemented.

Ending

Original idea: If you had one wish for zig, what would it be? - #23 by Dok8tavo

@Dok8tavo

2 Likes

Why don’t you contribute your idea to this discussion: Anytype is getting renamed to anyval (!) - #35 by alanza

1 Like

Thanks for the heads-up. However, infer T is more than just a rename — its design goes beyond what anytype covers. I think it deserves a separate discussion. I’ll check out the thread you mentioned. Thanks!

1 Like

I can’t find the issue but infer T (excluding your expression deconstruction) was officially proposed and rejected.

And there were many similar and also very different proposals to replace anytype that were also rejected.

2 Likes

It should be this issue.

But, well, it seems that it is now being reconsidered in another form.

2 Likes

so its just infer T but with capture syntax, which kind of makes sense since you are “capturing the type of a value/expression”

2 Likes