www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to prevent direct public creation of a struct?

reply "Nick Sabalausky" <SeeWebsiteToContactMe semitwist.com> writes:
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
next sibling parent reply "Brad Anderson" <eco gnuk.net> writes:
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
parent "Nick Sabalausky" <SeeWebsiteToContactMe semitwist.com> writes:
"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 :)
May 03 2012
prev sibling parent Justin Whear <justin economicmodeling.com> writes:
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 03 2012