www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can I make a variable public and readonly (outside where was declared)

reply "AsmMan" <jckj33 gmail.com> writes:
I know I can combine it by making an extra variable plus a 
property like this:

class Foo
{
   private int a_;

   void do_something1()
   {
     a_ = baa();
   }

   void do_something2()
   {
     if(cond) a_ = baa2();
   }

    property int a()
   {
       return a;
    }
}


limited knowledge. I don't do much OOP, maybe it's possible and I 
don't know. I'm using  property to make 'a' accessible and 
readonly at same time but I wanted to do that without this a_ 
extra variable, i.e, only the methods within the Foo class can 
assign a new value to a but a instance of Foo can't. An imaginary 
code example:

class Foo
{
   public MAGIC_HERE int a;

   void do_something1()
   {
     a = baa();
   }

   void do_something2()
   {
     if(cond) a = baa2();
   }
}


And then:

Foo f = new Foo();
writeln(f.a); // output value of a
f.a = 10; // compile error: a is readonly outside Foo's methods.

I hope it's clear (sorry for por English)
Sep 26 2014
next sibling parent "Gary Willoughby" <dev nomad.so> writes:
On Friday, 26 September 2014 at 17:16:04 UTC, AsmMan wrote:
 I know I can combine it by making an extra variable plus a 
 property like this:

 class Foo
 {
   private int a_;

   void do_something1()
   {
     a_ = baa();
   }

   void do_something2()
   {
     if(cond) a_ = baa2();
   }

    property int a()
   {
       return a;
    }
 }


 limited knowledge. I don't do much OOP, maybe it's possible and 
 I don't know. I'm using  property to make 'a' accessible and 
 readonly at same time but I wanted to do that without this a_ 
 extra variable, i.e, only the methods within the Foo class can 
 assign a new value to a but a instance of Foo can't. An 
 imaginary code example:

 class Foo
 {
   public MAGIC_HERE int a;

   void do_something1()
   {
     a = baa();
   }

   void do_something2()
   {
     if(cond) a = baa2();
   }
 }


 And then:

 Foo f = new Foo();
 writeln(f.a); // output value of a
 f.a = 10; // compile error: a is readonly outside Foo's methods.

 I hope it's clear (sorry for por English)
I think the extra variable and the properties are the way to go and it's the idiomatic way. In fact that's the reason properties are there. Saying that though, you can achieve what you want implementing a little more code using opDispatch. opDispatch intercepts calls to undefined members and deals with them, in this case forwarding to a private variable. http://dlang.org/operatoroverloading.html#dispatch
Sep 26 2014
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 09/26/2014 10:16 AM, AsmMan wrote:

 I know I can combine it by making an extra variable plus a property like
 this:
That's the proper way of doing it in D. If it's too much work, it is possible to take advantage of mixins to reduce the boilerplate. I found the following code among my D samples; it must have been found on these forums. Defining without "set" would disallow the setter: alias AutoImplementedProperty!(string, "get") title; The code: import std.stdio; class Bar { alias AutoImplementedProperty!(string, "get", "set") title; } template AutoImplementedProperty(T, args...) { import std.typetuple; property { private T _name; static if (args.length) { static if (staticIndexOf!("get", args) > -1) { public T AutoImplementedProperty() { return _name; } } static if (staticIndexOf!("set", args) > -1) { public void AutoImplementedProperty(T value) { _name = value; } } } } } void main(string[] args) { Bar a = new Bar(); a.title = "asf"; writeln(a.title); return; }
 I wanted to do that without this a_ extra variable
