Open ifreund opened 2 years ago
I like mixin
better than any of the alternatives you listed, but it implies something false to me. When I see mixin
it makes me think that the mixed-in things will be available in the local namespace. reexport
is awkward but closer to the intent. transship
? include
?
This feels a little bit bike-sheddy, but the feature's implemented and good names are really important. If we take a name for a concept with which people are familiar (like using namespace
) then users will be surprised when it has different semantics from what they expect. If it's an entirely unfamiliar name, they'll have to look up what it does, which is probably what we want. The balance, I think, is finding a name that's unfamiliar enough to cause transplants from other languages to look it up, while being intuitive enough that Zig programmers can remember it easily.
More bike-shedding here, but how about forward
, forwarddecls
or forwardnamespace
? Being that the new semantics are closer to forwarding declarations, as opposed to mixing them in with the present declarations, or including them.
I've never used a language with a mixin
keyword, but Wikipedia says many languages do different things with it, so I'm not convinced that the word implies influencing identifier lookup. They are available in the namespace, via indirection of @This()
.
To explicitly show only
As far as I understand it, that is no longer the case in stage2? Non-public declarations equally qualify, as long as they are within the same file (how pub
things are included, we could put it in the name: includepub
/ mixinpub
.pub
works in general).
adopt
/adoptdeclarations
/adoptdecls
would also sound understandable to me.
+1 for forwarddecls
. It's kinda ugly, but describes the semantics precisely. Since this is not a frequently used feature, a long and descriptive keyword should be better than a short but somewhat cryptic one.
I think that mixin
is short and to the point. Reading the summary of what a mixin is, it perfectly describes the intended use case, mixing in the definitions from another source. Its less awkward than most other suggestions, and being short encourages use.
@benrob0329 I think the goal at some point was to have a long word for it to discourage its use and not encourage it though
@Guigui220D Do you know why it's use would be discouraged? The intended use-case seems reasonable enough, though I suppose it does add some hidden complexity.
What about nonlocal
or outerspace
?
How about calling it mixindeclarations ? Or mixindeclarationsof ?
I like the logic of adopt
, it implies the superseding behavior of needing to label the namespace to access it. Sort of like a new family name. Something like AdoptNames
, or AdoptDef
could do a better job of hinting towards the actual use case. Usurp, Clone, Sample, Inherit, Use, Reference/Refencing, Take, Utilize, + Names/Def, etc, could be other variations with a similar train of thought.
I like usingnamespace
being long, and "namespace" being in the name accurately reflects that only the decls are being imported
But the decls aren't imported ... not any more; they are added ("mixed in") to the container and available to its users (by qualifying the decls with the name of the container), but they aren't available to the code within it (without qualification).
BTW, there seems to be a bug ... although the symbols are not imported, the duplicate definition checker thinks they are, so you can't define the symbols that you've mixed in.
Edit: I tried to create a test case for the above, but it worked fine ... maybe it's been fixed or I'm misremembering the problem. operator error ... the bug is still there.
Based on the comments here I couldn't quite grasp why mixin
is not a perfect choice, but after playing around with it this example made me realize:
fn SA(comptime Self: type) type {
return struct {
a: u8 = 80,
pub fn add(self: Self, b: u8) u8 {
return self.a + b;
}
};
}
const SB = struct {
c: u8 = 80,
pub usingnamespace SA(@This());
};
This example produces a compile error no member 'a' in struct 'SB'
on return self.a + b;
. That is because usingnamespace
only includes the declarations (functions and consts) but not fields from SA
into SB
. Note that if you changed that line to return self.c + b;
it would compile since Self
in SA
will actually refer to SB
.
To me the word mixin
implies mixing in fields should also work since I first learned about the concept in DLang. But, wikipedia is a bit confusion on the terms. The mixin page actually describes mixin
as something that only mixes in additional methods which actually is what is happening here. On the other hand the page about trait specifically describes the difference from mixing with this sentence:
In contrast, mixins include full method definitions and may also carry state through member variable, while traits usually don't.
I still like the choice of mixin
keyword the most but I do understand now why it is not perfect.
Because I didn't see this above I'll propose: usingdeclarations
.
To me, declarations is a more self-explaining word that namespace.
If using is not of your preference, how about splicedeclarations
(https://dictionary.cambridge.org/dictionary/english/splice).
forwarddecls
, or forwarddeclarations
, as suggested by @InKryption more adequately describes the behaviour than usingdeclarations
namespace
is already the name used internally for the list of a container's declarations. the name is fine
@nektro The term using
isn't great, can be misleading in this context though. This is obviously nitpicking though lol.
My suggestion of mixindeclarations
got a lot of downvotes even though it is more accurate than many of the other proposals and clearer and less ambiguous than simply "mixin" which is what this issue proposes ... but on reconsideration I think that forwarddeclarations
is better ... mixin
, like using
, has the wrong implication as @nmichaels explained above.
namespace
is already the name used internally for the list of a container's declarations. the name is fine
The problem isn't so much with namespace
(although only the public declarations are forwarded) as it is with using
... as of #9618 (implementing #9629) the code that includes the keyword does not and cannot use the declarations from that namespace ... they are only available to the importers of the code that contains the keyword. (I made the same point back on June 3, in response to " the name accurately reflects that only the decls are being imported" which is not accurate--the decls are exported, not imported. Please read ifreund's proposal up top ... the whole reason for it is that the semantics of the keyword changed.)
but on reconsideration I think that
forwarddeclarations
is better ...mixin
, likeusing
, has the wrong implication as @nmichaels explained above.
I agree with @jibal's assessment here. In fact, it took me the better part of an hour now (of reading the docs as well as the various Github issues I found here and on DuckDuckGo) to realize that, contrary to its name, usingnamespace
does not (or no longer, as of #9629) allow using the members of the given namespace in the current scope (the one that contains the usingnamespace
instruction). This is very confusing.
Even if the name will not be changed, it should at least be documented properly.
May I suggest derive
? Or deriving
, or something along those lines:
pub fn Mat3(comptime T: type) type {
return struct {
xx: T = 1, xy: T = 0, xz: T = 0,
yx: T = 0, yy: T = 1, yz: T = 0,
zx: T = 0, zy: T = 0, zz: T = 1,
pub derive
Mat3_Impl_Shared(T, @This());
pub derive if (T==f16 or T==f32 or T==f64 or T==f80 or T==f128)
Mat3_Impl_Float(T, @This()) else opaque{};
};
}
fn Mat3_Impl_Shared(comptime T: type, comptime Self: type) type {
return opaque {
const Index = enum {
xx, xy, xz,
yx, yy, yz,
zx, zy, zz,
};
pub fn compose(a: Self, b: Self) Self {
return .{
.xx = a.xx*b.xx + a.xy*b.yx + a.xz*b.zx,
.yx = a.yx*b.xx + a.yy*b.yx + a.yz*b.zx,
.zx = a.zx*b.xx + a.zy*b.yx + a.zz*b.zx,
.xy = a.xx*b.xy + a.xy*b.yy + a.xz*b.zy,
.yy = a.yx*b.xy + a.yy*b.yy + a.yz*b.zy,
.zy = a.zx*b.xy + a.zy*b.yy + a.zz*b.zy,
.xz = a.xx*b.xz + a.xy*b.yz + a.xz*b.zz,
.yz = a.yx*b.xz + a.yy*b.yz + a.yz*b.zz,
.zz = a.zx*b.xz + a.zy*b.yz + a.zz*b.zz,
};
}
pub fn cof(a: Self, index: Index) T {
return switch (index) {
.xx => a.zz*a.yy - a.yz*a.zy, .xy => a.zx*a.yz - a.yx*a.zz, .xz => a.zy*a.yx - a.yy*a.zx ,
.yx => a.xz*a.zy - a.zz*a.xy, .yy => a.xx*a.zz - a.zx*a.xz, .yz => a.xy*a.zx - a.zy*a.xx ,
.zx => a.yz*a.xy - a.xz*a.yy, .zy => a.yx*a.xz - a.xx*a.yz, .zz => a.yy*a.xx - a.xy*a.yx ,
};
}
pub fn det(a: Self) T {
return a.xx*a.cof(.xx) +
a.xy*a.cof(.xy) +
a.xz*a.cof(.xz) ;
}
};
}
fn Mat3_Impl_Float(comptime T: type, comptime Self: type) type {
return opaque {
pub fn inv(a: Self) ?Self {
const detA: T = a.det();
return if (detA == 0) null else .{
.xx=a.cof(.xx)/detA, .xy=a.cof(.yx)/detA, .xz=a.cof(.zx)/detA,
.yx=a.cof(.xy)/detA, .yy=a.cof(.yy)/detA, .yz=a.cof(.zy)/detA,
.zx=a.cof(.xz)/detA, .zy=a.cof(.yz)/detA, .zz=a.cof(.zz)/detA,
};
}
};
}
May I suggest derive?
I'm not found of it. "derive" doesn't convey the idea that it augments something.
Well, it isn't quite augmenting the Type being referenced (since you can't immediately access it within), rather it's merging the declarations from it (as you can only access it in the final product). Words that properly conveys the shoehorning "tacked-on" sense would be ones like "Impute", "Imbue", or "Infuse" but those seem a tad overmuch. "Inject" might suit it but it seems to have a rather overloaded usage in other places, while "Imitate" only suggests behaviors are replicated and not the comets and vars.
reappropriate
might work.
rather it's merging the declarations from it
But it's not ... please see the discussion above. The keyword has very odd semantics ... it exports the symbols from the referenced struct but it doesn't import them ... the code containing the keyword cannot use the symbols. That's the whole reason for this proposed change.
In any case I can't see how "derive" or "deriving" give any indication of what it does, and suggests a relationship that may not hold at all.
Since we're still bikeshedding, how about mixout
?
It's a mixin
that only has an effect outside the current namespace ))
Also unusual enough to hit the docs right away, without forming wrong expectations first.
pollute
🤪
None of these suggestions is clearly better than forwarddecls
(or forwarddeclarations
-- there's no need to be cryptic with this rarely used keyword), suggested over 2 years ago.
derive
isn't that cryptic is it?
derive
would be pretty misleading. It gives implications of OO-like behaviours: inheriting fields, and adjusting method types to operate on this type. In reality, all the keyword does is directly include all symbols from another namespace.
derive
is wrong in every possible way.
Again, forwarddeclarations
is accurate and none of these other suggestions are improvements ... and some are just horrible, with unclear semantics and connotations that simply don't apply.
It might be helpful to look at #9629 to see the sorts of use cases that kept Andrew from removing the keyword altogether ... examples like
// windows.zig
pub usingnamespace @import("std").os.windows;
pub usingnamespace @import("misc.zig");
where it is used to combine decls from various namespaces into a new namespace.
Most helpful though would be to stop bikeshedding this tiny corner of Zig and spend our time more fruitfully. And on that note I'm going to unsubscribe.
How about "merge"?
How about "merge"?
That would not be a good keyword to reserve, IMHO.
usingnamespace is good as is
Okay, brainstorming is going on: involve
, mixup
, or some re-prefixed reintroduce
, reuse
, reinject
Append
reexport
The semantics of
usingnamespace
were changed in #9618 as per proposal #9629. However, the keyword itself was not changed and it was decided to leave that for a separate proposal.To reiterate my comment on #9629, I think the originally proposed
includenamespace
isn't perfect as not everything in the target namespace is included, only the public declarations.I think using
mixin
as the new keyword would be more clear and concise. Mixins are already a well known concept in programming (wikipedia) and the revisedusingnamespace
semantics map quite well to the generally understood concept of a mixin.I also proposed using
includedecls
orincludedeclarations
in the original thread, however I find these ugly compared tomixin
and don't think they give a clearer idea of the semantics.As this is a rather zig-specific concept, people new to zig will almost certainly need to read the documentation to learn the exact semantics of this keyword no matter what we choose.