www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Way to make properties

reply KUV <KUV_member pathlink.com> writes:
Is there the way to make properties like Delphi, so that writing and reading
this property is processed with different function and procedure.
Jun 12 2005
parent reply Vathix <vathix dprogramming.com> writes:
On Sun, 12 Jun 2005 13:51:00 -0400, KUV <KUV_member pathlink.com> wrote:

 Is there the way to make properties like Delphi, so that writing and  
 reading
 this property is processed with different function and procedure.

Check out http://www.digitalmars.com/d/property.html and skip down to "Class and Struct Properties".
Jun 12 2005
next sibling parent KUV <KUV_member pathlink.com> writes:

Jun 12 2005
prev sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Vathix wrote:
 On Sun, 12 Jun 2005 13:51:00 -0400, KUV <KUV_member pathlink.com> wrote:
 
 Is there the way to make properties like Delphi, so that writing and  
 reading
 this property is processed with different function and procedure.

Check out http://www.digitalmars.com/d/property.html and skip down to "Class and Struct Properties".

I still think we'd be better off with C# style properties (I don't know how Delphi's props work.. someone show me an example?). As I do everytime this comes up, I'll show my suggested syntax once again. Apologies to those of you who have seen this a thousand times. But I'm adamant. :) # class Foo { # public property bar : int { # public int property bar { # void get(inout int dest){ dest = _value; } # void get(inout char[] dest){ dest = std.string.toString(_value); } # # void set(inout int src){ _value = src; } # void set(inout char[] src){ _value = toInt(src); } # } # }
Jun 12 2005
next sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
A few questions:

1. What is the benefit this has over the current syntax?
2. How do you propose to deal with the problem of a single 
expression/identifier having multiple possible types (which you'll 
notice D avoids heavily)?
3. Why do you have two (different) lines declaring the property?

In essence, I see you want to change this:

class Foo
{
    int _value;

    int bar()
    {
       return this._value;
    }
    void bar(int i)
    {
       this._value = i;
    }
}

To:

class Foo
{
    int _value;

    public int property bar
    {
       void get(out int dest)
       {
          dest = this._value;
       }
       void set(in int i)
       {
          this._value = i;
       }
    }
}

Which brings the following questions:

4. Why do you want it to be longer?
5. Why do you want to use void returning functions with out/inout 
parameters instead of returning the type as logical for the REST of C/D?

-[Unknown]


 I still think we'd be better off with C# style properties (I don't know 
 how Delphi's props work.. someone show me an example?).  As I do 
 everytime this comes up, I'll show my suggested syntax once again. 
 Apologies to those of you who have seen this a thousand times.  But I'm 
 adamant.  :)
 
 # class Foo {
 #   public property bar : int {
 #   public int property bar {
 #     void get(inout int    dest){ dest = _value;                      }
 #     void get(inout char[] dest){ dest = std.string.toString(_value); }
 #
 #     void set(inout int    src){ _value = src;        }
 #     void set(inout char[] src){ _value = toInt(src); }
 #   }
 # }

Jun 12 2005
parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Unknown W. Brackets wrote:
 A few questions:
 
 1. What is the benefit this has over the current syntax?

Its more explicit, which I think Properties ought to be. The current syntax is cute, and does provide the primary requisite for clean properties, which is the ability to be seamless between fields and methods. Or in other words, to user code a property should appear no different from a field.
 2. How do you propose to deal with the problem of a single 
 expression/identifier having multiple possible types (which you'll 
 notice D avoids heavily)?

Its a good question. Maybe we could require that there be only one gettor, and that its return type match the type of the property. Or even that it define that type, so that the property itself actually has no type. The type of expressions which use it would then be that of the gettor. I'll have to think on it.
 3. Why do you have two (different) lines declaring the property?

That was a mistake... I typed that out right after getting out of bed, you see. :) I actually made up the "property bar : int" syntax on the spot and typed it out just to see how it looked, then forgot to delete one of the lines before sending...
       void get(out int dest)
       void set(in int i)

Actually that's good too, using 'out' and 'in' instead of 'inout'... That might've been how I first proposed it. Its been a while.
 4. Why do you want it to be longer?

Its only a tiny bit longer, actually.
 5. Why do you want to use void returning functions with out/inout 
 parameters instead of returning the type as logical for the REST of C/D?

