Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement dynamic string interpolation #10318

Closed
bstrie opened this issue Nov 6, 2013 · 4 comments
Closed

Implement dynamic string interpolation #10318

bstrie opened this issue Nov 6, 2013 · 4 comments

Comments

@bstrie
Copy link
Contributor

bstrie commented Nov 6, 2013

In a perfect world, a minimal quine in Rust would look like this:

fn main(){let S="fn main(){let S={1}{0}{1};println!(S,S,'{1}')}";println!(S,S,'"')}

Sadly, this is impossible. Why? Because println! requires that the first argument not just be static; it must be a string literal.

There are other, non-contrived use cases for dynamic string interpolation; acrichto mentions internationalization as one example.

So what would be involved in implementing dynamic string interpolation?

acrichto mentions (https://botbot.me/mozilla/rust/msg/7556963/) that the current machinery used to parse strings for format! provides an interface that could be reused (std::fmt). But that's only part of the solution.

The first issue is that we can't guarantee type safety for dynamic interpolation (can we???), so the syntax for dynamic format strings might need to be rethought. For now we should probably assume that all arguments to dynamic string interpolation will implement ToStr and just ignore any format string options that aren't for positional or named arguments.

The second issue is that we can't just simply have anything like a simple .format() method on strings, like Python has, since we don't have variadic functions. We'd need to either do something like pass an array of trait objects:

"ab{1}d{0}".format(["e" as ~ToStr, "c" as ~ToStr]);  // gross
dyn_format!("ab{1}d{0}", "e", "c");  // maybe a little less gross

...or use method chaining and generics:

fn push<T: Any>(&mut self, x: T) { self.vec.push(~x as ~Any) }
"ab{1}d{0}".format().push("e").push("c").to_str()  // still kinda gross

(all code examples are just quick sketches, might be overlooking details (and don't worry about naming))

Any thoughts?

@alexcrichton
Copy link
Member

I agree that this needs a library interface to be more useful. The original intent with the new format strings was to allow extensions for things like i18n and such, and even programs such as this could in theory be possible.

I don't think that there's any feasible usage outside of a macro due to the way it's structured. You're right in that this would likely require that all the arguments implement the same trait instead of having a mixture of possible traits. I would recommend taking a look at the expansion of the format! macro to see how it works, because this would likely employ something similar.

Sadly I'm not sure that this would be entirely useful until we get syntax extension import/export working because I do really think that this belongs in a library as opposed to the compiler (which I would love to move fmt::{print,format,println} to the prelude).

@huonw
Copy link
Member

huonw commented Nov 6, 2013

FWIW, something like "ab{1}d{0}".format([&("e") as &fmt::Dynamic, &("c") as &fmt::Dynamic]) would be better than using ~ToStr (since that has a forced allocation, and the ToStr trait is suboptimal).

@seanmonstar
Copy link
Contributor

Additional use case (unless there's a way to currently do this I haven't noticed):

struct Record {
  name: ~str,
  message: ~str
// etc...
}
struct Logger {
  name: ~str,
  stream: Writer,
  fmt: ~str
}
impl Logger {
  fn log(&mut self, message: ~str) {
    self.stream.write_line(self.format(Record{name:self.name, message: message}));
  }
  fn format(&mut self, record: Record) {
    std::format::dynamic_format(self.fmt, record) // <-- use case
  }
  fn setFormat(&mut self, format: ~str) {
    self.fmt = format;
  }
}

// else where
logger.setFormat(~"{name}.{level}: {message}");

@steveklabnik
Copy link
Member

I'm pulling a massive triage effort to get us ready for 1.0. As part of this, I'm moving stuff that's wishlist-like to the RFCs repo, as that's where major new things should get discussed/prioritized.

This issue has been moved to the RFCs repo: rust-lang/rfcs#642

Jarcho pushed a commit to Jarcho/rust that referenced this issue Feb 26, 2023
Fix false positives for `extra_unused_type_parameters`

Don't lint external macros. Also, if the function body is empty, any type parameters with bounds on them are not linted. Note that only the body needs be empty - this rule still applies if the function takes any arguments.

fixes rust-lang#10318
fixes rust-lang#10319
changelog: none
<!-- changelog_checked -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants