Skip to content

← Modules, Visibility, Testing and Docs step 7 of 22

Medium Primitives

Three namespaces: types, values, and macros

Here is the hidden mechanism behind a dozen otherwise-arbitrary rules. Rust has three namespaces, and a name is only in conflict with another name in the same one.

namespace inhabitants
type structs, enums, unions, traits, type aliases, modules, primitives
value functions, constants, statics, and struct/variant constructors
macro macro_rules! macros, attribute and derive macros

Once you know this, several things stop being coincidences.

  • Option and Some are different names because one is a type and one is a constructor. They could not share a name space and both be spelled Option.
  • use std::io; and use std::io::Result; do not clash: io is a module (type namespace) and Result is a type — different names entirely, no conflict.
  • println! needs the ! partly because macros live somewhere else. A function called println would be an unrelated name.

The task

pub fn collisions(decls: Vec<String>) -> Vec<String>

Given normalised declarations, return the sorted, deduplicated set of names declared twice in the same namespace. Anything unrecognised is ignored.

form occupies
struct Name {} type
struct Name; type and value
struct Name() type and value
enum Name, trait Name, type Name, union Name, mod Name type
fn Name, const Name, static Name value
macro_rules! Name macro

The line that catches everybody

struct Foo {}      +  fn Foo    ->  no conflict
struct Foo;        +  fn Foo    ->  E0428, `Foo` is defined multiple times

A braced struct is a type only. A unit struct is a type and a value, because Foo on its own is an expression that produces one. A tuple struct is a type and a value too, because Foo(3) is a function call — the constructor really is a function, and you can pass Foo to map.

So this innocent-looking pair does not compile:

struct Config;                    // took the value namespace, silently
fn Config() -> Config { Config }  // E0428

…and the error message talks about Config being “defined multiple times”, which is baffling until you know that the unit struct quietly claimed a slot you did not know existed.

Three flavours of collision

Worth being able to tell apart, because the fix differs:

  • E0428 — defined multiple times. Two items with the same name in the same namespace. Rename one.
  • E0255 — the name is defined multiple times. An import collides with an item you declared. Use as on the import, or move the item.
  • E0252 — the name is defined multiple times. Two imports collide. as one of them.

And E0659 — from the previous item — is the fourth, deferred kind: two globs, error only at use.

Contract

Declarations arrive already normalised, with single spaces, in the exact forms in the table. macro_rules! keeps its !. Return names sorted; a name that collides in two namespaces at once still appears once.