Consider the problem with opCast, where one can have only a single opCast for a given class because there is no overload on return type. One method of avoiding this, which has been proposed, is to use a void return type and a single 'inout'ed parameter. Same basic idea applies, and admittedly the same basic flaws. In the end, its a pet desire, and I humbly admit it. But it is one thing I'd really like. Current properties are, essentially, like a side-effect of a D'ism allowing single-parameter methods to be invoked as if they were fields. Its cute... but is it wise? -- Chris Sauls
Jun 12 2005
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Chris Sauls wrote:
 Unknown W. Brackets wrote:
 
 A few questions:

 1. What is the benefit this has over the current syntax?

Its more explicit, which I think Properties ought to be.

The current syntax could just as well be made explicit by adding a 'property' attribute, if that's what you mean.
 The current syntax is cute, and does provide the primary requisite 
 for clean properties, which is the ability to be seamless between 
 fields and methods. Or in other words, to user code a property should 
 appear no different from a field.

At the moment, a property does look the same as a field, except that you can't do ++, *=, etc. with properties. It would be straightforward to extend the current D property system so that these operators extend to properties in the natural way. But is your idea going to extend beyond this?
 2. How do you propose to deal with the problem of a single 
 expression/identifier having multiple possible types (which you'll 
 notice D avoids heavily)?

Its a good question. Maybe we could require that there be only one gettor, and that its return type match the type of the property. Or even that it define that type, so that the property itself actually has no type. The type of expressions which use it would then be that of the gettor. I'll have to think on it.

I don't see any point in forcing the internal and external types of the property to be the same. But yes, having only one gettor (getter?) would be sensible. <snip>
 5. Why do you want to use void returning functions with out/inout 
 parameters instead of returning the type as logical for the REST of C/D?

Consider the problem with opCast, where one can have only a single opCast for a given class because there is no overload on return type. One method of avoiding this, which has been proposed, is to use a void return type and a single 'inout'ed parameter. Same basic idea applies, and admittedly the same basic flaws.

That only applies if you want a property to be gettable as more than one type. But to user code, this would be confusing return type overloading just the same. If we were to allow it in this special case, why not allow it for normal functions? If you want to be able to get a property in multiple ways, I was just thinking about allowing functions with arbitrary names to be defined within a property block. They would be accessed by propertyName.functionName. The only problem is that it could get ambiguous with members of the property's default getter. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Jun 13 2005
prev sibling next sibling parent "Matthew" <admin.hat stlsoft.dot.org> writes:
Agreed

"Chris Sauls" <ibisbasenji gmail.com> wrote in message
news:d8i1s9$10f$1 digitaldaemon.com...
 Vathix wrote:
 On Sun, 12 Jun 2005 13:51:00 -0400, KUV <KUV_member pathlink.com> wrote:

 Is there the way to make properties like Delphi, so that writing and  reading
 this property is processed with different function and procedure.

Check out http://www.digitalmars.com/d/property.html and skip down to "Class and Struct Properties".

I still think we'd be better off with C# style properties (I don't know how Delphi's props work.. someone show me an example?). As I do everytime this comes up, I'll show my suggested syntax once again. Apologies to those of you who have seen this a thousand times. But I'm adamant. :) # class Foo { # public property bar : int { # public int property bar { # void get(inout int dest){ dest = _value; } # void get(inout char[] dest){ dest = std.string.toString(_value); } # # void set(inout int src){ _value = src; } # void set(inout char[] src){ _value = toInt(src); } # } # }

Jun 12 2005
prev sibling next sibling parent reply "John C" <johnch_atms hotmail.com> writes:
 I still think we'd be better off with C# style properties (I don't know 
 how Delphi's props work.. someone show me an example?).  As I do everytime 
 this comes up, I'll show my suggested syntax once again. Apologies to 
 those of you who have seen this a thousand times.  But I'm adamant.  :)

 # class Foo {
 #   public property bar : int {
 #   public int property bar {
 #     void get(inout int    dest){ dest = _value;                      }
 #     void get(inout char[] dest){ dest = std.string.toString(_value); }
 #
 #     void set(inout int    src){ _value = src;        }
 #     void set(inout char[] src){ _value = toInt(src); }
 #   }
 # }

