property in C++

J

James Kanze

On 27/07/10 16:51, theambient wrote:

[...]
You can do without having to store any extra data in you property
objects. Because object's members are stored at a constant offset from
the beginning of an object you can calculate object's address from the
property address (this) using offsetof() macro from <stddef.h>. (beware,
it does not work with virtual base classes).

Beware, offsetof() doesn't work for anything but POD-structs.
As soon as the class has a non-trivial constructor, offsetof is
undefined behavior. (And IIRC, at least one compiler will
refuse to compile the code.)
 
J

James Kanze

On 28.07.2010 13:12, Maxim Yegorushkin wrote:

[...]
a few more words about setters and getters. Is it normal to
use names like
void property( const T & val ); // setter
T const & property(); // getter
or better with prefixes set_ and get_ which is in my opinion a
little bit ugly?

It's a question of style. My own preference is to use just the
names when it's conceptually a property (a data member
accessible from outside the class), and get and set otherwise.
 
K

Kirit Sælensminde

a few more words about setters and getters. Is it normal to use names like
void property( const T & val ); // setter
T const & property(); // getter

or better with prefixes set_ and get_ which is in my opinion a little
bit ugly?

Personally I think the names need to be the same as it allows you to
do things you couldn't otherwise (and I also find the user of 'get' or
'set' in the names unimaginably ugly). I wrote a long explanation of
why I think the names should be like that here http://bit.ly/18n5F


Kirit
 
J

joe

James said:
Jorgen Grahn wrote:
[...]
straustrup's third special edition followed this standard, pardon,
Standard :)
It's Stroustrup, with an 'o' and a capital 'S'. (I'm not normally
that pedantic, but you misspelled it twice.)
Give him a break: English does not seem to be his primary language.

Spelling a person's name correctly has nothing to do with
whether he's English speaking or not. It's more a question of
politeness.

I had a feeling someone was going to get all bent out of shape when I
posted that! (Especially since it was the God of C++).
 
Ö

Öö Tiib

Personally I think the names need to be the same as it allows you to
do things you couldn't otherwise (and I also find the user of 'get' or
'set' in the names unimaginably ugly).

How so unimaginably? Just imagine std::vector with getIsEmpty(),
getBegin(), getEnd(), getCapacity(), setCapacity(), getSize() and
setSize(). It is helper to anyone who can not imagine the ugliness of
that "get", "set" interface. ;-)

Mechanically written member-data mutators are ugly as design too. All
objects and their properties should be as immutable as possible.

If object has part of state that can be modified independently of rest
of its state then something is wrong there. Draw some life-cycle state
transition diagram for object and describe cases on it when part of
its state (some property) changes. As a rule it occurs that the
properties do not change so independently but instead several change
at once (just like all iterators of vector may be invalidated with
insert or reserve). When you look closer why you needed the setters/
getters for data members then it is usually so because your design has
separated Doers from Knowers or something like that.
I wrote a long explanation of
why I think the names should be like that here http://bit.ly/18n5F

Interesting article ... however on most common cases such functor does
not fit.

Imagine that you may want a public getter about something like say
area() for Square. You most likely do not need public setters like
area(newArea) for it? From there comes problem that you can not split
functor member so that one of its operator() overloads is public and
other is private in context of encapsulating class.

Other problem is that properties of object are usually interrelated
for example area is usually recalculated each time using side of
square not cached into other data member.
 
M

Maxim Yegorushkin

On 27/07/10 16:51, theambient wrote:
[...]
You can do without having to store any extra data in you property
objects. Because object's members are stored at a constant offset from
the beginning of an object you can calculate object's address from the
property address (this) using offsetof() macro from<stddef.h>. (beware,
it does not work with virtual base classes).

Beware, offsetof() doesn't work for anything but POD-structs.

Don't see why it would not work on practise (apart from virtual base
classes). Could you elaborate?
 
J

Jorgen Grahn

Give him a break: English does not seem to be his primary language.

I did give him /one/ break, as I wrote.

There were no other spelling errors, so I got the impression that he
had somehow mislearned Stroustrup's name, and that I was helping him
by correcting him.

