|
Poor approach, cumbersome usage.
|
|
|
|
|
I really like the idea, code and article But I would add a note that the classes' size increases when using properties by at least 8 bytes per property. This may be important when using properties in classes in huge Arrays...
|
|
|
|
|
Achilleas:
I found your work fine and worth. I tried your code in MSVC 6.0 and it did fine, but when I tried it under VS 2003 it threw compilation errors as follows:
------ Build started: Project: CProperties, Configuration: Debug Win32 ------
Compiling...
main.cpp
f:\Programa\Pruebas\CProperties\property.h(398) : warning C4346: 'cpp::properties::_property1<c,t>::_property2<t3,t4>' : dependent name is not a type
prefix with 'typename' to indicate a type
f:\Programa\Pruebas\CProperties\property.h(487) : see reference to class template instantiation 'cpp::properties::property<c,t,a,s>' being compiled
f:\Programa\Pruebas\CProperties\property.h(398) : error C2146: syntax error : missing ';' before identifier 'base_class'
f:\Programa\Pruebas\CProperties\property.h(398) : error C2501: 'cpp::properties::property<c,t,a,s>::base_class' : missing storage-class or type specifiers
Build log was saved at "file://f:\Programa\Pruebas\CProperties\Debug\BuildLog.htm"
CProperties - 2 error(s), 1 warning(s)
---------------------- Done ----------------------
Build: 0 succeeded, 1 failed, 0 skipped
I didn't have the time to try to figure out the difference, but I thought it was worth letting you know, as you probably will be able to find the reason quite more quickly than me.
Thanks
Ernesto Savoretti
|
|
|
|
|
What you did is nice, but this could be easely done with just declaring private member variables and public Get/Put methods.
To my opinion, properties are needed for one could enumerate properties of some unknown object and access them whenever you want. Some kind of property subsystem would be nice to implement.
What do you think about it?
|
|
|
|
|
I modified the library so as that it allows for much easier usage! Previously, one had to declare class and data type along with the access and storage policy classes. Now it is not necessary. Declaring properties has become like this:
class Foo {
public:
property<Foo, int, read_write, interface> data1;
property<Foo, int, read_only, variable> data2;
property<Foo, int, write_only, interface> data2;
};
|
|
|
|
|
why not just make a com object? it is intended
for this requirement.
|
|
|
|
|
Because COM is a windows-only technology.
|
|
|
|
|
For VC++ (6+) you can also use:
__declspec( property( ... ) ) ...
e.g.
#define CK_PROP(t,x) \
__declspec( property( get=Get_##x, put=Put_##x ) ) t x; \
t Get_##x ( void ); \
void Put_##x ( t _##x );
#define CK_PROP_GETPUT(t,x,G,P) \
__declspec( property( get=G, put=P ) ) t x;
allow you to add a property to a class fairly painlessly:
class MyClass {
...
CK_PROP(int, myProp);
...
};
...cmk
Save the whales - collect the whole set
|
|
|
|
|
Hello,
I personally believe that this line of solutions will not help as much as you probably hope it will.
The trouble is that it requires (even) more typing then just writing the accessor methods and declaring the private member variable to persist the property. The good side is that it would be probably easier(given that the user knows already how "your" properties behave like) for whomever is using a class, which takes advantage of your properties. It is definitely a possibility to be considered, but I would like to throw in some comments. Feel free to fire back
1. class *property* is totally unnecessary. It adds no functionality and is basically a 1:1 proxy for the policy class (from which it inherits! but I will get to that in a short while). It also offers constructors which if you try to use will cause compiler errors.
What I suggest here is the following: 1. remove class property completely, and 2. define a few types instead. Something like this:
<code>
template <class C, class T>
struct property
{
typedef read_write<C,T,interface<C,T> > rwi;
typedef read_write<C,T,variable<C,T> > rwv;
typedef read_only<C,T,interface<C,T> > roi;
typedef <all the others ... >
}
</code>
Too bad C++ does not support templated templates But I guess this will do.
2. the inheritance of the policy class from the actual implementation class is unnecessary and increases the coupling. The classes *variable* and *interface* "feel" a little strange with no public part, don't they ? What would be probably better is to declare instances of those classes as member variables in the corresponding policy classes. After all the relationship between the policy classes and the implementation classes is IS_IMPLMENTED_IN_TERMS_OF and not IS_A.
3. The private constructors do not have to be defined. It is enough to declare them as private. Any attempt to use them would end up with a compiler error.
All these suggestions and comments do not add or remove any functionality. They are merely a better, safer design considerations.
I hope this is useful to you. Sorry if I have any mistakes, I have not actually compiled or tried to use your class.
Regards,
Petar
|
|
|
|
|
Hello and thanks for the comments.
I personally believe that this line of solutions will not help as much as you probably hope it will. The trouble is that it requires (even) more typing then just writing the accessor methods and declaring the private member variable to persist the property.
I don't think so, for the following reasons:
- in 99% of cases properties will be of read-write 'variable' type, so the actual code to write is
property[class, type] name; and
name(this, &class::name_changed) . The actual function to call when the property is changed it can be an already existing function. For example, in a GUI toolkit, most properties will be tied either to method 'redraw/update' or 'resizeFromContent'. - Using properties has the advantage of a non-bloated API. The user of the library only knows the property name. There is no need to remember naming conventions like 'get' or 'is' or 'has'.
- The header file becomes less bloated.
- It becomes easier to maintain documentation, as there exists one piece of documentation of the property. With methods, one needs to put the same information in the getter and setter method, or put the information in one of them and a link in the other.
- Documentation becomes easier to read. The docs are not bloated with tens of little functions that do nothing more than setting and getting data.
- It is easier to prototype a class, because the class can start with plain data members, and then data members can later be replaced with properties, without breaking the code.
- Intellisense works better and faster since a class has less members.
- A reflection library can be made that registers the properties in a class object.
class *property* is totally unnecessary.
Again, I disagree. Having the word 'property' on the source code makes the thing easier on the eye, especially after you come back to the code. For example:
class Foo {
public:
property[Foo, int] data1;
property[Foo, float] data2;
property[Foo, double] data3;
};
class Foo {
public:
read_write[Foo, int] data1;
read_write[Foo, float] data2;
read_write[Foo, double] data3;
};
It's clear that using 'property' has the advantage of showing immediately what the member is about. The term 'read_write' is not so obvious.
It also offers constructors which if you try to use will cause compiler errors.
That is a design decision: you can't construct the wrong property. Furthermore, the wrong constructor thing will not go away if the policy classes are used directly.
1. remove class property completely, and 2. define a few types instead. Something like this:
I don't think that what you propose is an improvement. Let's see it with an example:
class Foo {
public:
property[Foo, int] data1;
property[Foo, float] data2;
property[Foo, double] data3;
};
class Foo {
public:
property[Foo, int]::rwv data1;
property[Foo, float]::rwv data2;
property[Foo, double]::rwv data3;
};
It's clear to me that my approach is better. You type less, with the exact same functionality.
Too bad C++ does not support templated templates
Actually, C++ 98 does. It is MSVC 6.0 that does not. I can do the following with VC 7.0 and GCC:
class Foo {
public:
property[Foo, int, read_write, variable] data1;
};
Since that does not work for all C++ compilers, I may put there a macro:
#define PROPERTY(CLASS, TYPE, ACCESS, STORAGE)\
property[CLASS, TYPE, ACCESS[CLASS, TYPE, [STORAGE[CLASS, TYPE ] ] ]
The classes *variable* and *interface* "feel" a little strange with no public part, don't they ?
No more strange than abstract classes. In fact, with C++, declaring no public members is a legal way of doing abstract classes that also provide some implementation.
What would be probably better is to declare instances of those classes as member variables in the corresponding policy classes. After all the relationship between the policy classes and the implementation classes is IS_IMPLMENTED_IN_TERMS_OF and not IS_A.
Again, I disagree: a property IS_A variable or IS_An interface to a data member. A property IS_A read-write/read-only/write-only construct.
They are merely a better, safer design considerations.
Thanks a lot for the input. I think I have found a way to do what GCC/VC++ 7.0 does. Stay tuned!
|
|
|
|
|
Hello,
Let me see ..
Achilleas Margaritis wrote:
I personally believe that this line of solutions will not help as much as you probably hope it will. The trouble is that it requires (even) more typing then just writing the accessor methods and declaring the private member variable to persist the property.
I don't think so, for the following reasons:
in 99% of cases properties will be of read-write 'variable' type, so the actual code to write is property[class, type] name;
and name(this, &class::name_changed)
. The actual function to call when the property is changed it can be an already existing function. For example, in a GUI toolkit, most properties will be tied either to method 'redraw/update' or 'resizeFromContent'.
Using properties has the advantage of a non-bloated API. The user of the library only knows the property name. There is no need to remember naming conventions like 'get' or 'is' or 'has'.
The header file becomes less bloated.
It becomes easier to maintain documentation, as there exists one piece of documentation of the property. With methods, one needs to put the same information in the getter and setter method, or put the information in one of them and a link in the other.
Documentation becomes easier to read. The docs are not bloated with tens of little functions that do nothing more than setting and getting data.
It is easier to prototype a class, because the class can start with plain data members, and then data members can later be replaced with properties, without breaking the code.
Intellisense works better and faster since a class has less members.
A reflection library can be made that registers the properties in a class object.
These are all valid reasons. I still do not think that it will be good enough though. Again, I think the whole approach is doomed. I believe what is necessary is an extension to the language, something "native". Nothing wrong with your concrete library.
Achilleas Margaritis wrote:
class *property* is totally unnecessary.
Again, I disagree. Having the word 'property' on the source code makes the thing easier on the eye, especially after you come back to the code. For example:
class Foo {public: property[Foo, int] data1; property[Foo, float] data2; property[Foo, double] data3;};
class Foo {public: read_write[Foo, int] data1; read_write[Foo, float] data2; read_write[Foo, double] data3;};
It's clear that using 'property' has the advantage of showing immediately what the member is about. The term 'read_write' is not so obvious.
I have to agree property<foo, int=""> looks nice. How about declaring something that is not variable, or a variable which is not read_write ? It did not look that nice, did it ? I think you are persuaded that 99% of the users will be using the variable property and are not even considering what will happen when (not "if") you need a setter/getter type of property.
By saying the property is unnecessary I meant that the property class did not add or change anything on top of the policy class. That is why I do not see why you need it. And that is why I offered what I offered (the typedefs).
True
Achilleas Margaritis wrote:
That is a design decision: you can't construct the wrong property.
What do you mean *I cannot* ? If I *should not*, then you should not be offering it.
Achilleas Margaritis wrote:
Furthermore, the wrong constructor thing will not go away if the policy classes are used directly.
As far as I remember the policy classes did have only the correct constructors.
At this point I realized that you have totaly redisigned the internals of the library and basically there is no point discussing it any further. At least not what it was.
If you are interested about reasoning of the suggestions I made feel free to peek at the following books:
Exceptional C++, item 24: Uses and abuses of Inheritance
Effective C++, Item 40: Model "has-a" or "is-implemented-in-terms-of" through layering.
Effective C++, Item 44: Say what you mean; understand what you're saying.
Effective C++, Item 27: Explicitly disallow use of implicitly generated member functions you don't want
Regards,
Petar
|
|
|
|
|
I believe what is necessary is an extension to the language, something "native".
Of course, something native is much better, there is no need to say that. But I don't see it coming in the C++ world anytime soon.
I meant that the property class did not add or change anything on top of the policy class.
Syntactic sugar is important, otherwise we would all be programming in assembly.
If I *should not*, then you should not be offering it.
You're right, but C++ does not have constructor promotion from base to inheriting class. Therefore constructors need to be there in the derived class, too. It's a C++ limitation. Fortunately, the error is caught at compile-time.
As far as I remember the policy classes did have only the correct constructors.
Yes, but in either case (either in your way, or in mine), if the correct constructing call is not called, the compiler will complain. There is no actual difference.
Exceptional C++, item 24: Uses and abuses of Inheritance
Effective C++, Item 40: Model "has-a" or "is-implemented-in-terms-of" through layering.
Effective C++, Item 44: Say what you mean; understand what you're saying.
Effective C++, Item 27: Explicitly disallow use of implicitly generated member functions you don't want
Thanks a lot for the tips, but I have quite a big experience in C++ to know what I am doing (and support my view with concrete arguments). I may not remember all of C++ in one go, but I have used all its capabilities in one way or another. The problem is I have to work around the serious limitations of VC++ 6.0 and GCC, especially regarding templates.
|
|
|
|
|
I will start with the last part and then go back to the beginning.
Achilleas Margaritis wrote:
Thanks a lot for the tips, but I have quite a big experience in C++ to know what I am doing (and support my view with concrete arguments). I may not remember all of C++ in one go, but I have used all its capabilities in one way or another.
Gotta love the “I know and 've seen it all” attitude . Apparently you are quite confident regarding your C++ skills. Probably your vast C++ experience is the reason you completely restructured your implementation over a night. If you would have checked some of the books I referred to you would have probably realized they are not about using all or fancy C++ features. They are about using essential C++ features correctly. And these advices come from some of the best C++ gurus, who I am sure have no less experience then you do.
Besides all your "examples" were all rather conveniently centered around using only one out of the 6 combinations of types of properties you were offering. The so called 99% usage.
Achilleas Margaritis wrote:
If I *should not*, then you should not be offering it.
You're right, but C++ does not have constructor promotion from base to inheriting class. Therefore constructors need to be there in the derived class, too. It's a C++ limitation. Fortunately, the error is caught at compile-time.
This one is a serious hit on your C++ guru title. I guess you did not consider the possibility of having designed the library badly. It's gotta be the language wrong. Hint: Don't try suggesting to the C++ committee to "fix" this "limitation". They will not buy it!
As fortunate as it is that the compiler is catching these inappropriate attempts, the developer should not be event thinking about making them. And by looking at the header file and checking the IntelliSense he may not "sense" right away your vision. Not until the compiler "slaps" him.
Achilleas Margaritis wrote:
As far as I remember the policy classes did have only the correct constructors.
Yes, but in either case (either in your way, or in mine), if the correct constructing call is not called, the compiler will complain. There is no actual difference.
I am all confused here ... but again I do not remember exactly what was that you wrote originally because you changed it completely.
Achilleas Margaritis wrote:
I meant that the property class did not add or change anything on top of the policy class.
Syntactic sugar is important, otherwise we would all be programming in assembly.
Your understanding of "syntactic sugar" is quite strange. A typedef can be considered syntactic sugar. std::string is syntactic sugar for basic_string<char>. Creating a class deriving from another one is most definitely not syntactic sugar. Syntactic sugar was what I offered in my original post: to create typedefs for the 6 different combinations of classes.
I have to admit by looking at your code you definitely have C++ skills. Kudos for that. But you really have to work on the attitude.
Petar
|
|
|
|
|
Petar K. Shomov wrote:
Gotta love the “I know and 've seen it all” attitude
It goes hand-in-hand with the 'cool library, but it's all wrong, and your C++ skills suck, and mine's rock' attitude.
Petar K. Shomov wrote:
Probably your vast C++ experience is the reason you completely restructured your implementation over a night.
You are talking as if you've never changed any code. I knew what I wanted to achieve, I just haven't thought about how to achieve it on MSVC++ 6.0.
Petar K. Shomov wrote:
If you would have checked some of the books I referred to you would have probably realized they are not about using all or fancy C++ features.
But these books refer to various C++ features necessary for following the principles they mention.
Petar K. Shomov wrote:
And these advices come from some of the best C++ gurus, who I am sure have no less experience then you do.
I see no need to read 'books' when I know 100% of what I am doing (and have done before, numerous times).
Petar K. Shomov wrote:
Besides all your "examples" were all rather conveniently centered around using only one out of the 6 combinations of types of properties you were offering. The so called 99% usage.
I have presented one other example: using a read-write interface property. Other examples are reduntant, because all you have to do is replace 'read_write' with 'read_only/write_only' and 'variable' with 'interface'.
Petar K. Shomov wrote:
This one is a serious hit on your C++ guru title. I guess you did not consider the possibility of having designed the library badly. It's gotta be the language wrong.
Well, does the language offer the possibility of inheriting from a class provided as a template parameter, then have the same constructors as the base class automatically? it does not. So I see no fault at the design, especially when usage of wrong constructors ends up in a compile-time error. I also avoid your silly design with typedefs inside a struct which would make the code look ugly.
Petar K. Shomov wrote:
Hint: Don't try suggesting to the C++ committee to "fix" this "limitation". They will not buy it!
Hint: if they are as sm@rtass as you, they will certainly not. Last time I exchanged e-mails with Bjarne Stroustrup though, he did not seem to be like that.
Petar K. Shomov wrote:
the developer should not be event thinking about making them.
How come the developer should be thinking about making them, if the compiler does not allow it? he maybe try once or twice, fail miserably, then know what is going on and never think about trying to call the wrong constructor again. It is more important that the code looks nice in the long run, for maintenance reasons.
Petar K. Shomov wrote:
And by looking at the header file and checking the IntelliSense he may not "sense" right away your vision
So? he may not sense it right away, but he should read the docs nevertheless and not the header file. And the docs explicitely say about how to use each constructor. You're right, it's important in the first 60 seconds though...I guess it is that how long it would take one to completely figure out how it works.
Petar K. Shomov wrote:
I am all confused here ... but again I do not remember exactly what was that you wrote originally because you changed it completely.
If you have checked the new code, you would see that, again, the property class has constructors for all kinds of properties. What I have changed is the way the property is declared: it uses tags and specialization to select the appropriate implementation instead of providing the implementation directly as template parameters.
Here is what went on previously and what goes on now: the property class is a proxy class: it is provided for selecting the proper property implementation. It inherits from that implementation, and so it provides all the constructors for each possible implementation (out of 6 possible).
The constructors are necessary because I want to enforce that property callbacks and property default values are only given once; therefore, they are specified in constructors.
The property class, as a proxy, needs to provide all the constructors of the base class, which is selected by the template parameters. Since C++ does not have 'constructor promotion', there is no other way.
The reason for using the proxy class and not the classes the proxy clas may possibly inherit from is purely syntactic sugar: there is only one class for programmers to know, parameterized at compile time with policy tags. It's the same tactic used with boost::smart_ptr and other high-quality libraries. I could have had 'read_write_variable_property<c, t="">', 'read_write_interface_property<c, t="">', 'read_only_variable_property<c, t="">' etc but it would look and feel UGLY.
Petar K. Shomov wrote:
Your understanding of "syntactic sugar" is quite strange.
Not at all. Syntactic sugar is when the code is made prettier to look at, easier to write for, and consequently easier to document and maintain.
Petar K. Shomov wrote:
A typedef can be considered syntactic sugar.
Not in every case. For example, if you have 6 different typedefs as a result of a combination of 2x3 options, it's is bad to use typedefs. It is better to use tags and selectors.
Petar K. Shomov wrote:
Creating a class deriving from another one is most definitely not syntactic sugar. Syntactic sugar was what I offered in my original post: to create typedefs for the 6 different combinations of classes.
He he I replied to the comment above before I read it. What you offered was not syntactic sugar, it was syntactic hell: you introduced 6 new words for the programmer to remember, plus the 'property' one. My solution has 5 words.
Furthermore, your identifiers where ugly: rwi, roi, rwv etc. What the heck are those? it's not clear from when looking immediately at it.
Finally, there is a big problem with your solution: imagine if one more option was introduced! Let's say that there is a new property storage type called 'remote' which sends a message across the network each time the property is changed. Then your naming (rwi, roi, rwv) whould be invalid, and you would have to provide 9 typedefs, where I would only have to provide one more keyword!
Petar K. Shomov wrote:
I have to admit by looking at your code you definitely have C++ skills.
Thanks.
Petar K. Shomov wrote:
But you really have to work on the attitude.
No, it was your attitude that was rude. You came on to me, saying that all I have done is wrong, and I would probably should educate myself, without giving any concrete argument on why I should do so or why my approach is wrong.
|
|
|
|
|
First of all: Congratulations on winning the Eurovision song contest. Elena is great! (I assume you are a greek or with similar origins).
Now with the other business...
Achilleas Margaritis wrote:
It goes hand-in-hand with the 'cool library, but it's all wrong, and your C++ skills suck, and mine's rock' attitude.
I did not say the library is wrong, I said it can be bettered.
I explicitly expressed my opinion about your C++ skills, I do not know why you say "...and your C++ skills suck ..." ?!?
Achilleas Margaritis wrote:
You are talking as if you've never changed any code. I knew what I wanted to achieve, I just haven't thought about how to achieve it on MSVC++ 6.0.
Change is one thing, rewrite it completely - another. Yes, I have changed and rewritten code. And that is why I always consider the criticism I get. May be they do have a point after all ...
Achilleas Margaritis wrote:
But these books refer to various C++ features necessary for following the principles they mention.
Of course they do, after all they are books about C++. But the books and especially the chapters are about features like inheritance and class constructors. Believe me, I was not trying to introduce you to these concepts. As I said the books are about using these features correctly.
Achilleas Margaritis wrote:
I see no need to read 'books' when I know 100% of what I am doing (and have done before, numerous times).
It is all up to you.
Achilleas Margaritis wrote:
I have presented one other example: using a read-write interface property. Other examples are reduntant, because all you have to do is replace 'read_write' with 'read_only/write_only' and 'variable' with 'interface'.
Yes, that is my favorite one. Let's look at it again, after all I think it is a scene to remember:
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
and then you have the nerve to come and say something like this ...
Achilleas Margaritis wrote:
So I see no fault at the design, especially when usage of wrong constructors ends up in a compile-time error. I also avoid your silly design with typedefs inside a struct which would make the code look ugly.
so lets look at that again
mine:
property<Foo, int>::rwi data1;
yours:
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
By the way, rwi stands for Read-Write Interface. I agree the typedef-in-a-struct hack is not the most beautiful thing around, but it is portable and the closest I could think of to express what would be better expressed as:
Non-standard C++ follows
template<class C, class T> typedef read_write<C,T,interface<C,T> > property_rwi;
Achilleas Margaritis wrote:
So I see no fault at the design, especially when usage of wrong constructors ends up in a compile-time error.
I think what you are actually trying to express here is the so called factory pattern but the approach is incorrect. I am kind of giving up on recommending you books which are considered classics by most software developers, so I will directly offer you to google for "factory pattern".
Achilleas Margaritis wrote:
Hint: if they are as sm@rtass as you, they will certainly not. Last time I exchanged e-mails with Bjarne Stroustrup though, he did not seem to be like that.
What a minute, you exchange e-mails with Bjarne Stroustrup ?!? Why didn't you say so from the very beginning ? I am so sorry, I am taking it all back, ... or not .
I am sure Bjarne is a nice guy, but may be in your next e-mail exchange with him you can mention our little conflict of ideas, and ask him what he thinks. By the way, one of the books I offered you is from Herb Sutter who is currently the chair of the ISO C++ standards committee. May be this way the book will be more appealing to you .
Achilleas Margaritis wrote:
How come the developer should be thinking about making them, if the compiler does not allow it? he maybe try once or twice, fail miserably, then know what is going on and never think about trying to call the wrong constructor again. It is more important that the code looks nice in the long run, for maintenance reasons.
Because before the developer tries to compile the code he will actually write it. He will check the intelliSense, look at the headers, may be even bother with the documentation. He will use one of the constructors and if he gets slapped by the compiler I am not sure you will get a second chance (we all know how compiler errors concerning templates look like - long, cryptic, etc.). Yes, I know that sometimes this is the only option, but I am saying that in this case it was totally uncalled for.
Regarding the "nice" part, the only nice part you mostly mentioned was relying on default paramters for the template so the user had absolutely idea what kind of property he had - read-only, read-write or write-only.
Achilleas Margaritis wrote:
The reason for using the proxy class and not the classes the proxy clas may possibly inherit from is purely syntactic sugar: there is only one class for programmers to know, parameterized at compile time with policy tags. It's the same tactic used with boost::smart_ptr and other high-quality libraries. I could have had 'read_write_variable_property', 'read_write_interface_property', 'read_only_variable_property' etc but it would look and feel UGLY
Actually the programmers should know about the property class and the access policy types and property storage mechanisms. Looking at your latest example reveals that:
property<MyClass, int, read_write, interface> data;
so the bad and ugly code would look like:
read_write_interface_property<MyClass, int> data;
Are still sure your point is very sound? Once again the property class brings unnecessary constructor and nothing more. Trouble, that's what it is.
Achilleas Margaritis wrote:
Not at all. Syntactic sugar is when the code is made prettier to look at, easier to write for, and consequently easier to document and maintain.
Agreed. What I was trying to say is that it changes the design. It is not only syntactic sugar. Regarding the "prettier to look at, easier to write for" part, I will have to be sm@rtass once again and say that if real sugar would be like your syntactic sugar
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
we would have had a lot less diabetis . Sorry, could not keep it.
Achilleas Margaritis wrote:
Not in every case. For example, if you have 6 different typedefs as a result of a combination of 2x3 options, it's is bad to use typedefs. It is better to use tags and selectors.
There is no such C++ constructs and I am not completely sure what you mean by "tag" and "selector", can you please clerify this for me and may be give an example in the context. I would appreciate it.
Achilleas Margaritis wrote:
He he I replied to the comment above before I read it. What you offered was not syntactic sugar, it was syntactic hell: you introduced 6 new words for the programmer to remember, plus the 'property' one. My solution has 5 words.
Ahhh, talking about syntactic hell, let me see ... this gives us one more opportunity to gaze at the beauty and conciseness of the one example I most admire:
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
I am sure all the keyboard producers are behind you on this one . I know, I know ... being sm@rtass again.
Achilleas Margaritis wrote:
Furthermore, your identifiers where ugly: rwi, roi, rwv etc. What the heck are those? it's not clear from when looking immediately at it.
Every time you mention clarity of code I will be reminding you about your own
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
Achilleas Margaritis wrote:
Finally, there is a big problem with your solution: imagine if one more option was introduced! Let's say that there is a new property storage type called 'remote' which sends a message across the network each time the property is changed. Then your naming (rwi, roi, rwv) would be invalid, and you would have to provide 9 typedefs, where I would only have to provide one more keyword!
A few things here:
1. Apparently the naming convention I was using is not as obscure as you were pretending after all. May be you were just bitter .
2. No, the naming scheme would still be ok. This may come as a surprise to you but the new types would be rwr, ror, wor. Let me make this clear to you. I was not imposing my naming scheme or the exact way you want to hack around this. I was trying to offer you a direction. I was saying that using the proxy class was incorrect way to go.
3. Is writing 9 typedefs some serious problem ? If they are easy to remember, meaningful and shorter to write then I am sure they would be worth the effort. I wouldn't have minded if you would have changed the names based on your experience you so proudly wave. I guess this is not very scalable solution but these typedefs are mere shortcuts, syntactic sugar. If the user wants he can write the full thing or create his own syntactic sugar. And if you make a solution that is so complex that would be unfeasible to make all the typedefs, I am pretty sure you would have problems on your own also.
By the way this is an interesting point you are bringing up. How do you see you current implementation scale in the situation you are referring? I would have to write 3 new typedefs. You, on the other hand, would have to write 6 template specializations - 3 for Visual C++ and 3 for the others. You have to practice what you preach .
Achilleas Margaritis wrote:
No, it was your attitude that was rude. You came on to me, saying that all I have done is wrong, and I would probably should educate myself, without giving any concrete argument on why I should do so or why my approach is wrong.
I think all you expected from the guys that looked at your class to be stunned with your exceptional C++ skills. I totally stand by all the points I made in my first post here. May be I was not clear enough when I used some terminology like IS_A and IS_IMPLEMENTED_IN_TERMS_OF so I will take this chance and apologize if that is the case. I see that you are not inclined in reading books about C++ so I have made this last effort and found a web site where the author of the book explains these things further. I hope you will consider the possibility to click on this[^] link and may be he will be more successful in getting your interest.
I spent too long time discussing this issue. I really hope you get something out of this for yourself, so at least all this typing (and trying too hard to be sm@rtass) was not a waste.
Regards,
Petar
|
|
|
|
|
Petar K. Shomov wrote:
First of all: Congratulations on winning the Eurovision song contest. Elena is great! (I assume you are a greek or with similar origins).
Thanks, but who cares? I think the Eurovision contest was given too much attention.
Petar K. Shomov wrote:
I do not know why you say "...and your C++ skills suck ..." ?!?
Because it is that what you've said. Don't try to wrap it up in a few nice words.
Petar K. Shomov wrote:
Change is one thing, rewrite it completely - another.
It's not my fault that VC++ 6.0 sucks that badly when it comes to templates.
Anyway, changing a piece of code, even completely, is not a criterion of one's worth, as you implied. It's totally irrelevant.
Petar K. Shomov wrote:
But the books and especially the chapters are about features like inheritance and class constructors.
Syntactic sugar matters more than 'inheritance and constructors'.
Petar K. Shomov wrote:
It is all up to you.
Of course(doh!!!).
Petar K. Shomov wrote:
so lets look at that again
mine:
property<Foo, int>::rwi data1;
yours:
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
By the way, rwi stands for Read-Write Interface. I agree the typedef-in-a-struct hack is not the most beautiful thing around, but it is portable
What I wanted to do is:
property<MyClass, int, read_write, interface> data;
I did it, after having thought of a trick to get around VC++ 6.0 limitations.
And what if I wanted this?
property<MyClass, int, read_write, other_way> data;
Then your solution would not work.
Petar K. Shomov wrote:
I think what you are actually trying to express here is the so called factory pattern but the approach is incorrect. I am kind of giving up on recommending you books which are considered classics by most software developers, so I will directly offer you to google for "factory pattern".
Bullshit, and your "teacher" style gets on my nerves! I am not trying to express the factory pattern, I am trying to use the policy pattern!
Petar K. Shomov wrote:
What a minute, you exchange e-mails with Bjarne Stroustrup ?!? Why didn't you say so from the very beginning ? I am so sorry, I am taking it all back, ... or not .
He was much more polite that you. Your manners are ...lamentable, to say the least.
Petar K. Shomov wrote:
am sure Bjarne is a nice guy, but may be in your next e-mail exchange with him you can mention our little conflict of ideas, and ask him what he thinks. By the way, one of the books I offered you is from Herb Sutter who is currently the chair of the ISO C++ standards committee. May be this way the book will be more appealing to you
I was offering an example of people that are real gurus and much less smarta$$ than you. If Herb Sutter is a nice guy, I am all for him.
Petar K. Shomov wrote:
Because before the developer tries to compile the code he will actually write it. He will check the intelliSense, look at the headers, may be even bother with the documentation. He will use one of the constructors and if he gets slapped by the compiler I am not sure you will get a second chance
But in order to write it, he would have to look at the documentation!!! otherwise, what he will write? so it's documentation first, not the other way around.
Oh now I got it! you have mystical powers and you can grab a library and start coding with it immediately without looking at the docs first...;)
Petar K. Shomov wrote:
(we all know how compiler errors concerning templates look like - long, cryptic, etc.). Yes, I know that sometimes this is the only option, but I am saying that in this case it was totally uncalled for.
Actually, in both your case and my case, the compiler error messages are very similar, and therefore similarly cryptic.
I personally have not ever had a problem with error messages though, because I simply ignore the template parameters (which are those that cause the cryptic problem), and read the rest of the text.
Petar K. Shomov wrote:
Regarding the "nice" part, the only nice part you mostly mentioned was relying on default paramters for the template so the user had absolutely idea what kind of property he had - read-only, read-write or write-only.
...as the docs say, the default is 'read/write'. What's the most common case? it's read/write. Right, you say that the most common case that 99% of times will be used is "having no idea".
So, by your principles, all identifiers in a program should be patched with their types, eh?
Hungarian notation is ...so bad...!!! I am sure your books tell you that.
Petar K. Shomov wrote:
Actually the programmers should know about the property class and the access policy types and property storage mechanisms. Looking at your latest example reveals that:
property<MyClass, int, read_write, interface> data;
so the bad and ugly code would look like:
read_write_interface_property<MyClass, int> data;
Man, what are you saying? let me tell you that again, and maybe you will understand it.
Here are the things one should know:
1) class property
2) class read_write
3) class read_only
4) class write_only
5) class variable
6) class interface
Let's see, with your method, what the programmer should know:
1) class property
2) class property<C, T>::rwv
3) class property<C, T>::rwi
4) class property<C, T>::rov
5) class property<C, T>::roi
6) class property<C, T>::wov
7) class property<C, T>::woi
So, in your case, the programmer has to know one more thing!
Furthermore, my method is vastly cleaner than yours.
And you conventiently sidestep the fact that, if one more policy is added to the library, your method sucks badly.
Petar K. Shomov wrote:
Are still sure your point is very sound? Once again the property class brings unnecessary constructor and nothing more. Trouble, that's what it is.
First of all, what we discuss above has nothing to do with the necessity of constructors.
Secondly, there is no such thing as an 'unneccessary constructor'. The constructors are needed, because they can not be avoided while the syntax I want to offer.
Petar K. Shomov wrote:
What I was trying to say is that it changes the design. It is not only syntactic sugar.
So what?
Petar K. Shomov wrote:
There is no such C++ constructs and I am not completely sure what you mean by "tag" and "selector", can you please clerify this for me and may be give an example in the context.
"Tags used as selectors" means classes that can not be instantiated and used as strong types for doing partial or full template specialization.
Petar K. Shomov wrote:
Ahhh, talking about syntactic hell, let me see ... this gives us one more opportunity to gaze at the beauty and conciseness of the one example I most admire:
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
Well, let's compare the 99% case:
mine:
property<MyClass, int> data;
yours:
property<MyClass, int>::rwv data;
Which one looks better?
And I finally did what I wanted to achieve in the first place (but did not occur to me right away):
property<MyClass, int, read_write, interface> data;
Which still looks much better than your offer.
Petar K. Shomov wrote:
I am sure all the keyboard producers are behind you on this one . I know, I know ... being sm@rtass again.
Since when having to type a little more is bad? are you a fan of APL?;P
Oh now I get it...your favorite competition is the obfuscated C contest! that explains all!
Petar K. Shomov wrote:
Every time you mention clarity of code I will be reminding you about your own
property<MyClass, int, read_write<MyClass, int, interface<MyClass, int> > > data;
Thanks. You saved me from typing that my solution is so much clearer:
mine:
property<MyClass, int> data;
property<MyClass, int, read_write, interface> data;
yours:
property<MyClass, int>::rwv data;
property<MyClass, int>::rwi data;
Petar K. Shomov wrote:
Apparently the naming convention I was using is not as obscure as you were pretending after all. May be you were just bitter
Another "argument" of yours with no basis whatsoever. Actually, I am bitter about the level of "smarta$$ness" of humanity. If everyone's like you, then we've had it.
Petar K. Shomov wrote:
No, the naming scheme would still be ok. This may come as a surprise to you but the new types would be rwr, ror, wor. Let me make this clear to you. I was not imposing my naming scheme or the exact way you want to hack around this. I was trying to offer you a direction. I was saying that using the proxy class was incorrect way to go.
Bullshit: ror, wor and every other abbreviation you might imagine is bad, bad, bad, especially when there are lots of them.
Petar K. Shomov wrote:
I was trying to offer you a direction.
You have to understand my direction first. Obviously, you did not.
Petar K. Shomov wrote:
I was saying that using the proxy class was incorrect way to go.
But you did not present a single argument about why.
Petar K. Shomov wrote:
Is writing 9 typedefs some serious problem ?
It depends on the context. Without context, it sounds innocent. But in this context, it's bad.
Petar K. Shomov wrote:
If they are easy to remember, meaningful and shorter to write then I am sure they would be worth the effort.
Let's see:
rwv
rwi
rwr
rov
roi
ror
wov
woi
wor
It's very very bad. Compare it with:
read_write
read_only
write_only
variable
interface
remote
Let's suppose we have one more type, the 'debug' storage, which actually prints a debug message each time the property is changed. Then, with your way, we have:
rwv
rwi
rwr
rwd
rov
roi
ror
rod
wov
woi
wor
wod
With my way:
read_write
read_only
write_only
variable
interface
remote
debug
I think that my way is vastly superior in readability.
Let's say now that we would like to do a compicated thing: wrap storage implementation around the debug class (so we can combine 'debug' capabilities with 'variable', 'interface' and 'remote'.
Your way:
rwv
rwi
rwr
rov
roi
ror
wov
woi
wor
rwvd
rwid
rwrd
rovd
roid
rord
wovd
woid
word
My way:
read_write
read_only
write_only
variable
interface
remote
debug<variable>
debug<interface>
debug<remote>
Petar K. Shomov wrote:
I would have to write 3 new typedefs. You, on the other hand, would have to write 6 template specializations
You are a cheater: how are you supposed to write the typedefs, without the implementations? so you would have too to write the new implementations.
Petar K. Shomov wrote:
You, on the other hand, would have to write 6 template specializations - 3 for Visual C++ and 3 for the others. You have to practice what you preach
There are ways around that. I can actually write the implementation once and share it with VC++ and others.
But you are still a cheater: the problem you mention (having to maintain too versions, because the compilers are stupid) has nothing to do with syntactic sugar.
Petar K. Shomov wrote:
I think all you expected from the guys that looked at your class to be stunned with your exceptional C++ skills.
How did you reach that ridiculus conclusion? just because I counter-argued your "arguments"?
Petar K. Shomov wrote:
I totally stand by all the points I made in my first post here.
Yeah, right. Every time a guy is cornered and can't defend his initial arguments, all I get is "I stand by all the points." Who cares? you do that. It's not my fault if you can't support your claims.
Petar K. Shomov wrote:
I see that you are not inclined in reading books about C++
You don't know what I have read. How do you know what I have read and what not?
Let me give you an advice: it's not good to make conclusions about others with your own perception.
Petar K. Shomov wrote:
I hope you will consider the possibility to click on this
I read artima forums quite often. But I stand away from too much theory. Endlessly speculating on IS-A and HAS-A is useless: let me see those people that talk about IS-A and HAS-A relationships implement properties, and then we can talk.
Here is hint for you: I chose inheritance because it makes it easier for me: I don't have to write wrapper methods for accessing the member variables.
I did this:
class Foo {
public:
int data();
};
class Bar : public Foo {
public:
};
instead of this:
class Foo {
public:
int data();
};
class Bar {
public:
int data() { return foo.data(); }
private:
Foo foo;
};
Petar K. Shomov wrote:
o at least all this typing (and trying too hard to be sm@rtass) was not a waste.
at least some self-awareness.
|
|
|
|
|
Guys,
Petar: Stop it. Don't bother. He does not get it.
Achilleas: first of all I really do think your attitude was the rude one.
You placed your article on CP and expect people to make comments.
At least that's why there is the "New Thread" button at the end of each article.
When one smart guy places one comment about "it might be better like this"
Petar K. Shomov wrote:
I personally believe that this line of solutions will not help as much as you probably hope it will. [...] All these suggestions and comments do not add or remove any functionality. They are merely a better, safer design considerations.
you start (I would say quite aggressively) explaining that he is wrong.
So... mate.. I really think you have an attitude problem.
Secondly, your read_write,read_only,write_only,variable[...] against his rwv,rwi,rwr,rov,roi has no point. It's a matter of coding preference. It would be trivial to rename his "rwv" to "read_write" and have the same keywords as you do (if you don't have copyright already, offcourse).
The idea of CP is of people helping people. Neither of us is so smart that needs no help.
So your I see no need to read 'books' when I know 100% of what I am doing it's quite aggressive. We all know you know everything. You don't have to prove it in every other sentence.
If I would be you, I would apologize for the rude comments (that you did) and maybe update your article to show "the other side of the story".
Your "can't defend his initial arguments" clearly shows you don't care about criticism and making things better, you care only about being right. And that might not be part of CP's policy.
I would prefer Petar's approach for 2 reasons:
1. I like templates.
2. After typing "property[Foo, int]:: " I get intellisense for the coming "rwi" or "read_write" (as I would rename it).
After "property[Foo, int, " I get not intellisense to fill the "read_write", "interface".
There might be more reasons. He presented an alternative.. that you really don't want to accept and consider it also very bad.
All I can say it: change your attitude.
Tutu.
|
|
|
|
|
Achilleas keep up the good work.
Don't bother answering these idiots.
|
|
|
|
|
Thanks, but it is important one can back up his/her design decisions. I built my lib in a specific way not because it just occurred to me out of the blue, but under careful considerations of the language, documentation issues, coding issues that come up in everyday experience.
|
|
|
|
|
Tutu wrote:
He does not get it.
It is Petar that does not get it.
Tutu wrote:
first of all I really do think your attitude was the rude one.
Your opinion is respected, but I think otherwise.
Tutu wrote:
You placed your article on CP and expect people to make comments.
Yes, comments that are based on some arguments. The comments of Petar was "your code sucks 100%, here is the right way", while he has not understood the reasons behind the design. I wouldn't have a problem with that, if the guy did not insist and not presented books for me to read! It was like saying "you are lame, please read these books and then come back".
Tutu wrote:
you start (I would say quite aggressively) explaining that he is wrong.
Quite aggressively? not at all? where is the aggressiveness? show me, please!!!
Tutu wrote:
So... mate.. I really think you have an attitude problem.
I consider it much more rude to give "advice" without first understanding what's going on. At least the guy could have asked: "why do you do such and such?" before giving "advice".
Tutu wrote:
It's a matter of coding preference.
No, it's not. It's a matter of design. Let me repeat my argument, because it seems you have not understood it either:
The usage of 'read_write', 'read_only', 'write_only', 'variable', 'interface' as selectors of policy in a template class is a better way than having typedefs of all the cases, for the following reasons:
- It allows for less typing, since the user would not have to type the property kind in 99% of cases (not even bother with intellisense).
- It makes intellisense faster.
- It is more intuitive to combine things together than choosing from a list of predefined configurations. The mental model is better: the programmer selects behaviours by mixing and matching, instead of selecting from a ready-made recipie.
- It is easier to extend for the API user, since the user will only need to know new selector keywords.
- Extending the library with new keywords will not force old code to be recompiled. It's better for backwards compatibility.
Where are your arguments? Don't reject what you don't understand.
Tutu wrote:
(if you don't have copyright already, offcourse)
'Light' irony like yours makes me angry: it is the behaviour of cowards, of people that can't stand up and say their opinion.
Tutu wrote:
Neither of us is so smart that needs no help.
Help, yes. But help should come with arguments. Why do I need to do what Petar has said? there is no single argument that persuaded me he is right.
Tutu wrote:
So your I see no need to read 'books' when I know 100% of what I am doing it's quite aggressive
So why do I need to read something, when I know it 100%? the need to read about it means I don't know it 100%. In the field of C++ properties, I have done similar libraries for over 6 years now, so I know all problems associated with it. But then I accepted the 'challenge' and read what Petar said and counter-claimed all of his arguments.
And in a previous library, I have done what Petar suggested, and it was ugly.
Furthermore, my design comes from reading the boost development mailing list. Most boost developers are in favor of policy-based design, which has been used extensively in boost.
Tutu wrote:
You don't have to prove it in every other sentence.
I did not say what I said to prove I know everything. I said it to prove I know everything regarding C++ properties design. Notice that I place my 'everything' on a specific domain! What I feel is an insult from your part is that you fail to understand this little detail.
Tutu wrote:
If I would be you
You're not. Let's keep it real.
Tutu wrote:
I would apologize for the rude comments (that you did)
So me one rude comment that was not a response to a Petar's rude comment, and I will apologise. One!
Tutu wrote:
and maybe update your article to show "the other side of the story"
There is no other side of the story. I have proved, again and again, that Petar's design is wrong.
Tutu wrote:
Your "can't defend his initial arguments" clearly shows you don't care about criticism and making things better, you care only about being right.
If I did not care about criticism, I would not respond. Have you got any counter-arguments? you don't. Does Petar? nope. Do I have counter-arguments? I surely do! so stop whining and accept the facts.
Tutu wrote:
I like templates.
But my solution is all about templates, too.
Tutu wrote:
After typing "property[Foo, int]::" I get intellisense for the coming "rwi" or "read_write" (as I would rename it).
With my solution, you get intellisense, too. When you type 'r..', you can select from 'read_write' and 'read_only'.
With Petar's solution, one that writes properties would always have to select the proper typedef'd type.
With my solution, one does not need to select the proper property kind, because it is there in the default arguments of the template.
My solution also has other advantages, mentioned above.
Tutu wrote:
After "property[Foo, int," I get not intellisense to fill the "read_write", "interface".
My IDE (VC++) shows template parameters when I type a template type. Then, when I press 'r', 'read_write' and 'read_only' comes up.
And it is really not a good practice to code around one's IDE intellisense capabilities instead of what makes the language better.
Tutu wrote:
There might be more reasons. He presented an alternative.. that you really don't want to accept and consider it also very bad.
He presented an alternative with insufficient arguments to back it up. He also implied that I don't know what I am doing, therefore I need to educate myself.
Tutu wrote:
All I can say it: change your attitude.
All I can say is all you should change attitudes:
- you should be more honest, more sincere. If you think my design sucks, tell me that "your design sucks". Don't wrap it up in a few "intelligent" wordisms.
- learn how to debate. Debating means presenting arguments. You don't have arguments? shut the f*** up then. I know I do so when I don't have arguments.
By the way, I don't really want to get in a teaching mood, but you guys have way crossed the line, up to the fact of telling another guy to change his attitude! you should learn what democracy is: to accept the others as they are (amongst other things...).
|
|
|
|
|
maybe u dont get it.
id have to side here with Achilleas...
iv read the whole thing out, and i must say, Achilleas might not have the very best of attitude, but his responces where called for. i dont know about u, but when u do a lot of work in something, only to be told by someone without any valid arguments that ur design is wrong, i would be pissed.
see, Petar presented an alternate. im sure the alternate would be better in some cases than the original, but its ur attitude Petar thats disgusting. ur pushing something without facts. all your arguments are half baked:
--> u claim expanding ur method is simpler than expanding Achilleas, which in fact is more work, not only do u need to write the implementations which Achilleas, u have to write the typdefs on top of it
--> u never explained ur implemtaion's pros and cons, while Achilleas managed to explain his pros and cons in terms of ur implemetaion
and Petar, dont be so confused with the statement "my implementation is soo good, urs sucks, learn to program" Achilleas expresses (in other words but it was something like that). when u push something on someone thats sooo similar, but say ur way is right and the otheway has major flaws(which u have yet to point out), it leads to those fealings.
sure ur implementation is parallel, but where it failed is that its not extendable... say if u wanted to add "remote" or "debug", sure u could get it to work if u added typedefs, but what if the client wanted to add one of these classes... do u really thing that a client would be willing to write typedefs for each case when he could us a simple template to begin with which are as readable? not more or less, just different?
but saying this, Achilleas, improve ur attitude... ur mistake is in ur attitude... not saying it was uncalled for in some cases, most of the time u handled him well, but when u present urself as allknowing, it fuels people's want to find ur flaw, and gives people like this who cant argure ammo to throw back and annoy you with. so as much as id call u the winner of this debate, ur sure didnt get a perfect victory.
|
|
|
|
|
Good article
|
|
|
|
|