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);
}
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:
Result: