Ok, Iād like to hash this out a little more.
@floooh suggested the example of āa whole array of structsā being allocād and initialized (with some data) simultaneously, which, to me, seems ludicrous indeed; I agree. Your comment, ā⦠when youāre used to it⦠you will probably do the same with not-so-simple cases, and that is where the harm isā - I want to respect, but it doesnāt āfeelā like I would. So, if I have a āsimpleā Zoo, and it has members that really donāt want default values, e.g., because data invariants of the struct could be violated by omitting a field during initialization (see here), you might provide:
const Zoo = struct {
a: u8,
b: u8,
const default: Zoo = .{
.a = 3,
.b = 4,
};
fn init(a: u8, b: u8) Zoo {
return Zoo {
.a = a,
.b = b,
};
}
};
Now, if you were creating a zoo with an allocator, and create() should really ādo no initializationā, it would perhaps at least(?):
...
fn create(al: Allocator) !*Zoo {
const r = try al.create(Zoo);
r.* = default; //?
return r;
}
But would it be the most conventional? to require the caller to:
var myzoo = try Zoo.create(al);
myzoo.* = { .a = 1, .b = 2 };
Or would it be āunconventionalā? (inappropriate by convention?) to provide:
...
fn make(al: Allocator, a: u8, b: u8) !*Zoo {
const r = try al.create(Zoo);
r.* = .{ .a = a, .b = b };
return r;
}
So that the user can one-liner instead:
var myzoo = try Zoo.make(al, 1, 2);
And, finally, if such a ādefaultā (as provided above) didnāt really make sense, and neither does an āuninitialized Zooā, then would it be appropriate to ONLY provide that make() function? If so, would it be better to call it something like make(), indeed, instead of create(), in order to avoid conveying that it was a standard create() that did NO initialization? (Though, of course, the (ā¦, a, b) parameters would make it pretty clear that it was going to initialize values.)
I donāt mean to nit-pick, but Iād like to develop routines that make sense and coincide with conventions the community has evolved⦠and I still havenāt spent enough time in various peoplesā libraries to feel confident drawing zeitgeist conclusions of my own (especially as the language and std are still evolving themselves and I do see a lot of ānot so right-lookingā code in the wild, too).
(Sorry, I usually compile code before posting, like this, but Iām growing confident enough to try freehanding now, so, forgive any flubs.)
EDIT: of course, for such a simple struct, Zoo wouldnāt really need a create() fn; caller could just al.create(Zoo); first by themselves, but for a more interesting struct, of course, providing that creation helper makes sense, even if itās ONLY doing allocation. By this token, a make() function would perhaps first call sister create(), then do the initialization (perhaps calling sister init(), such that make() might MERELY be a convenience r = create(); r.* = init();⦠but I didnāt think of packaging it that way when I wrote the above. The bottom-line question still remains: is this make() idea an anti-pattern that should be avoided? Is it āfineā, even to do this in a function named create(), with args for initialization, and maybe even ONLY provide such a create(al, argsā¦) if, in your application, it makes no sense to allocate-create an uninitialized version of the object? Or is it best to make sure, regardless, that create() only allocs, and never initializes with provided values (at the very least, so that callers donāt have to worry about whether expensive stuff is being done inside of create())? Sorry thatās so many questions wrapped in one, but Iāll be very satisfied to have the guidance.