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