I agree, but have a preference for the flexible syntax implemented in C++/CLI (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1600.html). class Address { property int houseNumber { int get() { return houseNumber_; } void set(int value) { houseNumber_ = value; } } property char[] town { final char[] get() { return town_; } } private char[] town_; private int houseNumber_; } You can also have named indexers, which would be nice to have (D only offers opIndex). These can be used to eliminate the need to define separate containers for array-like access: class Library { property Author authors[char[]] { Author get(char[] name) { ... } } } instead of: class Library { class AuthorCollection { Author opIndex(char[] name) { ... } ... } AuthorCollection authors() { return authorCollection_; } private AuthorCollection authorCollection_; } Author author = myLibrary.authors["Murdoch, Iris"];
Jun 13 2005
parent reply "Maxime Larose" <mlarose broadsoft.com> writes:
I don't understand why you all seem intent on making the language so
verbose. Wouldn't the following be a lot clearer and less error-prone:

class A {
  property int houseNumber;
}

With the compiler generating the get and set methods?

For a read-only fields:
class A {
  property readonly int houseNumber;
}

The underlying implementation is trivial and (almost)always identical from
one instance to the next. Let's allow one to define a special setter or
getter if need be, but don't force one to write it...

An alternative (even less verbose) syntax:

class A {
  property {
     int houseNumber;
     readonly char[] street;
   }
}

