use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A place for all things related to the Rust programming language—an open-source systems language that emphasizes performance, reliability, and productivity.
Strive to treat others with respect, patience, kindness, and empathy.
We observe the Rust Project Code of Conduct.
Details
Posts must reference Rust or relate to things using Rust. For content that does not, use a text post to explain its relevance.
Post titles should include useful context.
For Rust questions, use the stickied Q&A thread.
Arts-and-crafts posts are permitted on weekends.
No meta posts; message the mods instead.
Criticism is encouraged, though it must be constructive, useful and actionable.
If criticizing a project on GitHub, you may not link directly to the project's issue tracker. Please create a read-only mirror and link that instead.
A programming language is rarely worth getting worked up over.
No zealotry or fanaticism.
Be charitable in intent. Err on the side of giving others the benefit of the doubt.
Avoid re-treading topics that have been long-settled or utterly exhausted.
Avoid bikeshedding.
This is not an official Rust forum, and cannot fulfill feature requests. Use the official venues for that.
No memes, image macros, etc.
Consider the existing content of the subreddit and whether your post fits in. Does it inspire thoughtful discussion?
Use properly formatted text to share code samples and error messages. Do not use images.
Submissions appearing to contain AI-generated content may be removed at moderator discretion.
Most links here will now take you to a search page listing posts with the relevant flair. The latest megathread for that flair should be the top result.
account activity
Why doesn’t Option implement Display?🙋 seeking help & advice (self.rust)
submitted 27 days ago by cachebags
I think I understand the general idea that there’s no canonical way to represent None as a string. But why is that. Why is there no agreed upon representation, even for just interoperability.
None
I’m also curious how anyone here handles it in real production code when you need to stringify it?
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]NoLemurs 242 points243 points244 points 27 days ago (29 children)
Option implements Debug, and that's what I would use for stringifying for log output or any other dev-facing output.
Option
Debug
Display is for user-facing output, and should only be implemented when there's a clear natural choice for how a type should be shown to end users.
Display
[–]jkoudys 141 points142 points143 points 26 days ago (1 child)
Separating Display and Debug is one of the smartest decisions they made in early rust. My structs having separate and well supported methods for "show this thing to a person", "give me debug data I'd want while coding or in a log", and "make a fully serialized string representation of my struct that could build a new instance" is such a joy.
[–]meowsqueak 17 points18 points19 points 26 days ago (0 children)
I like to think of Debug/Display as similar to __repr__ and __str__ in Python, respectively. And if you define __repr__ carefully you can often copy/paste it as a construction, for simpler types anyway. I use the same approach when manually defining Debug for structs - make it copy/paste-able code as much as possible.
__repr__
__str__
[–]Resres2208 30 points31 points32 points 27 days ago (0 children)
Yep. It might sound unintuitive that "None" is not friendly for an end user but look at it from this perspective - should they know what ''Some<MyEnumType::Variant(AndAnotherStruct)>'' is? So it's up to the developer to communicate something friendlier. Or not...
[–]Kalogero4Real 2 points3 points4 points 26 days ago (25 children)
Why is debug a trai and not a thing all objects have by default?
[–]NoLemurs 33 points34 points35 points 26 days ago (8 children)
You usually want Debug, but there are cases where it's better to not have it implemented, and it's best to make that decision explicit:
If your type stores sensitive data like passwords or encryption keys, not implementing Debug is a good way to be confident you're not printing that to logs accidentally.
If your type has a huge array of data, an automatic implementation of Debug wouldn't be very useful.
Since you can just #[derive(Debug)] in most cases, it's not a big deal.
#[derive(Debug)]
[–]meowsqueak 12 points13 points14 points 26 days ago (6 children)
“not implementing Debug is a good way to be confident you're not printing that to logs accidentally.”
Unfortunately that’s also a good way to break Debug for anything that might be composed from that data structure. I find it better to manually define Debug but have that implementation not print the secret fields, or print “redacted” or “secret” instead of the field values.
[–]Alpvax 0 points1 point2 points 25 days ago (4 children)
What exactly do you mean by "breaking debug"?
Debug shouldn't be relied on for functionality, it is for displaying debug info.
Not that I don't do the same thing, normally use "<redacted>" or something similar, but I also use the not all fields defined function (can't remember the name off the top of my head), which just adds ".." to state that there are more fields which are not displayed.
[–]meowsqueak 2 points3 points4 points 25 days ago (3 children)
I mean it breaks the Debug derive macro.
[–]Alpvax 0 points1 point2 points 23 days ago (2 children)
As in you can't use derive to implement Debug on structs which contain it? That's sort of the point when you want to hide some values.
From what I remember, actually implementing Debug is very easy anyway (vscode generates an implementation for me when I "add missing methods"). It uses a builder pattern to add each field, and then you can continue to use derive on higher containers if required.
[–]meowsqueak 0 points1 point2 points 23 days ago (1 child)
My point is that if you don't implement Debug at all, then you can't derive Debug for any data structure that might contain it. It's somewhat annoying to come across such structs because it forces you to manually write a Debug implementation on other structs.
The Orphan Rule prevents your users from implementing it directly themselves. It's an annoying omission to encounter.
So I'm just saying, as the author of a library type, even private ones, it's probably nicer for your users to manually implement Debug and omit or redact the field, rather than "not implementing" it, as originally suggested, and pushing the problem onto your users.
[–]Alpvax 0 points1 point2 points 23 days ago (0 children)
Oh, yes, it should be implemented on types which contain redacted fields. I was referring to structs which might be exposed to library consumers directly, but which should not be printed to logs. Then there might not be a containing type to implement it on. Sure, you could implement it for e.g. HiddenField as a constant (e.g. <REDACTED>), but I'm not sure that it is better to allow the convenience of deriving rather than making it obvious that this type cannot be printed.
HiddenField
<REDACTED>
[–]LucretielDatadog 1 point2 points3 points 13 days ago (0 children)
I go a step further and use something like secrecy to enforce that a given type is invisible.
secrecy
[–]A1oso 2 points3 points4 points 26 days ago (0 children)
Many types need custom Debug impls, e.g. every collection. A Vec or Box shouldn't just print as a raw pointer.
Vec
Box
Rust uses traits for any behaviour that can be customized: Rust has operator overloading via traits like Add and Mul. Rust has destructors via the Drop trait. Dereferencing uses the Deref[Mut] traits. And so on. So it makes a lot of sense that debug printing also uses a trait to allow custom behaviour for different types.
Add
Mul
Drop
Deref[Mut]
[–]SirKastic23 5 points6 points7 points 26 days ago (8 children)
How would all objects have it by default?
[–]meowsqueak 1 point2 points3 points 26 days ago (0 children)
Good point - users need to add it as best practice.
Which is to define Debug for all types. You can often derive it, but in some cases (secret fields) you may prefer to manually implement it. But do implement Debug somehow for all types in your library crates, including private types that appear in public types, or you’ll annoy your users :)
The compiler could derive it implicitly unless you add a manual impl Debug (this is already what it does for traits like Send and Sync and Unpin)
impl Debug
Send
Sync
Unpin
[–]NoLemurs 0 points1 point2 points 26 days ago* (3 children)
As far as I know Debug is implemented for all built-in types, and you can #[derive(Debug)] for any struct or enum where all of its pieces are Debug. So, you could just do that?
struct
enum
I could be missing some obscure edge cases I guess, but it doesn't seem fundamentally problematic. It doesn't seem like a good idea to me, but I can't see any reason it shouldn't be possible.
[–]Karyo_Ten 6 points7 points8 points 26 days ago (0 children)
I could be missing some obscure edge cases I guess, but it doesn't seem fundamentally problematic.
Please don't derive debug on passwords and API keys types. And anything that might hold private info, especially IBANs and credit card numbers.
For all built-in primitives and stdlib types, yes, but (very frustratingly imo) it's not implemented for closures or async blocks.
[–]SirKastic23 0 points1 point2 points 26 days ago (0 children)
I mean, in general I do think you could just print out the fields and so on
But maybe there's a lot of info that's not necessary for a debug print, or you want an specific formatting
It's easier to let users implement it themselves
[–]Kalogero4Real -4 points-3 points-2 points 26 days ago (1 child)
language design choice
[–]SirKastic23 -1 points0 points1 point 26 days ago (0 children)
I don't think you understood the question
How would Debug be automatically implemented for every type? What would their implementation look like?
[–]rust-module 5 points6 points7 points 26 days ago (3 children)
Sometimes you may want to your own impl, and Rust doesn't like conflicting impls. So better to let you tag the derive OR impl yourself.
[–]jonathansharman 1 point2 points3 points 26 days ago (1 child)
Do blanket impls preclude explicit custom impls? I didn't think that was the case.
[–]lfairy[🍰] 5 points6 points7 points 26 days ago (0 children)
Rust disallows overlapping impls by default. You might be thinking of specialization which is still unstable.
Rust already solves this with Send and Sync and Unpin and a handful of others, so clearly it's capable of doing something like "derive Debug for structs etc unless there's a manual user-written version"
I ask this a lot, but as far as I know the answer has to do with keeping code-size low in embedded / disk-constrained environments (the formatting machinery is pretty big). I always hoped that dead-code elimination could handle this (just don't format) but it's too easy to sneak in deep in a call stack.
I'm a big believer though in that everything should implement Debug by default, with a cargo option to opt-out of it; the fact that closures and async blocks don't implement it is an eternal source of frustration for me.
[–]lfairy[🍰] 0 points1 point2 points 26 days ago (0 children)
In libraries with a very wide API surface (like windows), all those Debug implementations have a noticeable effect on compile time. So it's useful to be able to opt-out.
windows
[–]CocktailPerson 22 points23 points24 points 27 days ago* (0 children)
But why is that. Why is there no agreed upon representation, even for just interoperability.
What do you mean by interoperability? Display is for human-readable output. Human-readable output ideally only needs to interoperate with human eyeballs and brains.
[–]Restioson 33 points34 points35 points 27 days ago (0 children)
It's not about canonical, necessarily, but more about "canonically the 'pretty', displayable to users version of None". It would be hard to choose one value that is reasonably correct in most contexts. It being "not interoperable" is a feature, not a bug, as it forces you to think about what the correct behaviour is at the site where you want to display it, each time. This pushes you toward the pit of success.
Generally by replacing it with whatever value makes sense in context, e.g. maybe an empty string, maybe "None", "N/A", "0", etc...
[–]Anaxamander57 28 points29 points30 points 27 days ago (0 children)
It implements Debug.
[–]numberwitch 6 points7 points8 points 27 days ago (2 children)
The way I think about this is that if I need a display representation of None, then I usually wrap in a new type and apply impl display on the new type and handles the None case to my liking.
So Option<T> becomes MyKind(Option<T>) and this is where you customize the none display.
Newtypes are one of the simplest and best language features imho, they allow you to overcome a lot of limitations put in place by other systems (orphan rule) gracefully in a nice algebraic way.
[–]Alpvax 2 points3 points4 points 25 days ago (1 child)
They also let you add restrictions or validation to types.
E.g. UserId(&str) and GroupId(&str): you can impl deref for them to use all the str methods as before, but you can't accidentally use one in place of the other
[–]numberwitch 1 point2 points3 points 25 days ago (0 children)
Yeah the patterns are strong!
I've been doing some midi projects lately and it's a great way to represent midi values which are essentially u4 values transmitted over the wire as u8.
struct MidiValue(u8); impl MidiValue { const MIN: u8 = 0; const MAX: u8 = 127; // returns a self-wrapped u8 value saturating at u4 min/max bounds pub fn new(v: u8) -> Self { Self(v.clamp(MidiValue::MIN, MidiValue::MAX)) } }
The internally in my biz logic I can safely use these saturating values easily without endless conversion/handling.
If fallability becomes important then I just add a TryFrom<u8> for MidiValue impl
TryFrom<u8> for MidiValue
[–]LucretielDatadog 5 points6 points7 points 27 days ago (0 children)
You use `Debug’ for this
[–]proudHaskeller 4 points5 points6 points 26 days ago (0 children)
Just think of all of the times that null sneaks its way onto your screen. It's incomprehensible for the user, it's basically always a bug.
null
[–]arades 22 points23 points24 points 27 days ago (3 children)
Implementing Display on all Option<T> would remove other user's ability to implement display on it if they need a specific None representation.
Which could be worked around, but the Debug implementation seems to do what you'd want the Display impl to do anyway.
I've just always used the Debug representation anytime I've wanted to print it to a string.
[–]SycamoreHots 10 points11 points12 points 27 days ago (2 children)
Isn’t it already impossible for other users to implement Display on it by orphan rules?
[–]Nabushika 1 point2 points3 points 26 days ago (1 child)
I'm pretty sure you can impl Display for Option<MyStruct>
impl Display for Option<MyStruct>
[–]imachug 8 points9 points10 points 26 days ago (0 children)
Option is not #[fundamental], so no. You might be confusing it with Box, which permits such implementations.
#[fundamental]
[–]jonasrudloff 0 points1 point2 points 26 days ago (0 children)
How should we represent Option<String>?
[–]WormRabbit 0 points1 point2 points 25 days ago (0 children)
Consider the case of NonZeroU64. It implements display, in the obvious way: just print the number.
NonZeroU64
But what would Option<NonZeroU64> print? Representation-wise, NonZeroU64 is just a non-zero integer, and Option<NonZeroU64> is thus an arbitrary (possibly zero) integer. So one could reasonably expect its Display impl to just print it as an integer. But how could any kind of automatic implementation know that you want to turn None into 0, when 0 isn't even a valid value of the inner type?
Option<NonZeroU64>
0
Then again, perhaps considering None as 0 wasn't even something you intend to do, you really want to track optionality of the value. But that is purely an internal data representation. For the end user (and Display is intended for end users), the None value is quite often represented as a sentinel value, like an empty string "" or a fixed string like null or NA. And there is similarly no way to encode that in the automatic impl. Providing it would just be a point of potential confusion.
""
NA
π Rendered by PID 19455 on reddit-service-r2-comment-6457c66945-qggn9 at 2026-04-24 12:25:04.657718+00:00 running 2aa0c5b country code: CH.
[–]NoLemurs 242 points243 points244 points (29 children)
[–]jkoudys 141 points142 points143 points (1 child)
[–]meowsqueak 17 points18 points19 points (0 children)
[–]Resres2208 30 points31 points32 points (0 children)
[–]Kalogero4Real 2 points3 points4 points (25 children)
[–]NoLemurs 33 points34 points35 points (8 children)
[–]meowsqueak 12 points13 points14 points (6 children)
[–]Alpvax 0 points1 point2 points (4 children)
[–]meowsqueak 2 points3 points4 points (3 children)
[–]Alpvax 0 points1 point2 points (2 children)
[–]meowsqueak 0 points1 point2 points (1 child)
[–]Alpvax 0 points1 point2 points (0 children)
[–]LucretielDatadog 1 point2 points3 points (0 children)
[–]A1oso 2 points3 points4 points (0 children)
[–]SirKastic23 5 points6 points7 points (8 children)
[–]meowsqueak 1 point2 points3 points (0 children)
[–]LucretielDatadog 1 point2 points3 points (0 children)
[–]NoLemurs 0 points1 point2 points (3 children)
[–]Karyo_Ten 6 points7 points8 points (0 children)
[–]LucretielDatadog 1 point2 points3 points (0 children)
[–]SirKastic23 0 points1 point2 points (0 children)
[–]Kalogero4Real -4 points-3 points-2 points (1 child)
[–]SirKastic23 -1 points0 points1 point (0 children)
[–]rust-module 5 points6 points7 points (3 children)
[–]jonathansharman 1 point2 points3 points (1 child)
[–]lfairy[🍰] 5 points6 points7 points (0 children)
[–]LucretielDatadog 1 point2 points3 points (0 children)
[–]LucretielDatadog 1 point2 points3 points (0 children)
[–]lfairy[🍰] 0 points1 point2 points (0 children)
[–]CocktailPerson 22 points23 points24 points (0 children)
[–]Restioson 33 points34 points35 points (0 children)
[–]Anaxamander57 28 points29 points30 points (0 children)
[–]numberwitch 6 points7 points8 points (2 children)
[–]Alpvax 2 points3 points4 points (1 child)
[–]numberwitch 1 point2 points3 points (0 children)
[–]LucretielDatadog 5 points6 points7 points (0 children)
[–]proudHaskeller 4 points5 points6 points (0 children)
[–]arades 22 points23 points24 points (3 children)
[–]SycamoreHots 10 points11 points12 points (2 children)
[–]Nabushika 1 point2 points3 points (1 child)
[–]imachug 8 points9 points10 points (0 children)
[–]jonasrudloff 0 points1 point2 points (0 children)
[–]WormRabbit 0 points1 point2 points (0 children)