/Jorgen
 
G

Gennaro Prota

On 28.07.2010 13:12, Maxim Yegorushkin wrote:
[...]
a few more words about setters and getters. Is it normal to
use names like
void property( const T& val ); // setter
T const& property(); // getter
or better with prefixes set_ and get_ which is in my opinion a
little bit ugly?

It's a question of style. My own preference is to use just the
names when it's conceptually a property (a data member
accessible from outside the class), and get and set otherwise.

It would be my preference, too, but I think this is very
difficult to formulate. I mean: substituting a true, unambiguous
criterion to "it's conceptually a property".
 
J

joe

Jorgen said:
I did give him /one/ break, as I wrote.

There were no other spelling errors, so I got the impression that he
had somehow mislearned Stroustrup's name, and that I was helping him
by correcting him.

intelsence?
 
J

joe

Jorgen said:
I did give him /one/ break, as I wrote.

There were no other spelling errors, so I got the impression that he
had somehow mislearned Stroustrup's name, and that I was helping him
by correcting him.
adviced ?
 
J

joe

Jorgen said:
I did give him /one/ break, as I wrote.

There were no other spelling errors, so I got the impression that he
had somehow mislearned Stroustrup's name, and that I was helping him
by correcting him.

I got the impression that his enthusiasm to get started with the language
overcame any concern with proper linguistics. I've seen Bjarne S.
lecture/present and have read his books; He seems pretty laid back and
easy-going. I have a feeling he'd be more akin to helping someone who is
enthusiastic about C++ rather than to start out with "First, young man,
my name is ____, NOT ____". The poster obviously knew enough to get BS's
book, so he's on the right track for sure.
 
Ö

Öö Tiib

     [...]
a few more words about setters and getters. Is it normal to
use names like
void property( const T&  val ); // setter
T const&  property(); // getter
or better with prefixes set_ and get_ which is in my opinion a
little bit ugly?
It's a question of style.  My own preference is to use just the
names when it's conceptually a property (a data member
accessible from outside the class), and get and set otherwise.

It would be my preference, too, but I think this is very
difficult to formulate. I mean: substituting a true, unambiguous
criterion to "it's conceptually a property".

Property? It is something that is close to public data member, but you
want a thin layer of fake objectorientedness so you design hybride
between public data member and public member function. Even that gives
several advantages but it is not OO.

I do not actually buy that "set" helps with non-property somehow. For
example everybody was born somewhere. Birth place (a Location) however
is not property because it does not belong to Person. Also perhaps you
do not want public setters to it, because it is likely very special
use case when place of birth of someone may change. Now lets compare.
1):
LocationRef loc = bob.getBirthPlace();
2):
LocationRef loc = bob.birthPlace();

What i am seeing only wasted letters "get" on case 1) and nothing is
more readable there. I feel such helper parts in name (not necessarily
"get" or "set") might be useful when the name of function is otherwise
unambiguously clear if that is noun or verb (property or command). For
example empty() of std containers is often confused with clear() by
novice programmers and helper parts in names (like "is_empty" and
"clear_up") might therefore be fine on similar cases.
 
G

Gennaro Prota

Which is not the normal way of doing it. A "property" in C++ is
no more than a member with a getter and setter having the
externally visible name, e.g.:

class Toto
{
PropertyType myProp;
public:
PropertyType prop() const { return myProp; }
void prop( PropertyType const& newValue )
{ myProp = newValue; }
};

The syntax for accessing a property is different than that for
accessing a member variable, but that's the way C++ works.

Which means that C++ doesn't have "properties" :)

It really depends on the meaning of the word. But every time
I've seen it in the context of a specific language (not very
often, given the languages I frequent) the fact that a property
was read and written like a field --not invoked like a method--
was essential.

The hack they present attempts exactly to obtain that:
translating "the syntax for reading and writing" to a function
call. For writing it's almost OK; for reading, of course, it's
more problematic --the conversion isn't exactly transparent,
especially when T isn't a built-in.

