Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename usingnamespace to mixin #9861

Open
ifreund opened this issue Sep 29, 2021 · 35 comments
Open

Rename usingnamespace to mixin #9861

ifreund opened this issue Sep 29, 2021 · 35 comments
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@ifreund
Copy link
Member

ifreund commented Sep 29, 2021

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 revised usingnamespace semantics map quite well to the generally understood concept of a mixin.

I also proposed using includedecls or includedeclarations in the original thread, however I find these ugly compared to mixin 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.

@ifreund ifreund added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Sep 29, 2021
@ifreund ifreund added this to the 0.9.0 milestone Sep 29, 2021
@nmichaels
Copy link
Contributor

nmichaels commented Sep 30, 2021

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.

@InKryption
Copy link
Contributor

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.

@rohlem
Copy link
Contributor

rohlem commented Sep 30, 2021

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 pub things are included, we could put it in the name: includepub / mixinpub .
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 works in general).

adopt/adoptdeclarations/adoptdecls would also sound understandable to me.

@zzyxyzz
Copy link
Contributor

zzyxyzz commented Sep 30, 2021

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.

@benrob0329
Copy link

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.

@Guigui220D
Copy link

Guigui220D commented Oct 14, 2021

@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

@benrob0329
Copy link

@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.

@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 Nov 24, 2021
@kenaryn
Copy link

kenaryn commented Dec 22, 2021

What about nonlocal or outerspace?

@jibal
Copy link

jibal commented Jan 17, 2022

How about calling it mixindeclarations ? Or mixindeclarationsof ?

@andrewrk andrewrk modified the milestones: 0.10.0, 0.11.0 Apr 16, 2022
@Hsad
Copy link

Hsad commented Jun 2, 2022

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.

@nektro
Copy link
Contributor

nektro commented Jun 3, 2022

I like usingnamespace being long, and "namespace" being in the name accurately reflects that only the decls are being imported

@jibal
Copy link

jibal commented Jun 3, 2022

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.

@igor84
Copy link

igor84 commented Jun 13, 2022

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.

@daneelsan
Copy link

daneelsan commented Jul 15, 2022

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).

@ominitay
Copy link
Contributor

forwarddecls, or forwarddeclarations, as suggested by @InKryption more adequately describes the behaviour than usingdeclarations

@nektro
Copy link
Contributor

nektro commented Jul 15, 2022

namespace is already the name used internally for the list of a container's declarations. the name is fine

@ominitay
Copy link
Contributor

@nektro The term using isn't great, can be misleading in this context though. This is obviously nitpicking though lol.

@jibal
Copy link

jibal commented Jul 16, 2022

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.)

@codethief
Copy link

codethief commented Mar 3, 2023

but on reconsideration I think that forwarddeclarations is better ... mixin, like using, 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.

@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Apr 9, 2023
@andrewrk andrewrk modified the milestones: 0.13.0, 0.12.0 Jul 9, 2023
@expikr
Copy link
Contributor

expikr commented Nov 13, 2023

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,
            };
        }
    };
}

@jedisct1
Copy link
Contributor

May I suggest derive?

I'm not found of it. "derive" doesn't convey the idea that it augments something.

@expikr
Copy link
Contributor

expikr commented Nov 14, 2023

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.

@jibal
Copy link

jibal commented Nov 15, 2023

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.

@zzyxyzz
Copy link
Contributor

zzyxyzz commented Nov 17, 2023

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.

@deflock
Copy link

deflock commented Nov 17, 2023

pollute 🤪

@jibal
Copy link

jibal commented Nov 18, 2023

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.

@expikr
Copy link
Contributor

expikr commented Nov 18, 2023

derive isn't that cryptic is it?

@mlugg
Copy link
Member

mlugg commented Nov 18, 2023

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.

@jibal
Copy link

jibal commented Nov 18, 2023

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.

@jedisct1
Copy link
Contributor

How about "merge"?

@zzyxyzz
Copy link
Contributor

zzyxyzz commented Nov 18, 2023

How about "merge"?

That would not be a good keyword to reserve, IMHO.

@nektro
Copy link
Contributor

nektro commented Nov 18, 2023

usingnamespace is good as is

@deflock
Copy link

deflock commented Nov 18, 2023

Okay, brainstorming is going on: involve, mixup, or some re-prefixed reintroduce, reuse, reinject

@expikr
Copy link
Contributor

expikr commented Nov 18, 2023

Append

@hsyl20
Copy link

hsyl20 commented Nov 19, 2023

reexport

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests