# Pre-RFC new trait Set, impl on struct fields

**URL:** <https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383>\
**Category:** language design\
**Created:** [April 24, 2018, 2:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383 "2018-04-24T14:10:57Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 2:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/21 "2018-04-25T14:39:59Z")

</div>

But we already have `AddAssign` and other traits like it. The same argument could be made that they shouldn’t exist and only really do is use the `Add` trait in a shorter syntax. But we don’t and thus I don’t agree that changing how assignment operators (for fields in structs only) would be any less reliable or correct.

No I don’t want to use C++, Rust has better ergonomics (syntactically in general) and much better guarantees. Also I don’t see how this breaks assumptions of unsafe code at all. I should probably change my initial post since what I now am proposing has changed. Basically these traits would work more like C#'s `get; set;` where internally they still have to be represented by a private field that can be `memcpy`-ed so that wouldn’t break at all.

Yes I did author that RFC but also, that is not about traits but about Annotations which I would argue are quite different.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 2:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/22 "2018-04-25T14:41:31Z")

</div>

The point of this is exactly that contract so that the you can enforce what sort of values are stored and what to do when they are stored. Just in a much nicer looking structure

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [April 25, 2018, 2:53pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/23 "2018-04-25T14:53:58Z")

</div>

To me the underlying issue is one of the reader's intuition:

- If I see an assign operator (e.g., `=`), I think of that compiling to a possible addressing computation and a store.

- If I see an X-assign operator (e.g., `+=`), I think of that compiling to a possible addressing computation, a fetch and a store (with the advantage over separate assign and unary/binary-op that the target's addressing need only be defined once, and that in some architectures the load-modify-store may be a single instruction).

- If I see a setter or getter method, I know that I can't intuit the compilation result and thus have to examine the method definition.

As of the time of my writing, the [most recently posted](https://users.rust-lang.org/t/twir-quote-of-the-week/328/517) "TWIR quote of the week" on the Rust users forum summarizes this nicely:

> Explicitness is the fourth core value of Rust. Ironically, I don’t see that “Explicitness” is ever explicitly stated as a goal of Rust. But, given the choice between implicitness and explicitness, Rust usually chooses explicitness.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 3:24pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/24 "2018-04-25T15:24:14Z")

</div>

Fair, rust does generally choose to explicitness. Would a different syntax for the fields be good enough to hint that these are setters and getters? What about the following:

```rust
let a: MyStruct = MyStruct::new();

a.b = 1; // Pure assignment
a{c} = 3; // using setter

return a{c}; //using getter

```

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [April 25, 2018, 3:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/25 "2018-04-25T15:41:07Z")

</div>

Those traits exist for efficiency reasons. If you couldn’t overload the something-assign operators, it would mean, for example, that a matrix addition would have to allocate a huge temporary matrix, just to then have it copied into the LHS. These traits are **not** provided so that arbitrary trickery can be done in overloaded operators (this is/should be true for **all** overloaded operators in general, not only compound assignments).

In other words, using `+=` to add two values **then in addition** do some of the trickery that you describe is frowned upon (and for the good reasons I’ve already explained). Basically, the ability to overload these particular operators is a necessary bad for performance-critical code, however it can and should be used in an unsurprising way if treated cautiously.

Basically, the expectation/implicit contract of these traits is that they will do the semantic equivalent of whatever the corresponding non-assignment operator does, followed by a simple assignment, and nothing else.

The plain `=` operator, however, can’t possibly be used in this manner. It has one and only one purpose: moving/copying the RHS into the LHS. This can’t be done any more efficiently than the compiler already generates, hence it’s useless to overload for performance reasons. And it’s actively harmful to overload for any other reason, because any other, non-trivial implementation thereof would be surprising, as I explained earlier. So, basically, what I’m saying is the **only** expected/non-abusive overload of it would perform exactly the same action as it already does today.

I can image some different syntax which calls getters and setters, because then the distinction would be very clear, which is good. However, at that point I don’t really see value in it either, because in that case you could just use a setter function and a plain old function call, and we are back at square 1.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 3:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/26 "2018-04-25T15:59:54Z")

</div>

I agree that using `+=` to have some additional side affects on a type should be massively frowned upon. However, I disagree that `=` only purpose ever is for moving or copying the RHS to the LHS. We already use it for comparisons.

What about the `a{c}` syntax I wrote about above? There is a benefit for this syntax is the same for why people want pipelining. I am going to use the C# example again because I think that it does the syntax the best. The getters and setters are used to enforce contracts with the outside user. This is also how the rust books recommend to do it, not with getters and setters that are called but with a public field. That is why I think that this is also good. (I would argue that still using `a.c` is the best option because it is the most obvious way)

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [April 25, 2018, 4:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/27 "2018-04-25T16:11:17Z")

</div>

> I disagree that `=` only purpose ever is for moving or copying the RHS to the LHS. We already use it for comparisons.

