www.digitalmars.com         C & C++   DMDScript  

D - [Bug-ish] Dangerous property syntax [DTL-related]

reply "Matthew" <matthew.hat stlsoft.dot.org> writes:
I'm writing the Range helper for the List class, which has (roughly) the
following interface:

    template(T)
    {
        public class ListRange
        {
        public:
            boolean open();
            value_type current();
            void advance();
        public:
            int opApply(. . .);
        }
    }

As well as being able to be applied to foreach, a Range may be enumerated
individually via the following idiom:

    List!(int)    l = . . .;

    List!(int).range_type    r    =    l[]; // A full slice. Other slices
are available, as well as several kinds of filtering

    for(; r.open; r.advance())
    {
        printf("%d ", r.current);
    }

Anyway, the point I want to put accross is that I think D's implicit
properties mechanism is entirely appropriate for open() and current(), but
entirely inappropriate for advance(), because it is a mutating method call,
and *not* a property. But because it takes no parameters, it could be called
in property style, i.e. without the (). I would like some mechanism in the
language to proscribe this, perhaps something like:

    template(T)
    {
        public class ListRange
        {
        public:
            boolean open();
            value_type current();
            method void advance();
or
            no property void advance();
        public:
            int opApply(. . .);
        }
    }

or even better would be a requirement to apply the property to any methods
that are up for implicit property interpretation, as in:

    template(T)
    {
        public class ListRange
        {
        public:
            property boolean open();
            property value_type current();
            void advance();
        public:
            int opApply(. . .);
        }
    }

I know some people have grokked "the D way", as in the .dup "method" in
built-in arrays, but I think it's a mistake not to differentiate between
attributes (methods / fields) and modifying methods.

Thoughts everyone?
Apr 21 2004
next sibling parent reply Dave Sieber <dsieber spamnot.sbcglobal.net> writes:
"Matthew" <matthew.hat stlsoft.dot.org> wrote:

 I know some people have grokked "the D way", as in the .dup "method"
 in built-in arrays, but I think it's a mistake not to differentiate
 between attributes (methods / fields) and modifying methods.
 
 Thoughts everyone?

In your example, advance is void, so shouldn't be a property anyway, whether it has side effects or not. What's the "property"? (but one could define advance to have a boolean success return value...) Personally, I like the C# way, where you explicitly write get{} and/or set{} methods: class Person public string Name { get { return myName; } set { myName = value; } } }; Here, you have to specify a type, and can leave out set{} if it's read only. But if not that, I think explicitly saying "property" on the declaration would be good -- and without it, you would have to use method call notation. It should be one or the other, but not wishy-washy like Perl's TMTOWTDI, otherwise the language is getting sloppy and Perl already covers that territory (it would be nice to learn not only from C++'s mistakes). In fact, I might like an explicit keyword better than C#'s way anyway: a property has the keyword "property" (somewhere), and may only be used with property syntax, using the "say what you mean and mean what you say" principle. No one is misled by it. Also makes it easy to search for with your text editor, just like "cast". -- dave
Apr 21 2004
next sibling parent "C. Sauls" <ibisbasenji yahoo.com> writes:
Dave Sieber wrote:
 Personally, I like the C# way, where you explicitly write get{} and/or 
 set{} methods:
 
 class Person
     public string Name {
         get { return myName; }
         set { myName = value; }
     }
 };

We have it similarly in the Lux concept-language... a la: define class Person { define public { property str Name { Name = "Person_Default_Name"; str get() { return Name; } str set(str x) { return Name = x; } str set([]str xx) { import std.utils.string; return Name = xx:join("_"); } } } } Something worth noting about the Lux syntax, and which I'd like to see in D if it were to adopt an explicit property syntax, is that the get/set methods are defined with full prototypes, allowing you to support multiple types on one property. And I suppose in D one could even templatize a property thereby making it support all types universally, or at least in theory. -C. Sauls -Invironz
Apr 21 2004
prev sibling next sibling parent "Matthew" <matthew.hat stlsoft.dot.org> writes:
That's pretty much how I feel, except that instinct tells me that allowing
properties to also be called in method syntax will provide for more genericity
down the line.


