Blogpost about the T.init problem

Jim Balter Jim at Balter.name
Sun Jul 29 08:35:52 UTC 2018


On Wednesday, 11 July 2018 at 07:30:59 UTC, FeepingCreature wrote:
> On Tuesday, 10 July 2018 at 21:08:32 UTC, Cym13 wrote:
>> First of all I must point that I would very much like to have 
>> seen a code actually producing an error in that article. 
>> Contrary to what is hinted just taking the struct and putting 
>> using it with Nullable or format() caused no error for me and 
>> worked as expected.
>
> To reproduce the format issue, try to print the struct with 
> writefln!"%s"(MyDomainType()).
>
> To reproduce the Nullable issue, you need to slightly modify 
> the struct. In Phobos, Nullable will (due to an abundance of 
> caution) refuse to initialize the struct if the default 
> constructor is disabled; also you need a destructor. However, 
> for this it is enough to use any type that has a destructor, so 
> that an implicit struct destructor is generated. For verbosity, 
> I'll write it out:
>
>
> struct MyDomainData {
>     string username;
>
>     this(string username) @safe
>     in(!username.empty) // only non-empty usernames please!
>     do { this.username = username; }
>
>     // let's formalise the restriction.
>     invariant { assert(!username.empty); }
>
>     string toString() { return null; }
>
>     ~this() @safe { }
> }
>
> Then just stick it in a Nullable. No explicit .init needed.
>
>> That said, I may be missing something obvious but what 
>> prevents you from overloading the init field?
>>
>>     struct MyDomainData {
>>         string username;
>>         @disable this(); // don't make a MyDomainData() by 
>> accident!
>>         this(string username)
>>         in(!username.empty) // only non-empty usernames please!
>>         do { this.username = username; }
>>         // let's formalise the restriction.
>>         invariant { assert(!username.empty); }
>>         string toString() { ... }
>>
>>         static @property MyDomainData init() {
>>             return MyDomainData("uninitialized");
>>         }
>>
>>         ...
>>     }
>>
>>     auto test = MyDomainData.init;  // There, no error
>>
>> Of course that value means nothing but .init isn't meant to 
>> actually mean something anyway, it's just a valid value and 
>> that's what that init is proposing, so it shouldn't cause any 
>> more bugs than empty .init in a normal case.
>
> That would work, it's just a really horrible hack and I hate 
> it. We're constructing a fictitious domain value that passes 
> our invariants while having zero correspondence to the real 
> world, *just to pass our invariants*. It's an obvious sign of a 
> language issue.

If so, then the only language solution is to remove either 
invariants or .init, because as long as .init can be called but 
cannot be made to conform to your invariant, then your design is 
beyond the scope of the language and you're in a pickle.

But the fact is that it's not a language issue and there are 
several ways in user code to guarantee that .init satisfies the 
invariant. In fact that very statement suggests a solution that 
Timothy Cour suggested earlier:

      invariant {
       if(this is typeof(this).init) return;
       assert(!username.empty);
     }




More information about the Digitalmars-d-announce mailing list