No, that is not the case. Equality comparisons in Rust are done using `==`. The `=` operator is only used for assignment.

> What about the `a{c}` syntax I wrote about above?

I think I addressed that in the last paragraph of my last reply. `foo{c} = thing` is not a step forward compared to `foo.set_c(thing)`. It doesn't have the same advantage as pipelining because, well, the setter- (plain old function-) based syntax isn't as awkward in the first place as it would be in the case of pipelined expressions. So, when field accesses are composed,

```
foo{bar}{baz} = new_value;

```

isn't much of an improvement over

```
foo.bar.set_baz(new_value);

```

By the way, while we are at nested property access: are you aware that [it's considered an anti-pattern in exactly the object-oriented languages you are referring to](https://en.wikipedia.org/wiki/Law_of_Demeter)? The quoted "Law of Demeter" is a principle that basically states that if you have deeply nested property access in your code, you are violating encapsulation, and you should refactor (instead of, as in this case, making it more convenient to violate encapsulation). Incidentally, this is probably the case why I never felt the need for this — I always try to factor my code so that reading or writing deeply embedded fields simply isn't necessary.

> The getters and setters are used to enforce contracts with the outside user.

In Rust, it's actually the type system that should be the primary means of enforcing contracts and expectations or providing guarantees.

> This is also how the rust books recommend to do it, not with getters and setters that are called but with a public field.

I'm afraid I'm not exactly following that. Could you please provide an example?

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 25, 2018, 4:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/28 "2018-04-25T16:26:17Z")

</div>

How exactly do you intend to handle restrictions on “implicit setters”?

If the only purpose of a get/set pair is to map between two representations with the same cardinality, then things are fine. But in returning `&T` from get, you’ve actually precluded this usage, as to tie the lifetime to something you have to either borrow a static or borrow a member of the structure.

But what if you’re using it to hold some invariant on the field, as you’ve suggested is the purpose? In C# you’d use exceptions, but Rust doesn’t have exceptions, it has `Result`. And I’m pretty sure that nobody wants to have assignment return a `Result`. You could panic, but that’s not how you control code flow, and then you also need the `try_assign` setter function anyway that returns a `Result`.

Using a function is strictly more powerful than any trait based overloading could be.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 5:05pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/29 "2018-04-25T17:05:49Z")

</div>

Sorry, I don’t know why I though `=` was also comparison.

However,

```rust
foo{bar}{baz} = new_value;

```

is not the same as

```rust
foo.bar.set_baz(new_value);

```

but actually

```rust
foo.set_bar(foo.get_bar().set_baz(new_value));

```

#### Furthermore:
Yes, the type system should be primary means and it does a very good job of that. But there are some things that are enforceable directly with the type system such as maximums or covariance between settings.

We read [here](https://doc.rust-lang.org/rust-by-example/mod/struct_visibility.html) that visibility and encapsulation are desirable and on by default (the private by default part). And read only fields would definetly fall under better visability

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 5:12pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/30 "2018-04-25T17:12:20Z")

</div>

So the pair isn’t a map between two representations with the same cardinality but more of letter box that might restrict what kind of letters are left in (and obviously not by throwing an error).

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [April 25, 2018, 5:38pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/31 "2018-04-25T17:38:26Z")

</div>

Fair enough, you are right – then it would indeed be syntactic improvement. However, I still hold my position that it’s generally not a good idea to do this (nested property access) at all, or to write code that will result in other programmers needing it, hence it shouldn’t be the target of a language change that makes it easier.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 25, 2018, 6:05pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/32 "2018-04-25T18:05:18Z")

</div>

> [@Nokel81](#):
>
> The point of this is exactly that contract so that the you can enforce what sort of values are stored and what to do when they are stored. Just in a much nicer looking structure

Except that if it's enforcing something interesting (that's not trivially checkable beforehand), the setter should probably be returning something like `Result<(), SomeError>` to let you know what happened. Which makes it another surprising difference from normal assignment. (And I never want `(a.x = foo())?;` to be a thing.)

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 6:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/33 "2018-04-25T18:32:56Z")

</div>

So I guess that you are right that returning a Result would make sense. However, even if it was trivially possible, code reusability should dictate that you would want it in a setter anyway

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 25, 2018, 6:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/34 "2018-04-25T18:37:26Z")

</div>

So I guess that the opinion of deep accesses is just that, an opinion. I would generally not fall into that camp because of the undesirable obfuscating and narrowness of the interfaces when designing a system. But I guess I can see where not having deep accesses would lead to better code.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [April 25, 2018, 6:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/35 "2018-04-25T18:41:58Z")

</div>

