What is a real world example of using a unit struct? - struct

I read these docs about structs, but I don't understand about unit structs. It says:
Unit structs are most commonly used as marker. They have a size of zero bytes, but unlike empty enums they can be instantiated, making them isomorphic to the unit type (). Unit structs are useful when you need to implement a trait on something, but don’t need to store any data inside it.
they only give this piece of code as an example:
struct Unit;
What is a real world example of using a unit struct?

Standard library
Global
The global memory allocator, Global, is a unit struct:
pub struct Global;
It has no state of its own (because the state is global), but it implements traits like Allocator.
std::fmt::Error
The error for string formatting, std::fmt::Error, is a unit struct:
pub struct Error;
It has no state of its own, but it implements traits like Error.
RangeFull
The type for the .. operator, RangeFull, is a unit struct:
pub struct RangeFull;
It has no state of its own, but it implements traits like RangeBounds.
Crates
chrono::Utc
The Utc timezone is a unit struct:
pub struct Utc;
It has no state of its own, but it implements traits like TimeZone and is thus usable as a generic argument to Date and DateTime.

In addition to providing a basis for stateless trait implementations, you may also see unit structs created simply to serve as a marker (as mentioned in the quote) to be used in some other structure. Some examples:
In std::marker, there are PhantomData and PhantomPinned which are used to augment other types in concert with the compiler for variance, auto-generated traits, or other behavior. These in particular are special cases and not really a usable pattern outside the standard library.
You can see marker types used in the typestate pattern. Like Rocket<P> in Rocket v0.5. It uses P as simply an indicator of what "pahse" the application is in and provides methods only with specific phases (like can't configure after it is started). Technically Build/Ingite/Orbit are empty structs and not unit structs, but that distinction isn't meaningful here.
You can also see marker types used similarly for defining Format options in the tracing-subscriber crate. The Compact type (a unit struct) is used in conjunction with it to provide different methods and behavior that are not tied to itself directly (Compact implements no traits, and has no methods; the specialization comes from Format<Compact, T> implementing FormatEvent).

Related

Why do traits in Rust require that no method have any type arguments to be object safe? [duplicate]

This question already has answers here:
Why are trait methods with generic type parameters object-unsafe?
(2 answers)
Closed 1 year ago.
Is this requirement really necessary for object safety or is it just an arbitrary limitation, enacted to make the compiler implementation simpler?
A method with type arguments is just a template for constructing multiple distinct methods with concrete types. It is known at compile time, which variants of the method are used. Therefore, in the context of a program, a typed method has the semantics of a finite collection of non-typed methods.
I would like to see if there are any mistakes in this reasoning.
I will take this opportunity to present withoutboat's nomenclature of Handshaking patterns, a set of ideas to reason about the decomposition of a functionality into two interconnected traits:
you want any type which implements trait Alpha to be composable with any type which implements trait Omega…
The example given is for serialization (although other use cases apply): a trait Serialize for types the values of which can be serialized (e.g. a data record type); and Serializer for types implementing a serialization format (e.g. a JSON serializer).
When the types of both can be statically inferred, designing the traits with the static handshake is ideal. The compiler will create only the necessary functions monomorphized against the types S needed by the program, while also providing the most room for optimizations.
trait Serialize {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer;
}
trait Serializer {
//...
fn serialize_map_value<S>(&mut self, state: &mut Self::MapState, value: &S)
-> Result<(), Self::Error>
where S: Serialize;
fn serialize_seq_elt<S>(&mut self, state: &mut Self::SeqState, elt: &S)
-> Result<(), Self::Error>;
where S: Serialize;
//...
}
However, it is established that these traits cannot do dynamic dispatching. This is because once the concrete type is erased from the receiving type, that trait object is bound to a fixed table of its trait implementation, one entry per method. With this design, the compiler is unable to reason with a method containing type parameters, because it cannot monomorphize over that implementation at compile time.
A method with type arguments is just a template for constructing multiple distinct methods with concrete types. It is known at compile time, which variants of the method are used. Therefore, in the context of a program, a typed method has the semantics of a finite collection of non-typed methods.
One may be led to think that all trait implementations available are known, and therefore one could revamp the concept of a trait object to create a virtual table with multiple "layers" for a generic method, thus being able to do a form of one-sided monomorphization of that trait object. However, this does not account for two things:
The number of implementations can be huge. Just look, for example, at how many types implement Read and Write in the standard library. The number of monomorphized implementations that would have to be made present in the binary would be the product of all known implementations against the known parameter types of a given call. In the example above, it is particularly unwieldy: serializing dynamic data records to JSON and TOML would mean that there would have to be Serialize.serialize method implementations for both JSON and TOML, for each serializable type, regardless of how many of these types are effectively serialized in practice. This without accounting the other side of the handshake.
This expansion can only be done when all possible implementations are known at compile time, which is not necessarily the case. While not entirely common, it is currently possible for a trait object to be created from a dynamically linked shared object. In this case, there is never a chance to expand the method calls of that trait object against the target compilation item. With this in mind, the virtual function table created by a trait implementation is expected to be independent from the existence of other types and from how it is used.
To conclude: This is a conceptual limitation that actually makes sense when digging deeper. It is definitely not arbitrary or applied lightly. Generic method calls in trait objects is too unlikely to ever be supported, and so consumers should instead rely on employing the right interface design for the task. Thinking of handshake patterns is one possible way to mind-map these designs.
See also:
What is the cited problem with using generic type parameters in trait objects?
The Rust Programming Language, section 17.2: Object Safety Is Required for Trait Objects

What is the scope of a trait implementation on a type from the standard library in Rust?

The rust book says:
We can also implement Summary on Vec<T> in our aggregator crate,
because the trait Summary is local to our aggregator crate.
https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type
If my package uses another crate from crates.io, like rand, and rand implements a trait on a type in the standard library, like Vec<T>, will my code be able to see those methods?
I know there's a restriction where a trait has to be in scope for you to use its methods. If rand implemented a custom trait on Vec<T>, and I tried to use one of the methods in that trait within my crate, would the compiler tell me that I need to import that trait from rand before using those methods, or would it tell me that the methods don't exist? If it's the former, if I import the trait from rand, can I then use those methods on Vec<T>?
From my experimentation, if a crate implements a trait on a foreign type, that trait is accessible using the normal rules (that is, in order to call methods of that trait, you must bring it in into scope, but otherwise, nothing special is required). You don't need to do anything else.
For example, consider the crate serde, which provides facilities to serialize and deserialize data. It provides the traits Serialize and Deserialize, which allow data structures to define how they are serialized and deserialized into various formats. Additionally, it provides implementations of those traits for many built-in and std types (see here and here). I made a quick experiment here, and my code can use those traits without me having to do anything extra (in fact, as you'll see, since I never directly use those traits, I don't even have to bring them into scope).
So, to the best of my knowledge, the answer to your question is yes, your code can use a trait implemented by rand for Vec<T>. All you need to do is import that trait from rand.

How to avoid code duplication using traits in Rust? [duplicate]

Traits are used to group some functions to be implemented from a struct, but is it possible to access struct fields from within the trait?
I could imagine declaring fields inside the trait so that the fields are abstracted as well. I haven't found such a syntax; is there any other solution? Otherwise, it wouldn't be possible to have non-static methods using a trait, would it?
I know object oriented programming from C# and I'm playing around with Rust, trying to adapt the OOP functionality I already know from C#.
This sounds like you're misunderstanding how traits work. Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah).
If you're asking whether you can access fields of a struct from within that struct's implementation of a trait, then yes. The struct knows it's own type, so there's no problem.
trait Pet {
fn is_smelly(&self) -> bool;
}
struct Dog {
washed_recently: bool,
}
impl Pet for Dog {
fn is_smelly(&self) -> bool {
!self.washed_recently
}
}
If you're writing a default implementation of a trait (i.e. defining a method body within the trait), then no, you can't access fields. A default implementation can only use methods that are defined on the trait or in a super trait.
It would be useful to define fields in a trait's default implementation, so a struct implementing the trait would always have the same fields.
Apparently, the Rust team thinks the same but it is still a work in progress according to this RFC. It's a big change and it has been postponed, so I think the short answer is: you can't do it yet, but you might be able to do it in the future.
For now, you'll have to make do with less powerful traits.
You can make accessor function in default trait implementation, that must return field value/ref in child implementations, returning default value. Use it in other fn's in default implementation, and redefine accessor's in child implementation. Default implementation fn's will use redefined accessors as it's virtual fn's.

Common attribute for trait composition [duplicate]

Traits are used to group some functions to be implemented from a struct, but is it possible to access struct fields from within the trait?
I could imagine declaring fields inside the trait so that the fields are abstracted as well. I haven't found such a syntax; is there any other solution? Otherwise, it wouldn't be possible to have non-static methods using a trait, would it?
I know object oriented programming from C# and I'm playing around with Rust, trying to adapt the OOP functionality I already know from C#.
This sounds like you're misunderstanding how traits work. Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah).
If you're asking whether you can access fields of a struct from within that struct's implementation of a trait, then yes. The struct knows it's own type, so there's no problem.
trait Pet {
fn is_smelly(&self) -> bool;
}
struct Dog {
washed_recently: bool,
}
impl Pet for Dog {
fn is_smelly(&self) -> bool {
!self.washed_recently
}
}
If you're writing a default implementation of a trait (i.e. defining a method body within the trait), then no, you can't access fields. A default implementation can only use methods that are defined on the trait or in a super trait.
It would be useful to define fields in a trait's default implementation, so a struct implementing the trait would always have the same fields.
Apparently, the Rust team thinks the same but it is still a work in progress according to this RFC. It's a big change and it has been postponed, so I think the short answer is: you can't do it yet, but you might be able to do it in the future.
For now, you'll have to make do with less powerful traits.
You can make accessor function in default trait implementation, that must return field value/ref in child implementations, returning default value. Use it in other fn's in default implementation, and redefine accessor's in child implementation. Default implementation fn's will use redefined accessors as it's virtual fn's.

How do I use instance variables of generic structs in traits? [duplicate]

Traits are used to group some functions to be implemented from a struct, but is it possible to access struct fields from within the trait?
I could imagine declaring fields inside the trait so that the fields are abstracted as well. I haven't found such a syntax; is there any other solution? Otherwise, it wouldn't be possible to have non-static methods using a trait, would it?
I know object oriented programming from C# and I'm playing around with Rust, trying to adapt the OOP functionality I already know from C#.
This sounds like you're misunderstanding how traits work. Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah).
If you're asking whether you can access fields of a struct from within that struct's implementation of a trait, then yes. The struct knows it's own type, so there's no problem.
trait Pet {
fn is_smelly(&self) -> bool;
}
struct Dog {
washed_recently: bool,
}
impl Pet for Dog {
fn is_smelly(&self) -> bool {
!self.washed_recently
}
}
If you're writing a default implementation of a trait (i.e. defining a method body within the trait), then no, you can't access fields. A default implementation can only use methods that are defined on the trait or in a super trait.
It would be useful to define fields in a trait's default implementation, so a struct implementing the trait would always have the same fields.
Apparently, the Rust team thinks the same but it is still a work in progress according to this RFC. It's a big change and it has been postponed, so I think the short answer is: you can't do it yet, but you might be able to do it in the future.
For now, you'll have to make do with less powerful traits.
You can make accessor function in default trait implementation, that must return field value/ref in child implementations, returning default value. Use it in other fn's in default implementation, and redefine accessor's in child implementation. Default implementation fn's will use redefined accessors as it's virtual fn's.

Resources