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

I think adding a string litteral form for Strings (e.g d"…") will be shorter and more productive, as the current way is either String::from("...") or "...".to_string, it’s fine but sometimes it get tedious and feels that String is unrelated to str while they’re basicly the same type (at least in many other languages).

This has been discussed before. A lot. See here, here, here, here, related topics here, here, and here. Undoubtedly there’s more out there.

7 Likes

New prefixes are a breaking change in the presence of macros, so this would probably need to be a next-edition kind of thing.

2 Likes

Wow!, I didn’t know it’s such a wanted feature, I would like some non-std string litteral in rust.

Can you elaborate? How can it break?

Consider

macro_rules! foo {
  ($x:expr) => {}
  (d$x:expr) => {}
}
4 Likes

I’ll not say whether I’m in favor of some sort of String literal or not…

…However, do note that there’s a difference between hypothetical breakage and actual demonstrated breakage. …I think it would be fine to try to crater run this to see if it would actually break anyone’s code; if it doesn’t, then depending on how sure we are we could do it within an edition I think.

3 Likes

To me, String::from appears to be more orthogonal than a special prefix or suffix, because the transformation is unlinked from the literal. Consider the following application:

use std::collections::HashMap;

macro_rules! map {
    ( $f:expr,$g:expr; $( $key:tt: $value:expr ),*) => {{
        let mut temp_map = HashMap::new();
        $(temp_map.insert($f($key),$g($value));)*
        temp_map
    }}
}

fn main() {
    let m = map!{|x| x, String::from;
        "Alder": "Alnus",
        "Ash"  : "Fraxinus excelsior",
        "Maple": "Acer",
        "Oak"  : "Quercus"
    };
    println!("{:?}",m);
}

Note that the type of m may be changed afterwards by changing a single line.

1 Like

Typically what you’d do here is get rid of $f and $g and instead write

$(temp_map.insert($key.into(), $value.into());)*

and require a type annotation. foo.into() is almost always what you want; I typically go &'static str to String via "...".into() which is quite painless. Among other things, it makes it clear that you hit malloc. It’s a similar deal with vec!; it’s painless but makes it very clear you’re making an allocation.

1 Like

Perhaps, but the string literal doesn’t remove this option. String::from isn’t going anywhere.

You are absolutely right that String::from is more orthogonal and less special; but the point of syntactic sugar is not orthogonality or being general; it is to take a pattern that occurs frequently and make it more ergonomic (and/or readable).

In judging whether we should add syntactic sugar you should ask yourself 1) whether the sugar will be frequently used, 2) how much it aids in ergonomics, 3) if it is an operation we wish to encourage, and 4) if that offsets the drawbacks of increased complexity.

I did a quick search for String::from which found 8,708 occurrences of it. Meanwhile, a search on GitHub turned up 35,929 occurrences.

1 Like

Raw numbers like that don’t mean much unless you’ve got a sense of scale. $5 is a large amount for a stick of gum, but it’s nothing in the world economy. Are 8708 occurrences a lot?

2 Likes

I don't know; I'm not making a value judgment; but now you have some data to use.

I only bring it up, because in the interest of making good decisions, it is unprofessional to publish unlabeled graphs and unscaled measurements. It’s “data to use” doesn’t really invite people to use the data correctly; most people will use such data to reinforce their biases, not to dig into a rationally constructed evaluation. (Besides, as data, it doesn’t do much. Are those calls on string literals? Does it account for .into()?)

5 Likes

Please have a little faith in people on this forum to understand that this data is rough and quickly assembled and to not draw too large conclusions.

Those are good questions to ask in further evaluation; but for an initial quick search it is certainly enough to pique my interest.

Let's now please get back on topic.

Why does it pique your interest? My point is that it should not pique your interest. If the result returned 0 matches, wouldn't we just conclude the syntax sugar doesn't actually change anything? If it returned millions of matches, wouldn't that also indicate that people really like String::from?

Usage numbers don't mean anything in syntax. The good syntax is usually commonly used, and the bad syntax needs improvement only if it is commonly used. You should expect the same numbers in either case.

