www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Q: How can I make a class act like a value type (such as struct)

reply Myron Alexander <someone somewhere.com> writes:
Hello.

I currently have a struct for named parameters called NamedParameter and 
this is defined as such:

struct NamedParameter {
    char[] name;
    Box    value;

    char[] toString () {
       return "(" ~ name ~ ": " ~ value.toString () ~ ")";
    }

    static NamedParameter opCall(T) (char[] name, T value) {

       // I have used a static if instead of static assert as the assert 
cannot
       // resolve and output the name and value.name. I would prefer a 
compile
       // time error.
       static if (is (T == NamedParameter)) {
          throw new SqlProgrammingException (
             "Invalid named parameter value. The value of a named 
parameter may "
             "not be a named parameter. Error on parameter (" ~ name ~
             ") trying to nest parameter (" ~ value.name ~
             ").");
       }

       NamedParameter m_np;

       m_np.name  = name;

       static if (is (T == Box)) {
          m_np.value = value;

       } else {
          m_np.value = box (value);
       }

       return m_np;
    }
}


The problem with this struct is that the name, and value fields are 
public and I want them private so the user is forced through the opCall. 
My reason for this is that I want all the validations done on 
initialization instead of having to be done whenever I use the values. 
(These validations are not in the above code).

The only way to make the fields private is to have a class so I would 
like to build my class to work as a value object in the same way that 
structs do but with information hiding.

How can I do this?

Thanks ahead,

Myron.
May 27 2007
next sibling parent reply Regan Heath <regan netmail.co.nz> writes:
Myron Alexander Wrote:
 The only way to make the fields private is to have a class so I would 
 like to build my class to work as a value object in the same way that 
 structs do but with information hiding.
What 'value object' behaviour do you want? As in, how are you using these types? Example please :) Something like this... NamedParameter p("test",5); NamedParameter q; q = p; In the above, is it that you want q to be a copy of p as opposed to both p and q referring to the same object? If so, D does not allow you to overload assignment and instead you would need to use a copy method or perhaps supply a constructor that copies, eg. class NamedParameter { NamedParameter(NamedParameter rhs) { ..copy rhs to self here.. } NamedParameter dup() { ..create new copy of self and return it.. } } If you want some other value object behaviour please explain. Regan Heath
May 27 2007
next sibling parent reply Myron Alexander <someone somewhere.com> writes:
Regan Heath wrote:
 What 'value object' behaviour do you want?  As in, how are you using these
types?  Example please :)  Something like this...
 
 NamedParameter p("test",5);
 NamedParameter q;
 
 q = p;
 
 In the above, is it that you want q to be a copy of p as opposed to both p and
q referring to the same object?
 
Regan, The above is one aspect of what I meant as a value object but my manner of use does not need it. I am more concerned with storage and I want my class to be allocated on the stack rather than on the heap so that the GC does not have to bother with it. If such a thing can't be done, then I am happy with GC'd references. This is a simple example of how it is used (np is an alias for NamedParameter): cu.execute ( "insert into atable values (:id, :name, :balance)", np("id",4), np("name","Fourth Person"), np("balance",999.99)); I've done a conversion and this is my latest version: class NamedParameter { private this (char[] name, Box value) { m_name = name; m_value = value; } static NamedParameter opCall(T) (char[] name, T value) { // I have used a static if instead of static assert as the assert cannot // resolve name and value.name. I would prefer a compile time error. static if (is (T == NamedParameter)) { throw new SqlProgrammingException ( "Invalid named parameter value. The value of a named parameter may " "not be a named parameter. Error on parameter (" ~ name ~ ") trying to nest parameter (" ~ value.name ~ ")."); } Box v; static if (is (T == Box)) { /* Unnest the innermost value. */ v = value; while (v.type == typeid (Box)) { v = unbox!(Box)(v); } } else { v = box (value); } return new NamedParameter (name, v); } char[] name () { return m_name; } Box value () { return m_value; } char[] toString () { return "(" ~ m_name ~ ": " ~ m_value.toString () ~ ")"; } private char[] m_name; private Box m_value; } Regards, Myron.
May 27 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Myron Alexander wrote:
 Regan Heath wrote:
 The above is one aspect of what I meant as a value object but my manner 
 of use does not need it. I am more concerned with storage and I want my 
 class to be allocated on the stack rather than on the heap so that the 
 GC does not have to bother with it.
You seem to have solved your problem using structs w/ private, but just FYI you can make classes be allocated on the stack using the 'scope' keyword. void something() { auto foo = new SomeClass(); // foo on the heap scope bar = new SomeClass(); // bar on the stack . . . } And I think if you put scope in the class declaration it makes you use 'scope' every time you use the class (? I think...): scope class SomeClass() { . . . } I tried that once long ago, but never have been able to think of a case where that would be better than just using a struct. I guess if you want it to implement an interface... --bb
May 27 2007
parent Myron Alexander <someone somewhere.com> writes:
Bill Baxter wrote:
 You seem to have solved your problem using structs w/ private, but just 
 FYI you can make classes be allocated on the stack using the 'scope' 
 keyword.
 
  void something()
  {
     auto foo = new SomeClass(); // foo on the heap
     scope bar = new SomeClass(); // bar on the stack
     . . .
 
  }
 
 And I think if you put scope in the class declaration it makes you use 
 'scope' every time you use the class (? I think...):
 
 scope class SomeClass()
 {
    . . .
 }
 
 I tried that once long ago, but never have been able to think of a case 
 where that would be better than just using a struct.  I guess if you 
 want it to implement an interface...
 
 --bb
For my library, I use Box to pass values around. My simple test seems to show that a scope class can be assigned to a box. The only functionality I cannot provide with scope classes is the opCall that I am using. I whipped up a simple test: import std.stdio; import std.boxer; scope class Xx { this (char[] v = "Default") { value = v; } //~ static Xx opCall (char[] v) { //~ return new Xx(v); //~ } private char[] value; char[] toString () { return value; } } void dobe (Box b) { writefln ("%s", b); } void main () { scope x = new Xx(); Box y = box (x); dobe (y); } If I uncomment the opCall, I get the following compiler error: scope_box.d(9): Error: functions cannot return auto scope_box.Xx Luckily, the struct works for my case so I am ok :) I also heard that structs are getting constructors which is double bonus. Regards, Myron.
May 27 2007
prev sibling parent Myron Alexander <someone somewhere.com> writes:
Regan,

Thanks for the help. I have solved my problem by using private with struct.

Best regards,

Myron.
May 27 2007
prev sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Myron Alexander escribió:
 
 The problem with this struct is that the name, and value fields are 
 public and I want them private so the user is forced through the opCall. 
 My reason for this is that I want all the validations done on 
 initialization instead of having to be done whenever I use the values. 
 (These validations are not in the above code).
 
 The only way to make the fields private is to have a class so I would 
 like to build my class to work as a value object in the same way that 
 structs do but with information hiding.
 
You can use "private" et al. with structs too. -- Carlos Santander Bernal
May 27 2007
parent Myron Alexander <someone somewhere.com> writes:
Carlos Santander wrote:
 You can use "private" et al. with structs too.
 
Carlos, I did not know that. The documentation says that hidden members are not a feature of structs, I took it to mean that private does not work. Having a DOH moment :) Thanks. Best regards, Myron.
May 27 2007