But in any case, as you say, it's all absolutely non-idiomatic
and really a way to invent one's own language on top of C++.
 
G

Gennaro Prota

On 29/07/2010 17.29, Ruslan Mullakhmetov wrote:
[...]
Once I've been writing tiny app in C#....I was crying how it's glamour,
especially regarding VS intelsence support. Ohhh, just two letters and
it adviced me (correctly) what to write. There is no need to think at
all, VS do all work for you )))

Sorry, in programming there's *always* a need to think.
 
G

Gennaro Prota

hi,

I want make property
(http://en.wikipedia.org/wiki/Property_(programming)) in C++.

In the wiki article explained how to make property in C++ using
template mechanism

this looks like

========================================================================
========================================================================
template<typename T> class property {
T value;
public:
T& operator = (const T&i) {
::std::cout<< i<< ::std::endl;
return value = i;
}
// This template class member function template serves the
purpose to make
// typing more strict. Assignment to this is only possible with
exact identical
// types.
template<typename T2> T2& operator = (const T2&i) {
::std::cout<< "T2: "<< i<< ::std::endl;
T2&guard = value;
throw guard; // Never reached.
}
operator T const& () const {
return value;
}
};
========================================================================
========================================================================

everything is clear (except never reached throw, aprreciate if anybody
explain it to me)

It's silly, they mean to generate a compilation error. You might
make it private and omit the definition (body). That's more or
less the standard way in C++03.

Be sure you understand template instantiation (among other
things) well enough to know what really happens, though.
Consider that you are also prohibiting

bar.bravo = 0 ;
or
bar.bravo = 1 ;
 
Ö

Öö Tiib

Which means that C++ doesn't have "properties" :)

Property is sort of symbiosis between data member and member function.
It is attempt to making access to data uniform with rest of things.
One of the core principles of object-oriented programming is uniform
access principle.
It really depends on the meaning of the word. But every time
I've seen it in the context of a specific language (not very
often, given the languages I frequent) the fact that a property
was read and written like a field --not invoked like a method--
was essential.

Uniform access principle is that there should be no difference if it
is some (possibly fixed and immutable?) attribute or data field of
objects data, some pre-computed and cashed property of object or more
complex (lazy?) function that calculates and constructs requested data
when called. Benefit of it is that interface does not reveal
implementation details nor enforce implementation details upon
implementation. It is least intrusive both ways.

Function-like form of access is most uniform in C++. Therefore that
form feels most fitting with uniform access principle in C++.
The hack they present attempts exactly to obtain that:
translating "the syntax for reading and writing" to a function
call. For writing it's almost OK; for reading, of course, it's
more problematic --the conversion isn't exactly transparent,
especially when T isn't a built-in.

But in any case, as you say, it's all absolutely non-idiomatic
and really a way to invent one's own language on top of C++.

Object-oriented programming may be is sometimes overrated. At least in
some situations. So properties and their getters and setters are OK
sometimes.

Optical illusions however that are made to mislead readers cannot be
ever cursed and bad-mouthed elaborately enough. If something is
accessed in C++ like fields of data structures of C are accessed then
reader assumes that it is PODS. If it is not PODS then why to hide the
shameful fact with clever tricks?

Plain old data structures are still often needed for portability and
interoperability in C++. Something else that has external interface
PODS-like is a distracting and confusing optical illusion. PODS have
numerous privileges in C++ so someone under wrong illusion that he is
dealing with one may make some hard-to-spot bugs.
 
J

James Kanze

On 31/07/2010 14.55, James Kanze wrote:

[...]
It would be my preference, too, but I think this is very
difficult to formulate. I mean: substituting a true, unambiguous
criterion to "it's conceptually a property".

Well, the compiler doesn't care, so it's really something you're
telling the reader. As the designer of the class, you decide
whether something is conceptually part of the class or not.
 
J

James Kanze

On 1 aug, 03:31, Gennaro Prota <[email protected]> wrote:

[...]
Property? It is something that is close to public data member,
but you want a thin layer of fake objectorientedness so you
design hybride between public data member and public member
function. Even that gives several advantages but it is not OO.