If the value is set only once and it is known during construction, it is indeed mark the variable public const: import std.stdio; class Foo { public const int a; this (int x) { a = 2 * x; } } void main() { Foo f = new Foo(21); writeln(f.a); // output value of a Foo f2 = f; // copy works f2 = f; // assignment works // f.a = 10; // compile error: a is readonly outside Foo's methods. } Ali
Sep 26 2014
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 26 September 2014 at 17:16:04 UTC, AsmMan wrote:
 I know I can combine it by making an extra variable plus a 
 property like this:

 class Foo
 {
   private int a_;

   void do_something1()
   {
     a_ = baa();
   }

   void do_something2()
   {
     if(cond) a_ = baa2();
   }

    property int a()
   {
       return a;
    }
 }


 limited knowledge. I don't do much OOP, maybe it's possible and 
 I don't know. I'm using  property to make 'a' accessible and 
 readonly at same time but I wanted to do that without this a_ 
 extra variable, i.e, only the methods within the Foo class can 
 assign a new value to a but a instance of Foo can't. An 
 imaginary code example:

 class Foo
 {
   public MAGIC_HERE int a;

   void do_something1()
   {
     a = baa();
   }

   void do_something2()
   {
     if(cond) a = baa2();
   }
 }


 And then:

 Foo f = new Foo();
 writeln(f.a); // output value of a
 f.a = 10; // compile error: a is readonly outside Foo's methods.

 I hope it's clear (sorry for por English)
The closest you can get is probably this: class Foo { private int a_; property int a() { return a_; } private property void a(int value) { a_ = value; } } You can then assign to `a` inside the class `Foo` _and_ inside its module (because `private` is always accessible from within the same module), while from other modules, it can only be read. But it's not exactly a read-only variable, because you cannot take an address from it, for example. Alternatively, you could create a union with a private and a public member with the same types, but I wouldn't recommend it. Besides, the members would need to have different names: class Foo { union { private int a; public int b; } }
Sep 26 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Marc Schütz:

 Alternatively, you could create a union with a private and a 
 public member with the same types, but I wouldn't recommend it. 
 Besides, the members would need to have different names:

     class Foo {
         union {
             private int a;
             public int b;
         }
     }
You can call them a and a_. Why are you not recommending this solution? It looks cool (if it works). Bye, bearophile
Sep 26 2014
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 26 September 2014 at 17:52:58 UTC, bearophile wrote:
 Marc Schütz:

 Alternatively, you could create a union with a private and a 
 public member with the same types, but I wouldn't recommend 
 it. Besides, the members would need to have different names:

    class Foo {
        union {
            private int a;
            public int b;
        }
    }
You can call them a and a_. Why are you not recommending this solution? It looks cool (if it works).
Don't know, it feels hacky. And I really don't like the two different names, what's the point if I have to distinguish the two manually? Now yet another way came to my mind: struct PrivatelyWritableProperty(T) { private T value_; const(T) get() const { return value_; } private void opAssign(T value) { value_ = value; } alias get this; } class Foo { PrivatelyWritableProperty!int a; } But this looks even more fragile; there are probably some corner-cases where it doesn't work (for example, what happens when someone copies the containing struct?).
Sep 26 2014
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/26/14 1:36 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" 
wrote:

 Alternatively, you could create a union with a private and a public
 member with the same types, but I wouldn't recommend it. Besides, the
 members would need to have different names:

      class Foo {
          union {
              private int a;
              public int b;
          }
      }
Hm.. that doesn't provide readonly access to either a or b. But it gave me an idea: class Foo { union { private int _a; public const int a; } void setA(int x) { _a = x; } } Hot damn! It works too :) Can't access _a from outside the module, can access a, but can't write it (even from within Foo). It's like an auto-inlined property function. I don't know how it would affect the optimizer, or the GC scanner. Unions are ugly things... -Steve
Sep 26 2014
next sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 26 September 2014 at 18:18:45 UTC, Steven 
Schveighoffer wrote:
 On 9/26/14 1:36 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= 
 <schuetzm gmx.net>" wrote:

 Alternatively, you could create a union with a private and a 
 public
 member with the same types, but I wouldn't recommend it. 
 Besides, the
 members would need to have different names:

     class Foo {
         union {
             private int a;
             public int b;
         }
     }
Hm.. that doesn't provide readonly access to either a or b. But it gave me an idea: class Foo { union { private int _a; public const int a; } void setA(int x) { _a = x; } }
Yes, that's what I originally intended. Just forgot the const, and didn't even notice it after I reread it :-P
Sep 27 2014
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/27/14 5:48 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>"
 Yes, that's what I originally intended. Just forgot the const, and
 didn't even notice it after I reread it :-P
I wondered... ;) -Steve
Sep 27 2014
prev sibling parent "AsmMan" <jckj33 gmail.com> writes:
On Friday, 26 September 2014 at 18:18:45 UTC, Steven 
Schveighoffer wrote:
 On 9/26/14 1:36 PM, "Marc =?UTF-8?B?U2Now7x0eiI=?= 
 <schuetzm gmx.net>" wrote:

 Alternatively, you could create a union with a private and a 
 public
 member with the same types, but I wouldn't recommend it. 
 Besides, the
 members would need to have different names:

     class Foo {
         union {
             private int a;
             public int b;
         }
     }
Hm.. that doesn't provide readonly access to either a or b. But it gave me an idea: class Foo { union { private int _a; public const int a; } void setA(int x) { _a = x; } } Hot damn! It works too :) Can't access _a from outside the module, can access a, but can't write it (even from within Foo). It's like an auto-inlined property function. I don't know how it would affect the optimizer, or the GC scanner. Unions are ugly things... -Steve
This is really a loot cool and works. Thanks. If private in D had was declared and not public to the entire module, I guess we could even do: class Foo { union { private int a_; public property int a() { return a_; } private property void a(int value) { a_ = value; } } //no one need knows the 'a_' (ugly?) identifier void setValue(int x) { a = x; } } And then Foo f = new Foo(); f.a = 10; // give a compile error becaus it is private and acessible within Foo class only BTW: I'm not sure about memory usage where using properties. But it is still cool.
Sep 27 2014