These kinds of issues are much more cleanly handled when we understand that they are arbitrary. You trade some convenience in the common case for some complexity or inefficiency in the edge cases, and you weigh that against the market-appeal of being able to write code easily for simple problems. The other threads on this topic already cover it quite well... so what's new here?

Let’s now please get back on topic.

This is the topic:

In judging whether we should add syntactic sugar you should ask yourself 1) whether the sugar will be frequently used, [...]

2 Likes

Of course they do... If a certain pattern is repeated over and over again at some point it turns into boilerplate, which is usually not helpful for reading, maintaining and writing code. At that point, we should ask ourselves if sugar would be helpful. Conversely, if something isn't frequently used, then there is little reason to add any sugar. However, usage isn't everything. We must also ask whether in this case introducing s"foo" would lead to people over allocating because it would be too easy. If it turns out that this would be a sufficiently manifested problem in practice, that would be a reason why we wouldn't introduce said sugar.

In the case of try! the sugar was added in the first place because it was so common a pattern. After that, it turned out that the sugar wasn't optimal wherefore we changed it to ?.

It piques my interest to do further research (i.e. read the threads noted in the 2nd comment and more); not to propose or advocate anything now.

I think counts for String::from are particularly special because they’re what the book uses

so they may well be more common in trying-to-be-extra-explicit beginner code, but at the same time some experienced people prefer using one of the other options

1 Like

It would not be overused because "" is less obscure than String lits... but it would be overused because it would be too easy... except most APIs take &str, so String lits wouldn't be needed... but people would be putting &str in HashMaps and Vecs, and String lits would band-aid the problems with that... except that when building 'real' applications, we usually populate these with non-literal data... except when building dynamic error handling structs... and how often does that happen? And do we even care, when the decisions we make today will fundamentally impact the kind of code people write code in the future? We just did a grandfather paradox to ourselves.

This is what I mean when I say "arbitrary." You need a moral framework to evaluate competing possibilities. There needs to be principles at stake. You can't solve moral questions by simply pattern matching on historical data; you can't ask "what are people doing?" to answer "what should we have them do?" Instead, you ask "what are people not doing that they should be doing?"

For instance, you did a search for String::from and got ~8700 hits, but I did a search for String::from(" and got only ~500. And that still doesn't tell us that people should have done anything differently, because we don't know how many times they should be calling String::from, even if it had different syntax...

If a certain pattern is repeated over and over again at some point it turns into boilerplate, which is usually not helpful for reading, maintaining and writing code.

I disagree on all three points in general. Repetition is very helpful. If you work too hard to get rid of it, you are getting rid of pedagogical clues and lessons (as learning requires repetition), tools for emphasis and symmetry, and ultimately just trying to compress source code, which is not how anybody wants to work. Nobody is seriously trying to code-golf, compress, and obfuscate their application source code with symbolic indirection.

They're trying to get rid of noise, which is definitely here for String::from -- directly in the symbols and indirectly in its impact on indentation and line width (EDIT: People might also just really want to be avoiding an extra set of parens!) -- but what level of noise reduction is excessive?

I don't know how you can be so sure that this statement is right. You could very well be right; but I cannot state it with such surety.

Sure; I agree with everything in this paragraph. These are questions we must also ask.

The sum total of ".into() and ".to_owned() makes for 8190 occurrences.

But yours is an interesting data point to consider, it does make me less interested.

Answering such questions is usually highly difficult and I don't think we usually set such high standards or do that research when developing new language features. We simply don't have the bandwidth for that.

This is something to keep in mind yes; when we do add features such as lifetime elision, implied bounds, type inference, and the ? operator, we are trading required repetition, which may help in learning, for convenience, which can also help in learning because otherwise the learning process feels punishing and the learner might just give up.

I don't think those that desire s"foo" to work are trying to code golf... and we didn't want to do that when we added ?, yet you may call that "symbolic indirection".

That depends on how much something is used (if it is used more, then documentation should talk about it more, and the sugary form will be well known which mitigates drawbacks...) and at what point noise reduction becomes harmful. In Rust, we considered it acceptable to reduce error propagation down to a single letter, ?. Haskell uses two characters (<-). In Java, they reduced it to zero characters.