"Dave Sieber" <dsieber spamnot.sbcglobal.net> wrote in message
news:Xns94D244BCD2FB8dsiebersbc 63.105.9.61...
 "Matthew" <matthew.hat stlsoft.dot.org> wrote:

 I know some people have grokked "the D way", as in the .dup "method"
 in built-in arrays, but I think it's a mistake not to differentiate
 between attributes (methods / fields) and modifying methods.

 Thoughts everyone?

In your example, advance is void, so shouldn't be a property anyway, whether it has side effects or not. What's the "property"? (but one could define advance to have a boolean success return value...) Personally, I like the C# way, where you explicitly write get{} and/or set{} methods: class Person public string Name { get { return myName; } set { myName = value; } } }; Here, you have to specify a type, and can leave out set{} if it's read only. But if not that, I think explicitly saying "property" on the declaration would be good -- and without it, you would have to use method call notation. It should be one or the other, but not wishy-washy like Perl's TMTOWTDI, otherwise the language is getting sloppy and Perl already covers that territory (it would be nice to learn not only from C++'s mistakes). In fact, I might like an explicit keyword better than C#'s way anyway: a property has the keyword "property" (somewhere), and may only be used with property syntax, using the "say what you mean and mean what you say" principle. No one is misled by it. Also makes it easy to search for with your text editor, just like "cast". -- dave

Apr 21 2004
prev sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Dave Sieber" <dsieber spamnot.sbcglobal.net> wrote in message
news:Xns94D244BCD2FB8dsiebersbc 63.105.9.61
| "Matthew" <matthew.hat stlsoft.dot.org> wrote:
|
|| I know some people have grokked "the D way", as in the .dup "method"
|| in built-in arrays, but I think it's a mistake not to differentiate
|| between attributes (methods / fields) and modifying methods.
||
|| Thoughts everyone?
|
| In your example, advance is void, so shouldn't be a property anyway,
| whether it has side effects or not. What's the "property"? (but one could
| define advance to have a boolean success return value...)
|
| Personally, I like the C# way, where you explicitly write get{} and/or
| set{} methods:
|
| class Person
|     public string Name {
|         get { return myName; }
|         set { myName = value; }
|     }
| };
|
| Here, you have to specify a type, and can leave out set{} if it's read
| only.
|
| But if not that, I think explicitly saying "property" on the declaration
| would be good -- and without it, you would have to use method call
| notation. It should be one or the other, but not wishy-washy like Perl's
| TMTOWTDI, otherwise the language is getting sloppy and Perl already covers
| that territory (it would be nice to learn not only from C++'s mistakes).
|
| In fact, I might like an explicit keyword better than C#'s way anyway: a
| property has the keyword "property" (somewhere), and may only be used with
| property syntax, using the "say what you mean and mean what you say"
| principle. No one is misled by it. Also makes it easy to search for with
| your text editor, just like "cast".
|
| --
| dave

Sorry for joining late, but there're just too many messages!
A couple of things:
1. TMTOWTDI???
2. In to the subject, I rather prefer the Delphi way, where you do something
like this:

property MyProp : SomeType; read foo; write bar;

Where foo must be a function returning a SomeType, or a variable of type
SomeType, and bar is a variable of type SomeType, or a procedure taking a
SomeType as parameter. They're both optional, so you automatically know if
they're read-only, write-only or read-write. They can have a default
modifier, and IIRC an index modifier or something like that. And, of course,
if you want you can use foo or bar as if MyProp didn't exist.
Ilya suggested this a long time ago, but Walter just didn't like it.
And BTW, I'm writing this as I remember things, so things might not be 100%
accurate. But that's the general idea.

-----------------------
Carlos Santander Bernal
Apr 23 2004
parent Dave Sieber <dsieber spamnot.sbcglobal.net> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote:

 Sorry for joining late, but there're just too many messages!
 A couple of things:
 1. TMTOWTDI???

Perl's guiding principle on how to write unmaintainable software: "There's More Than One Way To Do It"
 2. In to the subject, I rather prefer the Delphi way, where you do
 something like this:
 
 property MyProp : SomeType; read foo; write bar;

This is similar to what Microsoft provides in their C++ compiler for COM property support. In COM interfaces there are no member variables, so "properties" are implemented via methods. In their C++ compiler, they have a special syntax you can use, similar to the above, to create fake properties. But it doesn't enforce anything, you can still call the methods directly.
 And, of course, if you want you can use foo or
 bar as if MyProp didn't exist.

This is what I don't like (the TMTOWTDI problem again): there should be only ONE access point to fetch a property value, not two. It becomes a maintainence problem: client code can always bypass your Property definition and call methods directly, so you can't change the implementation without potentially breaking client code. Bad design. In C# they corrected this. -- dave
Apr 23 2004
prev sibling parent reply "Ben Hinkle" <bhinkle4 juno.com> writes:
 I know some people have grokked "the D way", as in the .dup "method" in
 built-in arrays, but I think it's a mistake not to differentiate between
 attributes (methods / fields) and modifying methods.

 Thoughts everyone?

Usually it is clear from the name if a "property" is modifying or doing something fishy. I have grown to like the brevity of .dup and other short-but-sweet calls. It gets rid of those ugly () that would have to get tacked on. And since I'm super-lazy I'd like to suggest using .next instead of .advance in the DTL api. -Ben
Apr 21 2004
next sibling parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Ben Hinkle wrote:

I know some people have grokked "the D way", as in the .dup "method" in
built-in arrays, but I think it's a mistake not to differentiate between
attributes (methods / fields) and modifying methods.

Thoughts everyone?

Usually it is clear from the name if a "property" is modifying or doing something fishy. I have grown to like the brevity of .dup and other short-but-sweet calls. It gets rid of those ugly () that would have to get tacked on. And since I'm super-lazy I'd like to suggest using .next instead of .advance in the DTL api.

I don't agree. The () carries information that is lost if you "abuse" properties for methods. For example, if I read something like x=b.next I expect "next" to be a field of b (whether it is a variable or derived information returned by a function doesn't matter). I do not expect that b is modified when one of its fields is read! So if I write b.next twice without explictly modifying b in between I expect to get the same result each time. In contrast, b.next() makes it clear that something may happen during the call that modifies b, like advancing the iterator or something. Don't get me wrong, I like properties in general. But I think that if the syntax stays the way it is there should be a firm convention that "read-access" to properties does not modify the object. For consistency that should also include iterators and the like. Hauke
Apr 21 2004
next sibling parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Hauke Duden wrote:

 Ben Hinkle wrote:

 I know some people have grokked "the D way", as in the .dup "method" in
 built-in arrays, but I think it's a mistake not to differentiate 
 between
 attributes (methods / fields) and modifying methods.

 Thoughts everyone?

