once_cell icon indicating copy to clipboard operation
once_cell copied to clipboard

impl Display for Lazy<T: Display>

Open nalply opened this issue 5 years ago • 6 comments

Use case: I have some Lazy<&'static str> fields.

An example inside a macro from a project:

pub const DESCRIPTION: &'static str = $description;

pub const VALIDATION_REGEX: Lazy<&'static str> = Lazy::new(
  || Box::leak(trim_1_1(&rx::$rx.as_str()).into_boxed_str()));

Then format!("validation failed, must match {}", Docid::VALIDATION_REGEX) fails because Lazy<&'static str> doesn't implement Display. To get this to work, use &*Docid::VALIDATION_REGEX instead or Lazy::force().

It might be surprising for people that DESCRIPTION and VALIDATION_REGEX are different, and the solution with &* is possibly not very self-evident.

That's why I propose here: Lazy could implement Display if the value implements Display.

An open question is whether Lazy could implement other traits, too, as it has been done for unsync::OnceCellwith Clone (https://github.com/matklad/once_cell/issues/4).

nalply avatar Feb 27 '20 12:02 nalply

@matklad Would a PR implementing this be accepted? I'm also interested in implementing impl<T, U> AsRef<U> for Lazy<T> where T: AsRef<U> for similar reasons.

jhpratt avatar May 12 '20 21:05 jhpratt

I am really torn about this...

On the one hand, forcing in display and as_ref seems surprising.

On the other hand, Lazy is really just a convenience type, it does implicit forcing in deref

On the third hand, it seems like this would be a relatively minor convenience, and, where you need it, it's not too hard to newtype lazy

On the fourth hand, I am pretty sure that we'd go with concervative option for std, so, once std-lazy rfc is implemented, it makes sense to be expand once_cell API considerably, just to try more stuff out outside of std.

matklad avatar May 13 '20 22:05 matklad

This would turn into a never ending stream of requests to forward one trait after another. It seems like a better solution would be to solve the problem for deref coersions in general at the language/core level.

briansmith avatar May 13 '20 22:05 briansmith

Yeah, that's definitely true. Perhaps waiting for this to get into std would be best. I just ran into AsRef because I was iterating over a reference, which led to a triple dereference, something I'd never had to do before.

If there were some way to automatically implement all traits implemented by the inner type, that would be ideal. But I'm fairly certain that's neither possible nor desired in the compiler.

jhpratt avatar May 13 '20 23:05 jhpratt

Wow, a triple dereference. Can you show the code?

nalply avatar May 14 '20 05:05 nalply

(Un?)fortunately I already rewrote that bit of code to avoid it. One of the dereferences was due to the iterator, the second was because I was iterating over references (to avoid taking ownership), and the third was followed by a reference (equivalent to Lazy::force). I certainly wouldn't say it was unidiomatic, but rather a side effect of how I was passing data around.

jhpratt avatar May 14 '20 05:05 jhpratt

Thinking about this more, I am inclined to close this issue. It's important that operatiof of forcing a Lazy is visible in the source code. I recall debugging several performance issues in my IntelliJ day which boiled down to "stuff is printing to logs, and printing forces lazy evaluation".

matklad avatar Jun 03 '23 19:06 matklad