Thread overview
How to prevent direct public creation of a struct?
May 03, 2012
Nick Sabalausky
May 03, 2012
Brad Anderson
May 04, 2012
Nick Sabalausky
May 03, 2012
Justin Whear
May 03, 2012
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"



May 03, 2012
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.
May 03, 2012
On Thu, 03 May 2012 17:37:47 -0400, Nick Sabalausky wrote:
> 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"

The @disable annotation can do this, I believe:
struct Foo
{
	@disable this();   // Cannot use default constructor
}

But this disables it for code within the module as well as outside, so you may wish to also add a private constructor.
May 04, 2012
"Brad Anderson" <eco@gnuk.net> wrote in message news:jhsccvjskiqqzzqbdugx@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 :)