Heads up -- explicit std imports

Hey all, yet another change in the language – explicit std imports.

The Mojo standard library lives in the std namespace, but up until today one could import std modules directly, e.g. from memory import *. No longer – now one has to write from std.memory import *.

Our apologies for the communication gap; this should’ve been communicated sooner.

@joe is going to publish the proposal with the reasoning shortly. In brief, this change makes it possible for non-stdlib modules to have the same names, i.e. one can have a memory module and not clash with ours.

6 Likes

After the current change hits nightly, Mojo compiler will issue a warning for non-qualified imports. No immediate plans to make this an error.

1 Like

Here is the commit from last night’s nightly release with my original proposal: [mojo-lang] Add proposal for explicit standard library imports · modular/modular@2ccdc63 · GitHub. Please take a look for some context and rationale — happy to discuss more on this thread.

1 Like

@Joe, based on the GitHub repo you shared, it states that we should implement std in Mojo as a precedent for Rust and Zig.

But in Rust and Zig.

I think this is the case:

However, this is only needed if you want to use Zig’s std (for example std.debug.print, std.ArrayList, etc.).
For third-party Zig libraries or C libraries, you typically:

  • Import a Zig package via @import on a path or package name (not necessarily “std”).
  • Import C headers via @cImport and @cInclude, without involving std at all.

For Rust: In Rust, the standard library is also available by default in regular crates (via std), but you can write no_std crates that deliberately avoid std.
To import libraries, you use use (or extern crate in older code) for crates from Cargo.toml.

So I don’t directly understand what you meant by this feature on standard library import in Mojo being a precedent for Rust and Zig?

What I’m explicitly and respectfully pointing out is that:
If Mojo follows a “copycat” approach to syntax without the robust package management of Rust/Cargo, it could lead to “frictional” code—where you’re typing more (std.) but not getting the same safety or modularity benefits that Rust provides.

What are your suggestions?

I’m really glad to see this proposal. Beyond the immediate benefits mentioned, I think this change has a very interesting architectural impact—especially for Kernel, WASM and Embedded systems.

In many ways, this feels like a distinct and effective alternative to the no_std pattern in Rust. Instead of having a default environment that developers might need to opt-out of, Mojo’s move toward explicit imports allows us to build from the ground up. It feels very natural and aligns well with the “pay-for-what-you-use” philosophy of C++ (#include <stdlib.h>) and the explicit nature of Python (import math).

This approach provides a clean, predictable path for resource-constrained environments to pull in exactly what they need, without any implicit overhead.

One quick thought: To balance this with developer experience (DX) for rapid prototyping, is there any plan to support from std import *? It would be a nice “middle ground” for scripts where the full standard library is desired, while still keeping the overall system explicit and opt-in.

Speaking as a Python developer and someone who encourages other Python developers to try Mojo, please don’t do this, it is a bad idea. import std.memory is C++ style, not Python.

Python programmers have spent decades writing code where import searches the built in standard library first. If you want to write a module with the same name, a Python program must explicitly import from . or somewhere.

It works well in Python because again for decades we’ve been assuming that the standard library is extensive and very often you’re importing more standard modules than you are private. If there’s a name clash between a standard library module and a program-specific, the usual advice is to rename your module.

1 Like

I comply with you but it’s no longer a python case consider it a rust like case

I am largely indifferent between from memory import * and from std.memory import *.

However, I am not convinced by the argument that this change allows non-stdlib modules to use the same names as standard library modules. In my opinion, that would introduce unnecessary ambiguity.

If from memory import * could resolve to a third-party module while from std.memory import * refers to the standard library, the behavior could become confusing and potentially misleading.

In general, it is preferable for the standard library to have clear and stable naming, and for third-party packages to avoid shadowing those names. This reduces ambiguity and helps users reason about where functionality is coming from.

Part of the reason to move to std.* is because Modular is taking pains to make sure the standard library for Mojo is less “special”. Both Rust and C++ have run into problems where the standard library is the only place with “permission” to do certain things, and thus accumulates far more than it really needs to. This also dramatically reduces the namespace occupied by the standard library, so that we can add a new section to it without it being a breaking change. If we didn’t have this, then your code could be broken by us adding a new module, meaning we’d have to push that out to Mojo 2.0. Doing it this way means that we can tell people to not use the std namespace and work inside of that. You are right that this is more of a C++/Rust style of thinking, but that’s partially because Python has the luxury of breaking compatibility frequently. Systems languages do not, because it is expected that very large codebases will exist in them (millions of lines), which may take months or years to migrate.

4 Likes

The proposal notes that Python imports from standard library were controversial and other options were considered. True, but ultimately Python came down on the side of not making everyone rewrite every single import statement.

Is the Python import from standard perfect? Of course not. But it is good enough, widely used and understood by gazillions of potential Mojo developers. (OK, widely used by gazillions, and understood by a much smaller fraction.) The problems that can occur are well known, and when they occur even novices will easily find help.

I don’t disagree with the concept of making the standard namespace less special, just with breaking every existing Mojo/Python program in doing so.

My suggested modification:

import memory continues to work, now and forever. No deprecation warning, but sure add some message about no longer being recommended style, the same severity as not having a full stop in a docstring.

Add package std around the standard library. People can write

import std.memory

or

from std import memory

as they prefer. This becomes the recommended style, used in tutorials and examples. (Heck, I could even see this being adopted in Python itself.)