Usually it is clear from the name if a "property" is modifying or doing something fishy. I have grown to like the brevity of .dup and other short-but-sweet calls. It gets rid of those ugly () that would have to get tacked on. And since I'm super-lazy I'd like to suggest using .next instead of .advance in the DTL api.

I don't agree. The () carries information that is lost if you "abuse" properties for methods. For example, if I read something like x=b.next I expect "next" to be a field of b (whether it is a variable or derived information returned by a function doesn't matter). I do not expect that b is modified when one of its fields is read! So if I write b.next twice without explictly modifying b in between I expect to get the same result each time. In contrast, b.next() makes it clear that something may happen during the call that modifies b, like advancing the iterator or something. Don't get me wrong, I like properties in general. But I think that if the syntax stays the way it is there should be a firm convention that "read-access" to properties does not modify the object. For consistency that should also include iterators and the like. Hauke

I don't like this idea for read-access. There are cases where you want to use latent computation, so you don't have to recompute something again (ie cache). And don't say use a method because often you start of with a public variable and late in the design process make it into a property method. -- -Anderson: http://badmama.com.au/~anderson/
Apr 21 2004
parent Hauke Duden <H.NS.Duden gmx.net> writes:
J Anderson wrote:

 Hauke Duden wrote:
 
 Ben Hinkle wrote:

 I know some people have grokked "the D way", as in the .dup "method" in
 built-in arrays, but I think it's a mistake not to differentiate 
 between
 attributes (methods / fields) and modifying methods.

 Thoughts everyone?

Usually it is clear from the name if a "property" is modifying or doing something fishy. I have grown to like the brevity of .dup and other short-but-sweet calls. It gets rid of those ugly () that would have to get tacked on. And since I'm super-lazy I'd like to suggest using .next instead of .advance in the DTL api.

