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

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.

Related

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.

Implement foreign trait for foreign type [duplicate]

This question already has answers here:
How do I implement a trait I don't own for a type I don't own?
(3 answers)
Closed 7 years ago.
So I see there are reasons to forbid orphan trait implementations because of forward compatibility considerations (to prevent the addition of a further trait implementation in a library from breaking somewhere where the type's trait is used) and it possibly making compilation a lot more difficult. But I wonder which workaround would be considered by the Rust community to be the most ideal one:
(Just in case this wasn't enough background: I am trying to use rusqlite with chrono's DateTime. So I want to implement rusqlite's FromSql and ToSql traits for DateTime<UTC> but that's apparently not as easy as I thought it'd be - I'm just starting out with Rust currently.)
Fork rusqlite and implement the trait. (I kind of feel like this is not the nicest way to do it because maybe it's just me who needs this trait implementation there and so I might end up having to keep my own fork up to date. Also I wasn't able to implement the traits because there are some complicated generics things that I don't understand perfectly yet.)
Implement my own DateTime struct (probably the best workaround but I feel like this is just some replication of work that shouldn't be nescessary).
Somehow "copy" the DateTime<UTC> trait and give it an alias and implement the FromSql and ToSql traits for my aliased type (however I think this is not trivial either and when I tried it I wasn't able to get it to work since it was still treated as an external type).
I hope somebody can explain to me how to best solve this issue, from my pure OOP experience I would just like to be able to inherit DateTime and implement the interface but (for valid reasons) this is not how it gets done in Rust...
The simplest way would be to use newtype pattern:
extern crate a;
extern crate b;
use a::SomeTrait;
use b::SomeStruct;
pub struct MySomeStruct(SomeStruct);
impl SomeTrait for MySomeStruct {
...
}
Here you create a wrapper around the foreign struct, and since this wrapper is a completely different type which belongs to your crate, you are free to implement a::SomeTrait for it. This is similar to your 2nd point, except that you absolutely don't need to reimplement the type from scratch.
Naturally, you won't be able to call all methods of SomeStruct on MySomeStruct. You must either forward all methods you want, or unwrap the inner value when you don't need its trait implementation anymore, or you can impl Deref for MySomeStruct { type Target = SomeStruct; ... }, but the latter is considered an antipattern.
I'm not sure what would be the most idiomatic, but it looks like the best approach would be to use the newtype pattern, which is a tuple-struct with one field. This creates a new type distinct from the old one, and you can implement the traits for that new type. To use the trait methods, you will need to wrap it in the newtype, but to use the normal methods, you'll use the normal struct without your newtype wrapper.
struct MyType(TheirType);
impl TheTrait for MyType {
....
}
fn main() {
let a = TheirType::new(....);
a.method_on_their_type();
let b = MyType(TheirType::new(....));
b.method_on_the_trait();
}

Is there a way other than traits to add methods to a type I don't own?

I'm trying to extend the Grid struct from the piston-2dgraphics library. There's no method for getting the location on the window of a particular cell, so I implemented a trait to calculate that for me. Then, I wanted a method to calculate the neighbours of a particular cell on the grid, so I implemented another trait.
Something about this is ugly and feels unnecessary seeing as how I'll likely never use these traits for anything other than this specific grid structure. Is there another way in Rust to extend a type without having to implement traits each time?
As of Rust 1.67, no, there is no other way. It's not possible to define inherent methods on a type defined in another crate.
You can define your own trait with the methods you need, then implement that trait for an external type. This pattern is known as extension traits. The name of extension traits, by convention, ends with Ext, to indicate that this trait is not meant to be used as a generic bound or as a trait object. There are a few examples in the standard library.
trait DoubleExt {
fn double(&self) -> Self;
}
impl DoubleExt for i32 {
fn double(&self) -> Self {
*self * 2
}
}
fn main() {
let a = 42;
println!("{}", 42.double());
}
Other libraries can also export extension traits (example: byteorder). However, as for any other trait, you need to bring the trait's methods in scope with use SomethingExt;.
No. Currently, the only way to write new methods for a type that has been defined in another crate is through traits. However, this seems too cumbersome as you have to write both the trait definition and the implementation.
In my opinion, the way to go is to use free functions instead of methods. This would at least avoid the duplication caused by traits.

Do I have to 'use' a trait in order to call methods defined in that trait?

I'm toying with the cgmath library. I have the following main.rs file:
extern crate cgmath;
use cgmath::vector::{Vector3, EuclideanVector};
fn main() {
let mypoint = Vector3 { x: 1f64, y: 1f64, z: 3f64 };
println!("The length of the vector is {}, and the length squared is {}", mypoint.length(), mypoint.length2());
}
In my use line, when I omit EuclideanVector, I am given the following compilation error:
type 'cgmath::vector::Vector3<f64>' does not implement any method in scope named 'length'
It appears that the Rust compiler cannot find the length() method unless I import one of the traits that Vector3 uses. Delving into the source code, it looks like the length method is defined within the EuclideanVector trait.
Intuitively, I should not need to import an trait to use a type that inherits said trait. Is there a technique to do so that I am missing? Is this a nuance specific to the cgmath library? Is this an idiomatic part of Rust that I should become accustomed to?
You're thinking of traits in terms of inheritance. It might make more sense if you think of a trait as a module that's overloadable with respect to the Self type. From this perspective, it makes sense that the trait has to be in scope in order for the compiler to know about its methods, just as a module has to be in scope in order to use it. A particular implication of this is that implementations can be declared alongside the trait they implement rather than the type they implement it for. In this situation, clearly if your code doesn't know about the trait, it can't use its methods.
Another motivation for the current behaviour is that multiple traits can define methods with the same name, and when you have such a conflict for traits implemented for the same type, you can no longer use method call syntax to access their methods. Instead, you have to use function call syntax in order to specify which trait the method is a member of (the trait acting as the module the method is in). If method call syntax used all traits in your program rather than just the ones in scope for method resolution, you'd end up with these conflicts much more often, since you'd have name conflicts with methods in traits that your code isn't actually using directly.
Strictly speaking, you don't have to use use. Alternatively:
(&mypoint as &cgmath::vector::EuclideanVector).length2()
Yes, this is how Rust works. You must always import a trait before you can use its methods. This is by design.
If you really don't want to import, you can call cgmath::vector::EuclideanVector::length(&mypoint).
(I don't know if this was possible when the question was asked.)

Resources