String::from("...") => d"..."


Ok, I think we’re pretty much on the same page, barring some minor potential misunderstandings that I won’t waste time on. Thanks for your patience. I do have this ridiculous compulsion to yak on.

Though I would like to point out that, with this issue specifically, I don’t personally see any horses in any races. Compare s"" to r""… At the end of the day, does r"" seem like a mistake? Does it really even matter how many times it is used, or how specialized the applications using it are? Or how beginner unfriendly the #-syntax is?

People will get used to the convenience until they can’t live without it. Or at least, until after a short-yet-frustrating period of relearning to live without it. In either case, I think there’s no real damage being done whether this syntax is available or not. (Assuming it doesn’t cause breakage problems in practice.)

EDIT: On second thought, there is something that would irk me bit. A String literal syntax would make std::String a little more special, and introduce a kind of ergonomic penalty for using non-std string types.


In a sense, this problem already exists for all the other literal types. In my current project, I use a lot of r32 and r64s. I can’t construct them with literals, which is an incessant pain.

I’d really like to see implicit literal coercion in general. If combined with the ability to construct heap-allocated values at compile time, String literals would be both free, and something that could be added to std.


Extending that slightly to include panics at compile time (which are—as far as I know—closer to stabilisation) (EDIT: and const traits, which is… not anywhere near stabilization) there could be a very simple macro to handle this for arbitrary types:

// No idea what to call it, so...
macro_rules! d {
    ($($tt:tt)*) => {{

// Just a guess at what you're referring to
type r32 = ::num::rational::Rational32;

const STRING: String = d!(foo);
const RATIONAL: r32 = d!(2 / 10);

Whether this is good enough, or needs some language level sugar ¯\_(ツ)_/¯


This is getting off-topic, but just to clarify:

  • Make literal types like {integer} actual types that can be accepted by const fns, but which cannot exist at runtime (“ephemeral” types).
  • Implicitly invoked trait: trait FromLiteral<T: Ephemeral> { const fn from_literal(_: T) -> Self; }. This then retroactively becomes how an integer literal turns into a concrete i32, for example.
  • Some kind of scheme where you could say #[freeze_safe] pub struct String { #[follow] ptr: *mut u8, ... } to indicate that it’s safe to just dump a type’s contents into a binary and never drop it. Such types could be returned from const fn and stored in consts or statics.

At that point, you could implement FromLiteral<{str}> for String and Robert’s your mother’s brother.

(Incidentally: r32 is my "f32 sans NaN" type; “r” is for “real” (yes, I know that infinity is not in ℝ, I don’t care).)


Why isn’t this the default case for all statics? I’ve got this nagging feeling it has to do with concurrency and data races, but can’t make it concrete atm.


No opinion on the subject, but I just want to know what d would stand for & I’m confused why no one has asked yet, is this obvious to everyone else?


I assume it stands for “dynamic”; I think no one has brought it up because there are more interesting semantic questions :wink: Presumably we would bikeshed this and come up with an appropriate prefix if we wanted to do it.