www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - tupleof seems to break encapsulation

reply 60rntogo <60rntogo gmail.com> writes:
Consider the following code.

foo.d
---
module foo;

struct Foo
{
   private int i;
}
---

main.d
---
void main()
{
   import std.stdio;
   import foo;

   auto x = Foo();
   writeln(x);
   // ++x.i;
   ++x.tupleof[0];
   writeln(x);
}
---

As expected, the commented line does not compile. If I uncomment 
it, I get the error "no property i for type foo.Foo". However, 
the rest of the code compiles just fine and outputs:
---
Foo(0)
Foo(1)
---

This appears to defeat the purpose of declaring i private. What 
am I missing?
Sep 04 2020
next sibling parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Friday, 4 September 2020 at 10:16:47 UTC, 60rntogo wrote:
 Consider the following code.

 foo.d
 ---
 module foo;

 struct Foo
 {
   private int i;
 }
 ---

 main.d
 ---
 void main()
 {
   import std.stdio;
   import foo;

   auto x = Foo();
   writeln(x);
   // ++x.i;
   ++x.tupleof[0];
   writeln(x);
 }
 ---

 As expected, the commented line does not compile. If I 
 uncomment it, I get the error "no property i for type foo.Foo". 
 However, the rest of the code compiles just fine and outputs:
 ---
 Foo(0)
 Foo(1)
 ---

 This appears to defeat the purpose of declaring i private. What 
 am I missing?
It's a known issue: https://issues.dlang.org/show_bug.cgi?id=19326 There are some very good reasons to allow some access to private fields, though it should be more limited than is currently the case. -- Simen
Sep 04 2020
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2020-09-04 12:16, 60rntogo wrote:
 Consider the following code.
 
 foo.d
 ---
 module foo;
 
 struct Foo
 {
    private int i;
 }
 ---
 
 main.d
 ---
 void main()
 {
    import std.stdio;
    import foo;
 
    auto x = Foo();
    writeln(x);
    // ++x.i;
    ++x.tupleof[0];
    writeln(x);
 }
 ---
 
 As expected, the commented line does not compile. If I uncomment it, I 
 get the error "no property i for type foo.Foo". However, the rest of the 
 code compiles just fine and outputs:
 ---
 Foo(0)
 Foo(1)
 ---
 
 This appears to defeat the purpose of declaring i private. What am I 
 missing?
It's useful for serialization and, as you can see in your example, for debugging as well. `writeln` will print the values of the fields in a struct, even for private fields. -- /Jacob Carlborg
Sep 04 2020
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Sep 04, 2020 at 07:36:00PM +0200, Jacob Carlborg via
Digitalmars-d-learn wrote:
[...]
 It's useful for serialization and, as you can see in your example, for
 debugging as well. `writeln` will print the values of the fields in a
 struct, even for private fields.
It's certainly useful, but violates private. I'd propose restricting it to -debug or at the very least system, so that normal safe code will behave as expected. T -- It's amazing how careful choice of punctuation can leave you hanging:
Sep 04 2020
parent Paul Backus <snarwin gmail.com> writes:
On Friday, 4 September 2020 at 18:23:09 UTC, H. S. Teoh wrote:
 On Fri, Sep 04, 2020 at 07:36:00PM +0200, Jacob Carlborg via 
 Digitalmars-d-learn wrote: [...]
 It's useful for serialization and, as you can see in your 
 example, for debugging as well. `writeln` will print the 
 values of the fields in a struct, even for private fields.
It's certainly useful, but violates private. I'd propose restricting it to -debug or at the very least system, so that normal safe code will behave as expected. T
Previously: https://issues.dlang.org/show_bug.cgi?id=19326 https://issues.dlang.org/show_bug.cgi?id=20941
Sep 04 2020
prev sibling parent reply 60rntogo <60rntogo gmail.com> writes:
On Friday, 4 September 2020 at 17:36:00 UTC, Jacob Carlborg wrote:
 It's useful for serialization and, as you can see in your 
 example, for debugging as well. `writeln` will print the values 
 of the fields in a struct, even for private fields.
I wouldn't dispute that it is useful, but that's besides the point. If I declare something private, it's usually because I want to preserve certain invariants and I want the compiler to provide a guarantee that I don't accidentally violate them. As it stands, the compiler cannot guarantee that if I use tupleof. I don't really have an issue with read-only access to private fields (but arguments could be made against it) and then serialization would still be possible. However, if my struct is supposed to maintain invariants, then any attempt at deserialization that naively reads from a tuple without establishing these invariants should fail to compile.
Sep 04 2020
parent Jacob Carlborg <doob me.com> writes:
On 2020-09-05 07:14, 60rntogo wrote:

 I wouldn't dispute that it is useful, but that's besides the point. If I 
 declare something private, it's usually because I want to preserve 
 certain invariants and I want the compiler to provide a guarantee that I 
 don't accidentally violate them. As it stands, the compiler cannot 
 guarantee that if I use tupleof.
 
 I don't really have an issue with read-only access to private fields 
 (but arguments could be made against it) and then serialization would 
 still be possible. However, if my struct is supposed to maintain 
 invariants, then any attempt at deserialization that naively reads from 
 a tuple without establishing these invariants should fail to compile.
I wouldn't mind if `tupleof` was not allowed in safe code, which Walter mentions in one of the linked issues. Although it would be a breaking change. Secondly, my serialization library, Orange [1], uses `tupleof` to read and write fields. It also supports before and after hooks for both serialization and deserialization. This allows to implement any invariants that are not covered by just restoring the fields. It also supports implementing a method that allows to take full control of the (de)serialization of a specific type. Thirdly, you can do the same thing with pointer arithmetic. Although this is not allowed if safe code. [1] https://github.com/jacob-carlborg/orange -- /Jacob Carlborg
Sep 06 2020