It’s not just my opinion, it’s a well-established observation of systems in general. And it’s not about the narrowness of interfaces, it’s about not exposing implementation details. These two are orthogonal issues. And while _unnecessary_ narrowness of interfaces can be an anti-pattern (although generally, several small interfaces are better than one giant one), but relying on being able to pull out and push back the guts of a nested object is generally a code smell. I’m not saying it’s never useful; I’m saying it’s usually dangerous.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 25, 2018, 6:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/36 "2018-04-25T18:59:18Z")

</div>

The way I see it, there are three main “classes” of structures.

Dumb data: your `i32`s, or `struct`s consisting entirety of publicly addressable members. Basically a tuple of related data maybe with names attached to the members.

Smartish data: `struct`s that are otherwise just dumb data, but maintain some invariant over it. Your `NonZero` or `R32` or `Quaternion`s of the world.

Abstractions: structures that present a wildly different interface than their internal structure. Or put another way, their logical structure is separate from their physical representation. Most library types are going to be this.

Of course, this is a continuous scale, not discrete, and dumb data can actually be wrappers around abstractions, so the lines get even more blurred.

But I think this shows where `=` overloading might be most useful: in the minor case of thin smart data. It might be useful to have `let r: R32 = 0` rather than `let r: R32 = 0.into()` or `let r = r32(0)`. But that’s actually distinct from properties, so /shrug.

Nested properties are pretty much an antipattern in languages with them anyway. And I think I’ve been convinced that most cases can be better represented with a semantic setter than representational properties.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [April 25, 2018, 7:16pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/37 "2018-04-25T19:16:24Z")

</div>

I would actually prefer `.into()` over the other choices. I don't want implicit value-to-value conversions to happen without my knowledge. (`Deref` coercions is an entirely different thing because it has one well-defined semantics with smart pointers and synchronization primitives as one-element containers.)

The `into()` call is non-invasive and common enough that it can be skipped over instinctively if its presence is not important (most of the cases), but it can still be easily spotted or searched for when it is still important. I've been wondering about explicit vs implicit conversions in language design for a long time before I encountered Rust, and then I came to the conclusion that `into()` is basically the sweet spot, a very well-balanced compromise between self-documenting code and minimization of noise.

> [@CAD97](#):
>
> But I think this shows where `=` overloading might be most useful: in the minor case of thin smart data. It might be useful to have `let r: R32 = 0` rather than `let r: R32 = 0.into()`

That is also true – it may well be **useful.** But "it's sometimes useful in a niche situation" is not enough justification for a feature to be added to the language. A language change is a huge responsibility. It really is a big deal, because growing the language leads to bugs in its implementation and its usage. Consequently, a feature has to carry very significant and extensive advantage in order to be worth the burden of making the language bigger.

---

<div class="post-metadata">

**Author:** ![vorner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/vorner/32/3310_2.png) [@vorner](https://internals.rust-lang.org/u/vorner)\
**Post date:** [April 26, 2018, 12:46pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/38 "2018-04-26T12:46:59Z")

</div>

I’d have a question.

Considering that Rust structs are _not_ objects in the OOP paradigm, they are just storage for fields and, by the way, you can glue some functions to them and call them methods, how would this proposal work with _other_ custom data types that can have functions glued onto them? Like enums? Because in most places you don’t have to care if the data type is struct or something else.

If glueing methods onto data is done by placing them inside an `impl` block and an `impl` block for a trait acts basically the same way, would it be possible to add setters/getters into a trait?

What I try to hint here is, just throwing something into the language without considering the whole consistency of the design leads to complicated mess. I don’t see much added value in getters/setters (and I probably don’t use any language that uses them), but if they _were_ to be added, I think the proposal would have to consider much more than „lets put them on structs somehow“.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 26, 2018, 1:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/39 "2018-04-26T13:33:23Z")

</div>

I agree that we have to be careful about such an addition and should consider all possibilities.

As for a language that uses this sort of feature, I have mentioned [C#](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties) before because that was a major inspiration for this.

I also agree that Rust structs are not objects in the OOP paradigm. However, there is a difference between structs and enums that would not make sense for enums to have this feature. Structs can have more than one field where as enums cannot. Enums are basically a structs with a single field that has a setter which the compiler guarantees some contract (that the assigned value is within the enum). Yes, I acknowledge that generally it does not matter what is within an `impl` block but there are cases (most notably what other traits have been implemented) where it does matter

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [April 26, 2018, 2:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383/40 "2018-04-26T14:08:38Z")

</div>

I think we really need to insist on concrete use cases in this thread (and many other proposal threads, tbh). We all know the general abstract arguments for/against this sort of thing, and it was always obvious that the general arguments alone probably don’t justify adding this, so the discussion is only going to go anywhere if someone presents a compelling example of actual code that would be dramatically (not just significantly) improved by a proposal like this.

So, does anyone know of any compelling, concrete examples of Rust code that would be _dramatically_ improved by setters?

[Previous page](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383.md?page=1)

[Next page](https://internals.rust-lang.org/t/pre-rfc-new-trait-set-impl-on-struct-fields/7383.md?page=3)