Maybe. But naming the function getSomething doesn't change
anything in this regard. In practice, OO or not, some classes
encapsulate data.
I do not actually buy that "set" helps with non-property
somehow. For example everybody was born somewhere. Birth place
(a Location) however is not property because it does not
belong to Person.

How is that? It obviously depends on the application, but in
most applications, Location are values (with no behavior or
identity), and each Person has one (and only one) birthplace,
which belongs to him. (In most applications, making Location a
type for birthplace, rather than just using std::string, is
overkill.)
Also perhaps you do not want public setters to it, because it
is likely very special use case when place of birth of someone
may change.

An input error is not what I'd consider a special use case. (It
would make a lot of applications simpler if it was.) On the
other hand, a lot of programs would probably not be involved in
correcting information about Person; they could probably
consider Person an immutable type.
Now lets compare.
1):
LocationRef loc = bob.getBirthPlace();
2):
LocationRef loc = bob.birthPlace();
What i am seeing only wasted letters "get" on case 1) and
nothing is more readable there. I feel such helper parts in
name (not necessarily "get" or "set") might be useful when the
name of function is otherwise unambiguously clear if that is
noun or verb (property or command). For example empty() of std
containers is often confused with clear() by novice
programmers and helper parts in names (like "is_empty" and
"clear_up") might therefore be fine on similar cases.

Regretfully, the naming conventions in the standard library are
horrible. There is certainly no "property" empty for a standard
container---it's arguable that a container doesn't have
properties, in the sense that it manages its data differently.
And functions which are not properties should be verbs. Which
means that by all rights, std::vector<>::empty is a verb, and as
a verb, defines an action. The only correct name in this case
would be is_empty. And clear should do just that: the verb
empty should remove all elements from the vector, and the verb
clear return it to the state it had immediately after
construction. But that would be good design. Not something we
see much of in the standard library.
 
J

James Kanze

On 31/07/10 13:53, James Kanze wrote:
On 27/07/10 16:51, theambient wrote:
[...]
You can do without having to store any extra data in you
property objects. Because object's members are stored at a
constant offset from the beginning of an object you can
calculate object's address from the property address (this)
using offsetof() macro from<stddef.h>. (beware, it does not
work with virtual base classes).
Beware, offsetof() doesn't work for anything but POD-structs.
Don't see why it would not work on practise (apart from
virtual base classes). Could you elaborate?

The standard says so. In practice, the obvious implementation
is something like:
#define offsetof(type, member) __builtin_offsetof (type, member)
Given that using it on a non-POD is undefined behavior, from a
quality of implementation point of view, I would expect a
compiler error if type were not a POD struct. If you don't get
an error, then the quality of implementation isn't very good.
 
F

Francesco S. Carta


<snip>

I pushed this for distraction and I had a bit of fun creating it, but I
would never use something like this, I'll simply stick to the functional
notation wherever I need to intercept the property change.

Disclaimer: the code below is _intentionally_ littered with macros.

Don't waste your time /criticizing it for me/: I _do_ consider it a very
expensive and silly way to skin this very cat.

Still, an interesting exercise for me.

//-------
/*
Assigning to a Property within the setter callback
or reading the same Property from the getter callback
will result in an infinite loop, either:

- keep the following macro defined and
pay for the additional checks

- undefine the following macro and be sure:
- to not assign to the Property in the setter callback
- to not read from the Property in the getter callback

*/

#define PREVENT_CALLBACK_LOOP
#undef PREVENT_CALLBACK_LOOP

template<class Object, class Type> class Property {
public:

typedef Type (Object::*setter_callback)(Type, Type);
typedef void (Object::*getter_callback)(Type);

Property(Type value = Type(),
Object* object = 0,
setter_callback setter = 0,
getter_callback getter = 0):
#ifdef PREVENT_CALLBACK_LOOP
_updating(false),
#endif
_value(value),
_object(object),
_setter_callback(setter),
_getter_callback(getter) {}

Property& operator=(const Property& p) {
return this->operator=(Type(p));
}

Property& operator=(Type newvalue) {
#ifdef PREVENT_CALLBACK_LOOP
if (!_updating) {
_updating = true;
#endif
if (_object && _setter_callback) {
newvalue = (_object->*_setter_callback)(_value, newvalue);
};
_value = newvalue;
#ifdef PREVENT_CALLBACK_LOOP
_updating = false;
}
#endif
return *this;
}

operator const Type&() const {
#ifdef PREVENT_CALLBACK_LOOP
if (!_updating) {
_updating = true;
#endif
if (_object && _getter_callback) {
(_object->*_getter_callback)(_value);
}
#ifdef PREVENT_CALLBACK_LOOP
_updating = false;
}
#endif
return _value;
}
private:
Property(const Property& p);

#ifdef PREVENT_CALLBACK_LOOP
mutable bool _updating;
#endif

Type _value;
Object* _object;
setter_callback _setter_callback;
getter_callback _getter_callback;
};

//-------
// test case:

#include <iostream>
using namespace std;

#define INITIALIZE_PROPERTY(property_name, parent_type) \
this, \
&parent_type::property_name##_write, \
&parent_type::property_name##_read

static int id_count = 1;

struct Tester {
Property<Tester, int> i;

Tester(int i = 0) :
i(i, INITIALIZE_PROPERTY(i, Tester) ),
id(id_count++) {}

Tester(const Tester& t) :
i(t.i, INITIALIZE_PROPERTY(i, Tester) ),
id(id_count++) {}

Tester& operator=(const Tester& t) {
i = t.i;
return *this;
}

int i_write(int oldvalue, int newvalue) {
cout << "[t" << id << "] ";
if (newvalue > 10) {
cout << "write: refused change from " << oldvalue
<< " to " << newvalue
<< ", let's make it 10" << endl;
return 10;
} else {
cout << "write: accepted change from " << oldvalue
<< " to " << newvalue << endl;
return newvalue;
}
#ifdef PREVENT_CALLBACK_LOOP
i = 78; // will never do anything, of course
#endif
}

void i_read(int current) {
cout << "[t" << id << "] read: "
#ifdef PREVENT_CALLBACK_LOOP
<< i
#else
<< current
#endif
<< endl;
}

private:
int id;
};

int main() {
cout << "\n# Tester t1(1);" << endl;
Tester t1(1);

cout << "\n# Tester t2(t1);" << endl;
Tester t2(t1);

cout << "\n# t2.i = 8;" << endl;
t2.i = 8;

cout << "\n# t2.i = t1.i;" << endl;
t2.i = t1.i;

cout << "\n# t2.i = 2;" << endl;
t2.i = 2;

cout << "\n# Tester t3(3);" << endl;
Tester t3(3);

cout << "\n# t3 = t2;" << endl;
t3 = t2;

cout << "\n# t3.i = 3;" << endl;
t3.i = 3;

cout << "\n# t1.i = t2.i = t3.i = 42;" << endl;
t1.i = t2.i = t3.i = 42;

cout << "\n# print'em all " << endl;
cout << t1.i << " " << t2.i << " " << t3.i << endl;

return 0;
}

/*
OUTPUT:

# Tester t1(1);

# Tester t2(t1);
[t1] read: 1

# t2.i = 8;
[t2] write: accepted change from 1 to 8

# t2.i = t1.i;
[t1] read: 1
[t2] write: accepted change from 8 to 1

# t2.i = 2;
[t2] write: accepted change from 1 to 2

# Tester t3(3);

# t3 = t2;
[t2] read: 2
[t3] write: accepted change from 3 to 2

# t3.i = 3;
[t3] write: accepted change from 2 to 3

# t1.i = t2.i = t3.i = 42;
[t3] write: refused change from 3 to 42, let's make it 10
[t3] read: 10
[t2] write: accepted change from 2 to 10
[t2] read: 10
[t1] write: accepted change from 1 to 10

# print'em all
[t3] read: 10
[t2] read: 10
[t1] read: 10
10 10 10

*/

//-------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,244
Latest member
cryptotaxsoftware12

Latest Threads

Top