D - Alternative syntax for property getters
- Riccardo De Agostini (32/32) Aug 04 2003 While properties are still on Walters to-do list, here I come with one m...
- Ilya Minkov (27/34) Aug 04 2003 No, not at all, i was just waiting for someone to make this kind of
- Riccardo De Agostini (59/74) Aug 04 2003 Shall I start signing as "El Dhe"? :-)
- Ilya Minkov (12/14) Aug 04 2003 Riccardo De Agostini wrote:
- Riccardo De Agostini (56/63) Aug 04 2003 Mmmh... do you mean that, given my last code example, we can just redefi...
- Ilya Minkov (34/58) Aug 05 2003 Defining the property as read-only or write-only is probably best done
- Riccardo De Agostini (21/32) Aug 08 2003 I see your point and it's a good one, from a pragmatic OO point of view;
- Ilya Minkov (30/48) Aug 08 2003 HARD ROCK :>
- Mike Wynn (38/69) Aug 08 2003 I can see that read to read/write would be valid,
- Riccardo De Agostini (12/13) Aug 25 2003 (This is also to reply to Ilya's message)
While properties are still on Walters to-do list, here I come with one more attempt to revolution... :-) Hope I'm not annoying anyone. Since most property getters will probably just return the value of a data member, there's gonna be lots of: class MyClass { private: int m_MyProperty; public: int MyProperty() { return m_MyProperty; } void MyProperty(int aValue) { m_MyProperty = do_whatever_it_takes(aValue); } } Talking about the property getter, that's code that will _almost_ surely be inlined by the compiler; still, it does _look_ as if a function call is actually going to happen, and requires the compiler to recognize the code as inline-able. Wouldn't it be easier for both the programmer and the compiler if there was a property getter simplified form like the following? class MyClass { private: int m_MyProperty; public: int MyProperty() = m_MyProperty; // Here it is void MyProperty(int aValue) { m_MyProperty = do_whatever_it_takes(aValue); } } That would make it clear, both to the reader and the compiler, that reading the property _is_ actually reading the data member. Less typing, a bit more work for the parser maybe, but less work for the optimizer. Any feedback greatly appreciated. Ric
Aug 04 2003
Riccardo De Agostini wrote:While properties are still on Walters to-do list, here I come with one more attempt to revolution... :-) Hope I'm not annoying anyone.No, not at all, i was just waiting for someone to make this kind of discussion started! It's a hot topic to the library design.Since most property getters will probably just return the value of a data member, there's gonna be lots of:[snip!]That would make it clear, both to the reader and the compiler, that reading the property _is_ actually reading the data member. Less typing, a bit more work for the parser maybe, but less work for the optimizer.Well, it would be really a *very* small revolution. :) You must consider, that for getters and setters, function bodies have to be generated anyway. What for? Inheritance. I don't see how your idea would simplify the compiler. Most probably not. But what makes code more readable, is definately worth it. In Delphi, a more wordy definition is used. IIRC something along the lines of: property MyName: TType read GetName write SetName; And now comes the magic part: both the identifier after the read, and the one after the write keyword, may be either a member function (a method), or the storage field! The only disadvantage is, that it takes up one more line in worst case: if you use both non-trivial acessor and setter. Advantages are numerous: * you can search for properties by a keyword, and distinguish them on the first look; * where a field is specified instead of a method, a corresponding trivial method is generated automatically; * in D, the advantage can be exploted further, by the possibility to define getter and setter functions inline, right within the property statement! Any other ideas? -i.
Aug 04 2003
"Ilya Minkov" <midiclub 8ung.at> ha scritto nel messaggio news:bgln9f$1nrq$1 digitaldaemon.com...Riccardo De Agostini wrote: Well, it would be really a *very* small revolution. :)Shall I start signing as "El Dhe"? :-)You must consider, that for getters and setters, function bodies have to be generated anyway. What for? Inheritance. I don't see how your idea would simplify the compiler. Most probably not. But what makes code more readable, is definately worth it.The compiler would know in advance that the getter is to be inlined; maybe it would be easier for the optimizer to load the data member in whatever register is available and fits best at call time, instead of just generating a "fake" function body which always uses AX / EAX. This is only loud thinking, since I must admit I know nearly nothing about compiler theory; but it seems practicable at first sight.In Delphi, a more wordy definition is used. IIRC something along the lines of: property MyName: TType read GetName write SetName; And now comes the magic part: both the identifier after the read, and the one after the write keyword, may be either a member function (a method), or the storage field!Guess where my idea came from... ;-) Delphi properties cannot be virtual; "read" and "write" methods can, though. Consequently, if you define a property getter as a direct access to a data member, it cannot be overridden. IMHO this would be correct in D too: no "virtual int MyProperty() = m_MyProperty". Or maybe let it be a D'ified version of Delphi's properties: // "common" should be "static" currently... but hope is the last to die... :-) // Also, read "constructor" as "this" and "destructor" as "~this". class MyClass { private: common ulong m_Count; private: int m_MyProperty; private: virtual int SetMyProperty(int aValue) { do_whatever_it_takes(aValue); } public: constructor() { ++m_Count; } destructor() { --m_Count; } public: common property ulong Count get m_Count; // read-only property int MyProperty get m_MyProperty set SetMyProperty; }* in D, the advantage can be exploted further, by the possibility to define getter and setter functions inline, right within the property statement!Aw, I like that one!!! // "common" should be "static" currently... but hope is the last to die... :-) // Also, read "constructor" as "this" and "destructor" as "~this". class MyClass { private: common ulong m_Count; private: int m_MyProperty; public: constructor() { ++m_Count; } constructor(int aValue) { constructor(); MyProperty = aValue; } destructor() { --m_Count; } public: common property ulong Count get m_Count; // read-only property int MyProperty get m_MyProperty set { do_whatever_it_takes(aValue); } } This leaves me with a question mark about virtual methods, but I'm sure it can be worked out. Any ideas anyone? Ric
Aug 04 2003
Riccardo De Agostini wrote: Hm... i didn't know delphi properties had to resolve statically... What a shame on me! Anyway, we'd have virtual in D.This leaves me with a question mark about virtual methods, but I'm sure it can be worked out. Any ideas anyone?In D, all object methods are virtual. Just that in the optimised builds, the compiler would be able to figure out which of them are final, and thus be able to inline them. BTW, inlining is done on approximately C code level, there are no registers marked yet. That's why it's such an effective optimisation: after common subexpression removal and assignment flow optimisations, the code may simplify greatly, thus matching hand-optimised code in quality. -i.
Aug 04 2003
"Ilya Minkov" <midiclub 8ung.at> ha scritto nel messaggio news:bglqbf$1qou$1 digitaldaemon.com...In D, all object methods are virtual. Just that in the optimised builds, the compiler would be able to figure out which of them are final, and thus be able to inline them.Mmmh... do you mean that, given my last code example, we can just redefine the property in a subclass and let the compiler do the dirty work? That's great! Now, what if I want to redefine a read-only method as read-write, or vice versa? And if I want to define abstract getters / setters? Let's see if there can be a syntax for all this, possibly one that makes sense... // "common" should be "static" currently... but hope is the last to die... :-) // Also, read "constructor" as "this" and "destructor" as "~this". class MyBaseClass { private: common ulong m_Count; private: int m_MyProperty; public: constructor() { ++m_Count; } constructor(int aValue) { constructor(); MyProperty = aValue; } destructor() { --m_Count; } public: common property ulong Count get m_Count; // read-only property int MyProperty get m_MyProperty set { do_whatever_it_takes(aValue); } } // I want MyDerivedClass to handle setting MyProperty // internally, so it must be read-only. class MyDerivedClass: MyBaseClass { public: constructor() { super(some_initial_value); } public: property int MyProperty set 0; } In this example, MyDerivedClass does not redefine MyProperty's getter, so it remains the same, while the setter is defined as not implemented for this class. A "notimpl" keyword instead of 0 would be better, probably. While wandering in the mists of my compiler ignorance, I suppose that: - an unimplemented getter / setter would translate as a NULL pointer in the vtable; - the RTL should be smart enough as to throw an "unimplemented" exception instead of going straight to page fault, in the case of an unimplemented getter / setter being called via a base class reference (while calling it via a reference to the "unimplementing" class could be trapped at compile time, IF no further-derived classes reimplement it) - the compiler should always make room for both getter and setter every time a property is defined, in case a derived class adds a setter where its base class had none. Of course, a really cool optimizer could even strip never-implemented getters / setters from vtables, but I guess this would be no picnic...BTW, inlining is done on approximately C code level, there are no registers marked yet. That's why it's such an effective optimisation: after common subexpression removal and assignment flow optimisations, the code may simplify greatly, thus matching hand-optimised code inquality. Thanks for enlightening me about that. As I said, compiler theory is voodoo to me. Ric
Aug 04 2003
Riccardo De Agostini wrote:Mmmh... do you mean that, given my last code example, we can just redefine the property in a subclass and let the compiler do the dirty work? That's great!That's how it's intended.Now, what if I want to redefine a read-only method as read-write, or vice versa? And if I want to define abstract getters / setters? Let's see if there can be a syntax for all this, possibly one that makes sense...Defining the property as read-only or write-only is probably best done by leaving out the set or get clause. It should be distinguished between defining getter or setter without an implementation and defining no getter or setter. For the first case, the class would become abstract, and current declaration syntax for pure virtual functions should be adapted. (is there one? i didn't find one in the spec!) Implicitly, a property defines 2 virtual functions, if used both with get and set clauses. What that means, is that in derived classes, you can only leave a property access as it was, or make it both read- and write-enabled, by adding another declaration clause, and implicitly by defining another function. It should be impossible to undefine a setter as you have proposed it, else calling using class is inherently unsafe. Turn to any OO book for a motivation why you cannot leave undefined virtual functions in classes which are to be instantiated, or ask me and i'll explain as soon as i have some time.In this example, MyDerivedClass does not redefine MyProperty's getter, so it remains the same, while the setter is defined as not implemented for this class. A "notimpl" keyword instead of 0 would be better, probably.Why not use null keyword? Then again: this example is illegal in OO terms!While wandering in the mists of my compiler ignorance, I suppose that: - an unimplemented getter / setter would translate as a NULL pointer in the vtable;A class with NULLs in the VTable cannot be safely instantiated, because other functions of this class probably rely on having each function implemented!- the RTL should be smart enough as to throw an "unimplemented" exception instead of going straight to page fault, in the case of an unimplemented getter / setter being called via a base class reference (while calling it via a reference to the "unimplementing" class could be trapped at compile time, IF no further-derived classes reimplement it)If you *really* think you need to leave a getter or setter unimplemented, care to provide a stub implemntation which throws an exception -- but before you do it and break your code think again. Maybe you need to declare a more restricted access in the parent? Then you can still widen it in further derived types.- the compiler should always make room for both getter and setter every time a property is defined, in case a derived class adds a setter where its base class had none. Of course, a really cool optimizer could even strip never-implemented getters / setters from vtables, but I guess this would be no picnic...It should make room for what you declare. And what you declare, you must somewhere define.Thanks for enlightening me about that. As I said, compiler theory is voodoo to me.For me, optimisations done in the backend are black magic. :) I just know they can do amazing things, like optimise out the whole stupidity which comes from template expansion in C++... But what a frontend does, is fairly clear, at least in such a language as D which aviods too much complication. -i.
Aug 05 2003
"Ilya Minkov" <midiclub 8ung.at> ha scritto nel messaggio news:bgpgu7$2ens$1 digitaldaemon.com...Implicitly, a property defines 2 virtual functions, if used both with get and set clauses. What that means, is that in derived classes, you can only leave a property access as it was, or make it both read- and write-enabled, by adding another declaration clause, and implicitly by defining another function. It should be impossible to undefine a setter as you have proposed it, else calling using class is inherently unsafe.I see your point and it's a good one, from a pragmatic OO point of view; there are, however, cases where being able to turn an inherited property from read/write to read-only can be useful.Turn to any OO book for a motivation why you cannot leave undefined virtual functions in classes which are to be instantiated, or ask me and i'll explain as soon as i have some time.Too kind of you, really... <g> OK, so let's say that if I want to turn an inherited property to read-only I can always override the setter with one that just raises an exception. That should make both of us happy: no NULLs in the VTable, *and* I can break, crush and disintegrate my own code, be it perhaps for the mere fun of it. :-) All of this, unfortunately, is going to remain in the field of pure theory, however, because nobody seems to have noticed this discussion, apart from the two of us.It should make room for what you declare. And what you declare, you must somewhere define.Consider a base class that declares a read-only property (no setter); then, two or more distinct derived classes extend the property to read-write. Woudn't we potentially end up having the address of the setter function at different points in the VTable? Or is that no problem because, being the property read-only in the base class, we cannot call the setter via a base-class reference anyway? Ric
Aug 08 2003
Riccardo De Agostini wrote:I see your point and it's a good one, from a pragmatic OO point of view; there are, however, cases where being able to turn an inherited property from read/write to read-only can be useful.There are such cases even with usual virtual functions. :)OK, so let's say that if I want to turn an inherited property to read-only I can always override the setter with one that just raises an exception. That should make both of us happy: no NULLs in the VTable, *and* I can break, crush and disintegrate my own code, be it perhaps for the mere fun of it. :-)HARD ROCK :>All of this, unfortunately, is going to remain in the field of pure theory, however, because nobody seems to have noticed this discussion, apart from the two of us.Walter reads everything. Give him time.Consider a base class that declares a read-only property (no setter); then, two or more distinct derived classes extend the property to read-write. Woudn't we potentially end up having the address of the setter function at different points in the VTable?Sure.Or is that no problem because, being the property read-only in the base class, we cannot call the setter via a base-class reference anyway?Exactly, there is no way to access this setter. Now, here comes my FINAL PROPOSAL. Walter should simply decide on how these acessor functions are to be called. They can be called with a field name, as in the original plan, or with getField and setField. This is easy to do -- whenever a compiler detects a read from or a write to a field which isn't declared or is inacessible (i.e. private), it should go and generate a function call in that place. Then we can write this function definitions directly in the class, and be happy for the start. Then someday later, an alternative, greppable and legible syntax can be bolted on. I would recommend getField and setField or something along these lines for function names, since it can be searched for. Maybe propertyField for both? Ah, another thing: obviously this name rewsolution and propoerty things should not only apply to classes, but also to structs. Just that it is obvious that structs have no virtuals. How about me hacking the frontend to implement them? I'll give it a try next days. It's a pity we don't have just *some* backend to test it with! We need one of the folowing badly: * a GCC port * an integrated backport of DLI with some linkable output * interpreter/VM? * Walter: maybe we could have some crippled version of your backend as DLL? -i.
Aug 08 2003
"Riccardo De Agostini" <riccardo.de.agostini email.it> wrote in message news:bh0do7$2re9$1 digitaldaemon.com..."Ilya Minkov" <midiclub 8ung.at> ha scritto nel messaggio news:bgpgu7$2ens$1 digitaldaemon.com...I can see that read to read/write would be valid, like java allows a sub class to make a method more public (not less) it would be pointless for a subclass to define access to a member as more restrictive than its base class (all you have to do is cast or pass as base and you regain access).Implicitly, a property defines 2 virtual functions, if used both with get and set clauses. What that means, is that in derived classes, you can only leave a property access as it was, or make it both read- and write-enabled, by adding another declaration clause, and implicitly by defining another function. It should be impossible to undefine a setter as you have proposed it, else calling using class is inherently unsafe.I see your point and it's a good one, from a pragmatic OO point of view; there are, however, cases where being able to turn an inherited property from read/write to read-only can be useful.with a dynamic lang (like Java where base classes can change) so calls to super might be missing you do need a default (can all be the same throw an exception) function, but on a statically compiled lang the compiler should be able to tell that your attempting to either create an instance of an abstract class or call a method that can never be (super.method() either does nothing or causes a compiler error)Turn to any OO book for a motivation why you cannot leave undefined virtual functions in classes which are to be instantiated, or ask me and i'll explain as soon as i have some time.Too kind of you, really... <g>OK, so let's say that if I want to turn an inherited property to read-onlyIcan always override the setter with one that just raises an exception.Thatshould make both of us happy: no NULLs in the VTable, *and* I can break, crush and disintegrate my own code, be it perhaps for the mere fun of it. :-)you would have to (see above about making access less restrictive not more in sub classes).All of this, unfortunately, is going to remain in the field of puretheory,however, because nobody seems to have noticed this discussion, apart from the two of us.other are reading this, ....then,It should make room for what you declare. And what you declare, you must somewhere define.Consider a base class that declares a read-only property (no setter);two or more distinct derived classes extend the property to read-write. Woudn't we potentially end up having the address of the setter function at different points in the VTable? Or is that no problem because, being the property read-only in the base class, we cannot call the setter via a base-class reference anyway?if you have a reference to the base class you would have to cast (thus check it was an instance of derived) to write to the property. if the properties where in the vtbl this is no different from class base { void set_bla( T newval ); } class devr : base { T get_bla(); } you would not consider calling get_bla() on an instance of base, the getter and setters will be different entries anyway (unless you feel that it should be implemented as T & get_set( T & newval, boolean get ) !!! [I don't] but like methods, because D is a statically compiled lang the compiler is free to not put methods that are overridden into the vtbl, and I would assume it would do the same for getters/setter in the above case there are 2 derived classes that had setters but did not re-implement the getter then the getter would not need to be virtual, the setter might have to be, but only if one was derived again
Aug 08 2003
(This is also to reply to Ilya's message) "Mike Wynn" <mike.wynn l8night.co.uk> ha scritto nel messaggio news:bh0rbm$6nr$1 digitaldaemon.com...other are reading this, ....[Ilya specifically mentioned Walter] That's good, because properties are among the things D more badly needs to have implemented soon, so some brainstorming about them could help Walter get the job done _and_ have a life, a family, do some payed-for work, etc. :-) (That is, as long as there's someone like the two of you, ready to catch me and beat me when I get delirious :-) No, really, guys, I don't feel beaten at all - I think I've learnt something and am grateful to you). Ric
Aug 25 2003