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

add a compile error for usingnamespace crossing package boundaries #1853

Closed
thejoshwolfe opened this issue Dec 22, 2018 · 5 comments
Closed
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@thejoshwolfe
Copy link
Contributor

If you write an app like this:

use @import("lib1");
use @import("lib2");
fn foo() void {}

then this will only compile if neither of lib1 or lib2 export a symbol called foo. If one of those libraries decides in a minor version update to export a new function called foo, then it will cause a compile error in this app. Furthermore, if both lib1 and lib2 independently decide to export a new symbol bar in their own minor version updates, then updating those two dependencies would result in a compile error.

This means one of three things:

  • Exporting a new symbol should be a major version bump.
  • Minor version bumps are expected to break things.
  • use is bad. (this is my choice.)

As the Zig ecosystem scales up, the likelihood of this kind of symbol collision rises. If I were writing a Best Practices Guide at an organization that used Zig, I would discourage or forbid the use of use for this reason.

Perhaps a more nuanced rule would be that use should never cross package boundaries. There's no semver contract between the files of a single package, so this would work around this particular issue. This is even a rule that we could enforce in the compiler, although it might backfire if people start violating the package abstraction in order to work around this restriction (like use @import("../../../packages/lib1/src/main.zig");).

@andrewrk andrewrk added this to the 0.5.0 milestone Dec 22, 2018
@andrewrk
Copy link
Member

Thanks for the writeup. I want to note that the existence of compile-time reflection introduces complications into the meaning of semantic versioning. For example once #1047 is implemented, or even without it, you can iterate over the member functions of a struct and emit a compile error if it is more than 10. So then presumably a library which adds a member function to a struct could be breaking code. Is that a major or a minor version bump?

It can get a bit philosophical. For example, let's say that my build process creates one executable and embeds it into another one, with a maximum size of 1000 bytes. If a library updated versions and then didn't fit in 1000 bytes anymore, that could break something. But probably the machine code size is not something that is protected by the minor version bump.

I agree with your problem statement in this issue. I think we need to define very carefully, exactly what constitutes a major, minor, and bugfix version bump, and explore to what extent Zig can help prove that semver is upheld (#404).

@asoffer
Copy link

asoffer commented Dec 24, 2018

Titus Winters has a nice talk where he discusses some of the problems with SemVer.
https://www.youtube.com/watch?v=tISy7EJQPzI

In short, every change can be a breaking change for someone (Hyrum's law)... even bug fixes, so it is an inevitability that semver will not work as expected eventually for someone.

I think use is also usually a bad idea, but also even if it's not this particular issue, minor version bumps will eventually break things. It's probably best left to the library authors to decide what sorts of promises they want to make. Perhaps, in Andrew's example, the library is intended to be used in embedded settings and so the authors promise to always keep it under 1kb or have a major version bump.

This is a fundamentally a question about contracts between library authors and users. I'd argue that implictly it's the author's right to add new symbols at any time, and so while upgrading will be easiest if the user doesn't use things, it's up to them to weigh how much they want to use use against how painful they expect an upgrade to be.

@winksaville
Copy link
Contributor

I suggest the 'use' documentation provide the information on these pitfalls.

@binary132
Copy link

binary132 commented Dec 24, 2018

The fact that people learn to depend on features which are not part of the explicitly defined interface is not a limitation of semver. I'm with @asoffer on this one. Namespace obliteration is always a problem.

Here's a simple-ish way you could solve it: If you @use a package which defines a name that collides with a name in your local scope, the local name should be selected first, and the imported name may be resolved using a namespace selector. (Like Go's name shadowing in local scope, but with a namespace selector so you could still refer to the shadowed name.)

Of course, then the compiler would need to be aware of which names are "actually" @use names, and what package they actually belong to, or no longer be able to refer to them. And, it creates a semantic problem where it's not always obvious what a name refers to.

@andrewrk andrewrk added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Aug 21, 2019
@andrewrk andrewrk changed the title the use statement is hostile to semver add a compile error for usingnamespace crossing package boundaries Aug 21, 2019
@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Aug 21, 2019
@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Jan 3, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 27, 2020
@andrewrk
Copy link
Member

Please see this comment: #678 (comment)

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

5 participants