It achieves the same result in practice. The reason Zig needs to return a type is because it lacks a way to represent `T!A` where T is a parameterized type, and A is the parameter. In this case, that would've been better because you would be able to tell exactly what the type being returned was.
If you must return different types depending on the argument in D, it's also possible.
Here's a silly example:
struct ArrayList(T, alias capacity) {
private T[capacity] array;
private uint _length;
uint length() const => _length;
T get(uint index) const => array[index];
void add(T t) {
array[_length++] = t;
}
}
struct EmptyList(T) {
uint length() const => 0;
}
/// This will return a different type depending on the length argument,
/// which is like a Zig comptime argument.
/// We cannot return the type itself, but the result is very similar.
auto createArrayList(T, alias length)() {
static if (length == 0) {
return EmptyList!T();
} else {
return ArrayList!(T, length)();
}
}
void main()
{
import std.stdio;
auto empty = createArrayList!(int, 0);
writeln(empty);
auto list = createArrayList!(int, 2);
list.add(5);
list.add(6);
writeln(list);
}
Result: EmptyList!int()
ArrayList!(int, 2)([5, 6], 2)
You still misunderstand the type type. "type" does not mean "generic over all types" but that you're returning a reified type. The original Zig function does not return an ArrayList value, it returns the ArrayList type.
It's now too late to edit my original comment but I've skimmed your code a little too fast and now I see that you do understand that Zig works with reified types. But in that case, why conflate too very different things? Returning values of different types is not the same as returning types.
Regardless, we are now very far removed from the original code I was commenting on, which doesn't use auto to return different types.