|
| 1 | +- Feature Name: `hyphens_considered_harmful` |
| 2 | +- Start Date: 2015-03-05 |
| 3 | +- RFC PR: (leave this empty) |
| 4 | +- Rust Issue: (leave this empty) |
| 5 | + |
| 6 | +# Summary |
| 7 | + |
| 8 | +Disallow hyphens in package and crate names. Propose a clear transition path for existing packages. |
| 9 | + |
| 10 | +# Motivation |
| 11 | + |
| 12 | +Currently, Cargo packages and Rust crates both allow hyphens in their names. This is not good, for two reasons: |
| 13 | + |
| 14 | +1. **Usability**: Since hyphens are not allowed in identifiers, anyone who uses such a crate must rename it on import: |
| 15 | + |
| 16 | + ```rust |
| 17 | + extern crate "rustc-serialize" as rustc_serialize; |
| 18 | + ``` |
| 19 | + |
| 20 | + This boilerplate confers no additional meaning, and is a common source of confusion for beginners. |
| 21 | + |
| 22 | +2. **Consistency**: Nowhere else do we allow hyphens in names, so having them in crates is inconsistent with the rest of the language. |
| 23 | + |
| 24 | +For these reasons, we should work to remove this feature before the beta. |
| 25 | + |
| 26 | +However, as of January 2015 there are 589 packages with hyphens on crates.io. It is unlikely that simply removing hyphens from the syntax will work, given all the code that depends on them. In particular, we need a plan that: |
| 27 | + |
| 28 | +* Is easy to implement and understand; |
| 29 | + |
| 30 | +* Accounts for the existing packages on crates.io; and |
| 31 | + |
| 32 | +* Gives as much time as possible for users to fix their code. |
| 33 | + |
| 34 | +# Detailed design |
| 35 | + |
| 36 | +1. On **crates.io**: |
| 37 | + |
| 38 | + + Reject all further uploads for hyphenated names. Packages with hyphenated *dependencies* will still be allowed though. |
| 39 | + |
| 40 | + + On the server, migrate all existing hyphenated packages to underscored names. Keep the old packages around for compatibility, but hide them from search. To keep things simple, only the `name` field will change; dependencies will stay as they are. |
| 41 | + |
| 42 | +2. In **Cargo**: |
| 43 | + |
| 44 | + + Continue allowing hyphens in package names, but treat them as having underscores internally. Warn the user when this happens. |
| 45 | + |
| 46 | + This applies to both the package itself and its dependencies. For example, imagine we have an `apple-fritter` package that depends on `rustc-serialize`. When Cargo builds this package, it will instead fetch `rustc_serialize` and build `apple_fritter`. |
| 47 | + |
| 48 | +3. In **rustc**: |
| 49 | + |
| 50 | + + As with Cargo, continue allowing hyphens in `extern crate`, but rewrite them to underscores in the parser. Warn the user when this happens. |
| 51 | + |
| 52 | + + Do *not* allow hyphens in other contexts, such as the `#[crate_name]` attribute or `--crate-name` and `--extern` options. |
| 53 | + |
| 54 | + > Rationale: These options are usually provided by external tools, which would break in strange ways if rustc chooses a different name. |
| 55 | + |
| 56 | +4. Announce the change on the users forum and /r/rust. Tell users to update to the latest Cargo and rustc, and to begin transitioning their packages to the new system. Party. |
| 57 | + |
| 58 | +5. Some time between the beta and 1.0 release, remove support for hyphens from Cargo and rustc. |
| 59 | + |
| 60 | +## C dependency (`*-sys`) packages |
| 61 | + |
| 62 | +[RFC 403] introduced a `*-sys` convention for wrappers around C libraries. Under this proposal, we will use `*_sys` instead. |
| 63 | + |
| 64 | +[RFC 403]: https://github.com/rust-lang/rfcs/blob/master/text/0403-cargo-build-command.md |
| 65 | + |
| 66 | +# Drawbacks |
| 67 | + |
| 68 | +## Code churn |
| 69 | + |
| 70 | +While most code should not break from these changes, there will be much churn as maintainers fix their packages. However, the work should not amount to more than a simple find/replace. Also, because old packages are migrated automatically, maintainers can delay fixing their code until they need to publish a new version. |
| 71 | + |
| 72 | +## Loss of hyphens |
| 73 | + |
| 74 | +There are two advantages to keeping hyphens around: |
| 75 | + |
| 76 | +* Aesthetics: Hyphens do look nicer than underscores. |
| 77 | + |
| 78 | +* Namespacing: Hyphens are often used for pseudo-namespaces. For example in Python, the Django web framework has a wealth of addon packages, all prefixed with `django-`. |
| 79 | + |
| 80 | +The author believes the disadvantages of hyphens outweigh these benefits. |
| 81 | + |
| 82 | +# Alternatives |
| 83 | + |
| 84 | +## Do nothing |
| 85 | + |
| 86 | +As with any proposal, we can choose to do nothing. But given the reasons outlined above, the author believes it is important that we address the problem before the beta release. |
| 87 | + |
| 88 | +## Disallow hyphens in crates, but allow them in packages |
| 89 | + |
| 90 | +What we often call "crate name" is actually two separate concepts: the *package name* as seen by Cargo and crates.io, and the *crate name* used by rustc and `extern crate`. While the two names are usually equal, Cargo lets us set them separately. |
| 91 | + |
| 92 | +For example, if we have a package named `lily-valley`, we can rename the inner crate to `lily_valley` as follows: |
| 93 | + |
| 94 | +```toml |
| 95 | +[package] |
| 96 | +name = "lily-valley" # Package name |
| 97 | +# ... |
| 98 | + |
| 99 | +[lib] |
| 100 | +name = "lily_valley" # Crate name |
| 101 | +``` |
| 102 | + |
| 103 | +This will let us import the crate as `extern crate lily_valley` while keeping the hyphenated name in Cargo. |
| 104 | + |
| 105 | +But while this solution solves the usability problem, it still leaves the package and crate names inconsistent. Given the few use cases for hyphens, it is unclear whether this solution is better than just disallowing them altogether. |
| 106 | + |
| 107 | +## Make `extern crate` match fuzzily |
| 108 | + |
| 109 | +Alternatively, we can have the compiler consider hyphens and underscores as equal while looking up a crate. In other words, the crate `flim-flam` would match both `extern crate flim_flam` and `extern crate "flim-flam" as flim_flam`. This will let us keep the hyphenated names, without having to rename them on import. |
| 110 | + |
| 111 | +The drawback to this solution is complexity. We will need to add this special case to the compiler, guard against conflicting packages on crates.io, and explain this behavior to newcomers. That's too much work to support a marginal use case. |
| 112 | + |
| 113 | +## Repurpose hyphens as namespace separators |
| 114 | + |
| 115 | +Alternatively, we can treat hyphens as path separators in Rust. |
| 116 | + |
| 117 | +For example, the crate `hoity-toity` could be imported as |
| 118 | + |
| 119 | +```rust |
| 120 | +extern crate hoity::toity; |
| 121 | +``` |
| 122 | + |
| 123 | +which is desugared to: |
| 124 | + |
| 125 | +```rust |
| 126 | +mod hoity { |
| 127 | + mod toity { |
| 128 | + extern crate "hoity-toity" as krate; |
| 129 | + pub use krate::*; |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +However, on prototyping this proposal, the author found it too complex and fraught with edge cases. Banning hyphens outright would be much easier to implement and understand. |
| 135 | + |
| 136 | +# Unresolved questions |
| 137 | + |
| 138 | +None so far. |
0 commit comments