One that I would even like best (but hey, that's just me!)
class A {
  rw int houseNumber;   // read-write property
  ro street street; // read-only property
}




"John C" <johnch_atms hotmail.com> wrote in message
news:d8ji1p$19e2$1 digitaldaemon.com...
 I still think we'd be better off with C# style properties (I don't know
 how Delphi's props work.. someone show me an example?).  As I do


 this comes up, I'll show my suggested syntax once again. Apologies to
 those of you who have seen this a thousand times.  But I'm adamant.  :)

 # class Foo {
 #   public property bar : int {
 #   public int property bar {
 #     void get(inout int    dest){ dest = _value;                      }
 #     void get(inout char[] dest){ dest = std.string.toString(_value); }
 #
 #     void set(inout int    src){ _value = src;        }
 #     void set(inout char[] src){ _value = toInt(src); }
 #   }
 # }

I agree, but have a preference for the flexible syntax implemented in C++/CLI (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1600.html). class Address { property int houseNumber { int get() { return houseNumber_; } void set(int value) { houseNumber_ = value; } } property char[] town { final char[] get() { return town_; } } private char[] town_; private int houseNumber_; } You can also have named indexers, which would be nice to have (D only

 opIndex). These can be used to eliminate the need to define separate
 containers for array-like access:

     class Library {
         property Author authors[char[]] {
             Author get(char[] name) { ... }
         }
     }

 instead of:

     class Library {
         class AuthorCollection {
             Author opIndex(char[] name) { ... }
             ...
         }
         AuthorCollection authors() { return authorCollection_; }
         private AuthorCollection authorCollection_;
     }

     Author author = myLibrary.authors["Murdoch, Iris"];

Jun 13 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Maxime Larose wrote:
 I don't understand why you all seem intent on making the language so
 verbose. Wouldn't the following be a lot clearer and less error-prone:
 
 class A {
   property int houseNumber;
 }
 
 With the compiler generating the get and set methods?

How would this be different from a normal field? Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Jun 14 2005
parent reply "Maxime Larose" <mlarose broadsoft.com> writes:
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
news:d8m7bp$m5o$1 digitaldaemon.com...
 Maxime Larose wrote:
 I don't understand why you all seem intent on making the language so
 verbose. Wouldn't the following be a lot clearer and less error-prone:

 class A {
   property int houseNumber;
 }

 With the compiler generating the get and set methods?

How would this be different from a normal field?

A setter and getter would be generated for the property. It could obviously be inlined later by the compiler, but the indirection would remain there. Later on, it would be possible to manually specify a getter and/or setter if the need arose, and clients would pick it up without changing a line of code. Don't take this bad, but your question suggests you do not know/realise why getters and setters are used in the first place. Why would one do this: class A { private int number; public int getNumber { return number; } public void setNumber(int n) { number = n; } } ... instanceOfA.setNumber(6); ... = instanceOfA.getNumber(); If it's a 100% equivalent to this: class A { public int number; } instanceOfA.number = 6; ... = instanceOfA.number; ??? The reason is that these forms are not equivalent, at least conceptually. The fact that 'number' is a member variable of class A is an implementation detail, and maybe later on in the program lifecycle the implementation detail will change. E.g., for efficiency 'number' could become lazily calculated, or it could be writen to and read from a DB, etc. Thus, setters and getters shield clients from the implementation details. If/when 'number''s implementation change, not a single line of code has to be changed on the clients. (It may have to be recompiled though, if the compiler optimised away the function call.) Now, to be honest, this whole idiom is a bit silly because in actual facts 99.9% of the time, the getter will simply return the member variable and the setter will set it. In the oft-chance that the implementation is changed later on, making the variable private and recompiling will flag all instances of clients using the variable directly and it is then quite easy to fix. Actually, unless a whole lot implementation details change, which I've never seen personnally, it is probably more time efficient not to bother with setters and getters and later fix the compilation error if the variable is made private. However, an advantage of setters/getters is it allows one to treat variables more or less the same way across the board (setA/getA everywhere) and read-only variables are implemented by simply not coding a setter. In other words it is consistent, i.e. you don't end up with class A being defined as: class A { public int number; // can set and get private char[] street; // read-only public char[] getStreet(); } ... instanceOfA.number ... // to access number ... instanceOfA.street; // invalid .. instanceOfA.getStreet(); // to access street which would make the program look messy. Another compelling reason to use setter and getters is that by convention, in certain languages at least (C and C++), the interface of a class is defined in terms of methods, not exposed public variables. However, there is absolutely no reasons why a language would not help programmers in this regard and give some syntaxing sugar for it, as it is one of the most used idiom. Being built in the language, programmers of that language become accustomed to it and do not hesitate to change publicly exposed variables! So, coming back to my suggestion, the following code would tell the compiler to implement the idiom: Definition: class A { property int houseNumber; } In clients: instanceOfA.setHouseNumber(6); ... = instanceOfA.getHouseNumber(); // or even more simply: // would be translated to use the setter instanceOfA.houseNumber = 6; // would be translated to use the getter ... = instanceOfA.houseNumber; Now, it would be possible to change the implementation details without changing clients: class A { property int houseNumber { get { ...read value from DB...; return value; } set { ...write value in DB...; } } } // clients remain the same, // compiler knows to look for setter/getter // and not use the variable directly instanceOfA.houseNumber = 6; ... = instanceOfA.houseNumber; Ouf! I didn't intend this to be a lecture on setters/getters. Sorry if you knew that stuff... Max
Jun 14 2005
parent "Maxime Larose" <mlarose broadsoft.com> writes:
I didn't read the name of the poster in my reply... Should have since now I
feel stupid having 'explained' all this stuff to you (who knew it for sure).
Wasted my time... oh well...

:-/

Max



"Maxime Larose" <mlarose broadsoft.com> wrote in message
news:d8mf9u$so2$1 digitaldaemon.com...
 "Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
 news:d8m7bp$m5o$1 digitaldaemon.com...
 Maxime Larose wrote:
 I don't understand why you all seem intent on making the language so
 verbose. Wouldn't the following be a lot clearer and less error-prone:

 class A {
   property int houseNumber;
 }

 With the compiler generating the get and set methods?

How would this be different from a normal field?

A setter and getter would be generated for the property. It could

 be inlined later by the compiler, but the indirection would remain there.
 Later on, it would be possible to manually specify a getter and/or setter

 the need arose, and clients would pick it up without changing a line of
 code.

 Don't take this bad, but your question suggests you do not know/realise

 getters and setters are used in the first place. Why would one do this:
 class A {
   private int number;
   public int getNumber { return number; }
   public void setNumber(int n) { number = n; }
 }
 ...
 instanceOfA.setNumber(6);
 ... = instanceOfA.getNumber();


 If it's a 100% equivalent to this:
 class A {
   public int number;
 }
 instanceOfA.number = 6;
 ... = instanceOfA.number;

 ???


 The reason is that these forms are not equivalent, at least conceptually.
 The fact that 'number' is a member variable of class A is an

 detail, and maybe later on in the program lifecycle the implementation
 detail will change. E.g., for efficiency 'number' could become lazily
 calculated, or it could be writen to and read from a DB, etc.

 Thus, setters and getters shield clients from the implementation details.
 If/when 'number''s implementation change, not a single line of code has to
 be changed on the clients. (It may have to be recompiled though, if the
 compiler optimised away the function call.) Now, to be honest, this whole
 idiom is a bit silly because in actual facts 99.9% of the time, the getter
 will simply return the member variable and the setter will set it. In the
 oft-chance that the implementation is changed later on, making the

 private and recompiling will flag all instances of clients using the
 variable directly and it is then quite easy to fix. Actually, unless a

 lot implementation details change, which I've never seen personnally, it

 probably more time efficient not to bother with setters and getters and
 later fix the compilation error if the variable is made private.

 However, an advantage of setters/getters is it allows one to treat

 more or less the same way across the board (setA/getA everywhere) and
 read-only variables are implemented by simply not coding a setter. In

 words it is consistent, i.e. you don't end up with class A being defined

 class A
 {
   public int number;      // can set and get
   private char[] street;  // read-only
   public char[] getStreet();
 }
 ... instanceOfA.number ... // to access number
 ... instanceOfA.street; // invalid
 .. instanceOfA.getStreet();   // to access street

 which would make the program look messy. Another compelling reason to use
 setter and getters is that by convention, in certain languages at least (C
 and C++), the interface of a class is defined in terms of methods, not
 exposed public variables.

 However, there is absolutely no reasons why a language would not help
 programmers in this regard and give some syntaxing sugar for it, as it is
 one of the most used idiom. Being built in the language, programmers of

 language become accustomed to it and do not hesitate to change publicly
 exposed variables!

 So, coming back to my suggestion, the following code would tell the

 to implement the idiom:
 Definition:
 class A {
    property int houseNumber;
 }

 In clients:
 instanceOfA.setHouseNumber(6);
 ... = instanceOfA.getHouseNumber();
 // or even more simply:
 // would be translated to use the setter
 instanceOfA.houseNumber = 6;
 // would be translated to use the getter
 ... = instanceOfA.houseNumber;

 Now, it would be possible to change the implementation details without
 changing clients:
 class A {
    property int houseNumber {
       get { ...read value from DB...; return value; }
       set { ...write value in DB...; }
    }
 }
 // clients remain the same,
 // compiler knows to look for setter/getter
 // and not use the variable directly
 instanceOfA.houseNumber = 6;
 ... = instanceOfA.houseNumber;

 Ouf! I didn't intend this to be a lecture on setters/getters. Sorry if you
 knew that stuff...

 Max

Jun 14 2005
prev sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Let me revise my initial example.  Consider a class 'Foo' with a property 'bar'
of type 
int, set'able with either an int or char[] value.  Okay, then, simple yes? 
Assume its a 
public property, through-and-through.  Now then.  Current D implementation of
properties:

# public class Foo {
#   public int bar () { return p_bar; }
#
#   public int bar (int    x) { return p_bar = x;        }
#   public int bar (char[] x) { return p_bar = toInt(x); }
#
#   private int p_bar;
# }

My proposal (currently... it fluxes, I'll admit) changes this to something like:

# public class Foo {
#   public property bar : int {
#     public set (int    x) { _value = x; }
#     public set (char[] x) { _value = toInt(x); }
#   }
# }

The gettor is the default gettor, simply returning bar._value.  To make a
property 
read-only, just don't define any settors.  So a read-only property looks like
this:

# public property foo : int {/+read only+/}

Or this, maybe:

# public property foo : int ;

Also note that the 'set' has no return-type.  It isn't a function/method at
all, but a 
wrapper around the assignment.  The return-type is always the type of the
property, and 
the return value is always the final contents of the _value variable, which
would be 
compiler-generated along the same lines as _arguments and _argptr currently
are.  As for 
gettors, they are locked into the type of the property, and use an out
parameter.  So, the 
default gettor above would look like this, if it were coded out:

# public get (out int x) { x = _value; }

Why use a parameter?  Well one might presumably do this:

# public class Foo {
#   public property bar : int {
#     public set (int    x) { _value = x; }
#     public set (char[] x) { _value = toInt(x); }
#
#     protected get (out char[] x) { x = std.string.toString(_value); }
#   }
# }

Which would only have meaning in cases like:

# public class Child : Foo {
#   public void someMethod () {
#     char[] str = bar;
#   }
# }

Where the expected type is obvious.  Or if this is two much complexity for the
compiler, 
then two other options are available.  An explicit get-invokation for special
gettors, so 
that the above becomes:

# char[] str;
# bar.get(str);

Or just disallow alternatively-typed gettors entirely, and make the syntax of
the gettor 
into just:

# [protection] 'get' '{' code '}'

Okay, I will hush now.  I'm really just typing my thoughts as they come to me,
anyhow. 
Its something that I would like, but if it really isn't a true improvement,
then so be it. 
  D isn't C#, nor do I want it to be.  :)

-- Chris Sauls
Jun 13 2005
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Chris Sauls wrote:
<snip>
 Also note that the 'set' has no return-type.  It isn't a function/method 
 at all, but a wrapper around the assignment.  The return-type is always 
 the type of the property, and the return value is always the final 
 contents of the _value variable,

Why not make it return the return value of the gettor? It would make sense. See also digitalmars.D/10199 Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Jun 14 2005