How to prevent direct public creation of a struct?

Nick Sabalausky SeeWebsiteToContactMe at semitwist.com
Thu May 3 17:27:58 PDT 2012


"Brad Anderson" <eco at gnuk.net> wrote in message 
news:jhsccvjskiqqzzqbdugx at forum.dlang.org...
> On Thursday, 3 May 2012 at 21:36:53 UTC, Nick Sabalausky wrote:
>> I want to do something like this:
>>
>> ------------------------------------------
>> module moduleFoo;
>>
>> // Only allow certain values of "str"
>> template foo(string str)
>> {
>>     static assert(str == "a" || str == "b" || str == "c");
>>     immutable foo = Foo(str);
>> }
>>
>> struct Foo
>> {
>>     // Only "a", "b", and "c" should be allowed,
>>     // checked at compile-time via "template foo".
>>     // Also, not modifyable.
>>     private string _str;
>>     @property string str()
>>     {
>>         return _str;
>>     }
>> }
>> ------------------------------------------
>>
>> I want struct Foo itself to be public, but I want to *force* all code
>> outside moduleFoo to *create* Foo via the "foo" template. Copying should 
>> be
>> allowed though. Ie:
>>
>> ------------------------------------------
>> auto a = foo!"a"; // ok
>> a.str = "b"; // Error: str is a read-only property
>> auto z = foo!"z"; // Error: fails static assert
>> auto a2 = a; // Copy it: ok
>>
>> auto b = Foo("b"); // Error: I want to *force* the usage of "template 
>> foo"
>>
>> Foo x; // Kinda ambivalent about this: I'd prefer if it were disallowed, 
>> but
>> I don't think that's possible. If it's indeed impossible, I know I can 
>> just
>> declare Foo.str as (string str = "a";) so that's not a big problem.
>> ------------------------------------------
>>
>> The *key* thing here that I'm not sure how to do is: How do I disallow
>> this?:
>>
>> auto b = Foo("b"); // Error: I want to *force* the usage of "template 
>> foo"
>
> I would have thought adding a private this(string str) constructor would 
> work but then foo can't be called from a separate module ("privcons.d(5): 
> Error: struct privcons.Foo member this is not accessible" which is the 
> same but desirable error it gives if you do "auto b = Foo("b");").  I 
> thought all module members had access to private members of the same 
> module but I guess that's not the case with template functions.

Hmm, interestingly, it works if the template calls through an intermediary 
private function:

http://d.puremagic.com/issues/show_bug.cgi?id=8028

I don't know if I'm relying on a bug or working around a bug, but this seems 
to work, *and* disallows "Foo b;" which is nice:

---------------------------------------------------
template foo(string str)
{
    static assert(["a", "b", "c"].find(str), "Invalid str: '"~str~"'");
    immutable foo = _foo(name);
}

private Foo _foo(string str)
{
    return Foo(str);
}

struct Foo
{
    immutable string str;

    private this(string str)
    {
        this.str = str;
    }

    @disable this();
}

---------------------------------------------------
// In a serparate module:

Foo a = foo!"a";  // Ok
auto a2 = a;  // Ok

a.str = "b";  // Error: can only initialize const member name inside 
constructor

auto z = foo!"z";  // Error: static assert  "Invalid str: 'z'"  instantiated 
from here: foo!("z")

auto b = Foo("b");  // Error: struct test2.Foo member this is not accessible

Foo x;  // Error: variable test1.main.x initializer required for type Foo
---------------------------------------------------

So that's awesome, everything as I wanted :)




More information about the Digitalmars-d-learn mailing list