pre-RFC: life-before-main / lib init


typetag, one of recent “crates of the week”, depends on ctor and with missing ctor calls you may suddenly get deserialization problems, I expect.

Can this example (a TWiR-approved crate that uses ctor) start C++-esque tradition of relying on life-before-main?


@dtolnay I couldn’t find anything in the docs for typetag, inventory or ctor on why any of this needs to be implemented with life-before/after-main instead of making the client app write something like typetag::init() in main().

Is the life-before-main stuff “just” to enable writing libraries that don’t virally “infect” all transitive dependents and their client apps with a need to explicitly init() the library in main()? Could this be controlled by cargo features? Is the inadequacy of cargo features for transitive dependency config (ping @kornel) a factor here? etc.


I intend to switch it from inventory to linkme which does not involve ctors or any dynamic initialization.


Cargo features are separate from Rust language features, and Cargo can’t nicely set language features (overriding compiler flags for the entire build is a blunt tool), so there’s a hypothetical inadequacy, but I don’t think that’s the reason.

Not having code before main is a very useful property for a low level language.

It means it’s easily interoperable with C. It means it can be used in a static library linked with any other programming language. It means it can work easily as a dynamic library used as a plug-in in lots of native software, and in all these cases every function you export from Rust will just work.

If Rust could depend on some global code automagically run outside of main, then it could break if that magic isn’t always properly set up. It would mean that externally calling some random Rust function (from C, from other language’s FFI, from plug-in host) could hit Rust by surprise in a semi-uninitialized state with broken globals.

OP’s motivation: running env_logger::init() for every test is a real problem. BUT I think it’s better to solve that one with test frameworks that have setup and teardown, without adding a potentially problematic feature to the entire language: