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 or prohibit the independent appearance of @TypeOf(infer _) can be compiled, and @TypeOf(infer _) == typeinfer.)
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 ) because it is not an expression.@TypeOf(infer _)
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 {
...
}
![]()
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