I don't agree. The () carries information that is lost if you "abuse" properties for methods. For example, if I read something like x=b.next I expect "next" to be a field of b (whether it is a variable or derived information returned by a function doesn't matter). I do not expect that b is modified when one of its fields is read! So if I write b.next twice without explictly modifying b in between I expect to get the same result each time. In contrast, b.next() makes it clear that something may happen during the call that modifies b, like advancing the iterator or something. Don't get me wrong, I like properties in general. But I think that if the syntax stays the way it is there should be a firm convention that "read-access" to properties does not modify the object. For consistency that should also include iterators and the like. Hauke

I don't like this idea for read-access. There are cases where you want to use latent computation, so you don't have to recompute something again (ie cache). And don't say use a method because often you start of with a public variable and late in the design process make it into a property method.

I agree. I don't mean that gettor methods should be the same as const methods in C++. The important thing is that the visible(!) state of the object is not changed by reading a field. If you want to cache a result in your property method that's fine, since it doesn't change the way the object behaves to the outside. What I really want, is not having to look at the source code of each and every class that is used in an expression in order to find out what it does. Is "next" just a plain variable or a property or a method that changes something? The whole point of properties is that you can treat methods like variables and that the way the property is implemented remains opaque to the user. If you have side-effects during read access that's not opaque at all. Hauke
Apr 21 2004
prev sibling next sibling parent "Ben Hinkle" <bhinkle4 juno.com> writes:
 For example, if I read something like x=b.next I expect "next" to be a
 field of b (whether it is a variable or derived information returned by
 a function doesn't matter).

In Matthew's code .advance didn't return anything so writing x=b.advance or x=b.next or whatever would be a compile-time error. If I read "b.next;" used as a statement then I suspect it has side effects because otherwise it would be a no-op. I agree a property name that returns something *and* is ambiguous that it has side effects is nasty. I haven't looked for examples of D code that could be like this but it would be interesting to search around and see how properties are being used and if they are being used for side effects or not.
Apr 21 2004
prev sibling next sibling parent reply Dave Sieber <dsieber spamnot.sbcglobal.net> writes:
Hauke Duden <H.NS.Duden gmx.net> wrote:

 I don't agree. The () carries information that is lost if you "abuse" 
 properties for methods.

I have to agree here -- if something can be abused, it will be. C taught us that :-)
 For example, if I read something like x=b.next I expect "next" to be a
 field of b (whether it is a variable or derived information returned
 by a function doesn't matter). I do not expect that b is modified when
 one of its fields is read! So if I write b.next twice without
 explictly modifying b in between I expect to get the same result each
 time. 

That's a good example. A property is really (IMO) a member variable that you want to have access control over. You should be able to change them from methods to member variables (and vice versa) in your class declaration, and the client code should still work. If you can't, it should not be a "property" -- in fact, it isn't one. In the D spec, it says: Class and Struct Properties: Properties are member functions that can by syntactically treated as if they were fields. By this definition, .dup, .sort, and .advance are not properties, and should be invokable only with method call syntax. Doesn't matter whether they modify the object or not, they aren't interchangable with member variables. Also doesn't matter if their value can change between fetches: a Timer class could have a property, .ticks, which of course will change (hopefully :-) every few times you get its value. But it could be implemented as a member variable if the class was built to allow this, and you could also write ".ticks = 0" to reset it. Something like this would be a good use of properties, in case you need to perform some action when resetting the timer, etc. That's all that those "getter/setter" methods you see in Java code do: control access to some member variable. Unfortunately, Java is not smart enough to encapsulate them in a clean syntax, and this is something C# improved on. The more I think about this, the more I think this is an error in D, although not a serious one. I basically don't like the idea that methods can be invoked with two different syntax options, and that in looking at some code, I don't know if I'm looking at a method call, or a member variable (and no, "guessing" about the name doesn't count). -- dave
Apr 21 2004
parent J Anderson <REMOVEanderson badmama.com.au> writes:
Dave Sieber wrote:

By this definition, .dup, .sort, and .advance are not properties, and 
should be invokable only with method call syntax.
  

 That's a good example. A property is really (IMO) a member variable that

Oh no, I'm feel another re-fix of dig <g>. If it must change it must change :( -- -Anderson: http://badmama.com.au/~anderson/
Apr 21 2004
prev sibling next sibling parent "Matthew" <matthew.hat stlsoft.dot.org> writes:
Absolutely agreed. I think we could all learn from Ruby in this, which uses !, ?
and "nothing at all" suffixes to denote modifying, querying and "other" method
types, since it does not require () for 0-parameter method calls

"Hauke Duden" <H.NS.Duden gmx.net> wrote in message
news:c669v2$1fd8$1 digitaldaemon.com...
 Ben Hinkle wrote:

I know some people have grokked "the D way", as in the .dup "method" in
built-in arrays, but I think it's a mistake not to differentiate between
attributes (methods / fields) and modifying methods.

Thoughts everyone?

Usually it is clear from the name if a "property" is modifying or doing something fishy. I have grown to like the brevity of .dup and other short-but-sweet calls. It gets rid of those ugly () that would have to get tacked on. And since I'm super-lazy I'd like to suggest using .next instead of .advance in the DTL api.

I don't agree. The () carries information that is lost if you "abuse" properties for methods. For example, if I read something like x=b.next I expect "next" to be a field of b (whether it is a variable or derived information returned by a function doesn't matter). I do not expect that b is modified when one of its fields is read! So if I write b.next twice without explictly modifying b in between I expect to get the same result each time. In contrast, b.next() makes it clear that something may happen during the call that modifies b, like advancing the iterator or something. Don't get me wrong, I like properties in general. But I think that if the syntax stays the way it is there should be a firm convention that "read-access" to properties does not modify the object. For consistency that should also include iterators and the like. Hauke

Apr 21 2004
prev sibling parent "Carlos Santander B." <carlos8294 msn.com> writes:
"Hauke Duden" <H.NS.Duden gmx.net> wrote in message
news:c669v2$1fd8$1 digitaldaemon.com
| I don't agree. The () carries information that is lost if you "abuse"
| properties for methods.
|
| For example, if I read something like x=b.next I expect "next" to be a
| field of b (whether it is a variable or derived information returned by
| a function doesn't matter). I do not expect that b is modified when one
| of its fields is read! So if I write b.next twice without explictly
| modifying b in between I expect to get the same result each time.
|
| In contrast, b.next() makes it clear that something may happen during
| the call that modifies b, like advancing the iterator or something.
|
| Don't get me wrong, I like properties in general. But I think that if
| the syntax stays the way it is there should be a firm convention that
| "read-access" to properties does not modify the object. For consistency
| that should also include iterators and the like.
|
| Hauke

That's your POV. I don't think that omitting () or not, tells you something
additional. From your same example, the name "next" tells me that if b is
some kind of collection or something, it might advance, and that's what I'd
be expecting. I wouldn't care about the ().
Now, I do agree that there should be a way to tell properties and methods
apart. And I do agree that some properties in D built-in types should be
methods rather than properties.
But that's just me.

-----------------------
Carlos Santander Bernal
Apr 23 2004
prev sibling parent "Matthew" <matthew.hat stlsoft.dot.org> writes:
"Ben Hinkle" <bhinkle4 juno.com> wrote in message
news:c665uf$18ij$1 digitaldaemon.com...
 I know some people have grokked "the D way", as in the .dup "method" in
 built-in arrays, but I think it's a mistake not to differentiate between
 attributes (methods / fields) and modifying methods.

 Thoughts everyone?

Usually it is clear from the name if a "property" is modifying or doing something fishy. I have grown to like the brevity of .dup and other short-but-sweet calls. It gets rid of those ugly () that would have to get tacked on. And since I'm super-lazy I'd like to suggest using .next instead of .advance in the DTL api.

I've reasons for not using .next, since that's part of several Object-based runtime polymorphic enumeration interfaces that we'll be supporting. Also, Ranges (as defined in "Imperfect C++" - to the newbies, that's my new Addison-Wesley book coming out in Sept) defines the method-based form to use advance()/Advance() when the operator-based form is not used (which it cannot be in D, because we do not, and will not, have opDeref / operator *()).
Apr 21 2004