Archived

This topic is now archived and is closed to further replies.

Pitfall of OOP? Or me just having a hard time following good practice ...

This topic is 5824 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

There is something about OOP that I do not entirely understand ... I know for a fact that there must be a better way so hopefully someone can tell me. If I create a Vector class I have no problem keeping all of the properties private and adding accessor functions for every property. But, what if I create another class that has Vectors for properties ... say a Body class that as a Vector for its velocity. Then wouldn''t I have to write functions for the Body class that change the properties of the Vector? I can''t access the vector directly so i can''t invoke the accessor functions. What do I do? Thanks

Share this post


Link to post
Share on other sites
there are wonderful features called inheritance, polymorphisism, friend classes etc, i dont know what any of them do, but im sure there useful, and ive had too many glasses of chapagne this new year

Share this post


Link to post
Share on other sites
In addition to having functions to just get every property, you canadd functions to set every property. That way, external classes and functions can set the variables of the object, but the function can be defined to prevent errors.

Take a class where all the members are public, for example. Anything can access those members and change them. In your vector class (I'm not sure whether you mean mathematical vector or like an STL vector, but I'll assume STL vector), a you might have a variable that holds the amount of variables to hold memory for. If another part of the program changed that variable to, say, a negative number, there would be memory leaks all over the place. If that variable were protected by a function that changes it, you could check for improper values for that variable within the function and not change the variable at all, preventing future errors. Probably not the best example, but I hope you understand now.

Edit: Now that I re-read your question, I think I answered the wrong thing. Oh well.

No, HTML is not an OO language.

Edited by - masonium on December 31, 2001 7:46:00 PM

Share this post


Link to post
Share on other sites

// Body header:
class Body
{
...
Vector &SetVelocity(vector_type x,
vector_type y,
vector_type z);
private:
Vector vecVelocity;
...
};
Vector &Body::SetVelocity(vector_type x, vector_type y, vector_type z)
{
vector vecOld = vecVelocity;
vecVelocity = Vector(x,y,z);
return vecOld;
}
.
// somewhere else:
Body *bod = new Body();
bod->SetVelocity(x, y, z); // <- There''s no way around this step

Deal with it.

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
Deal with it? That is all? Does anyone see the major problem with this? I am positive someone has, so there must be a way around it or a better way to do things. If I create a class and I write 3 functions for "getting" and "setting" the values of the private variables then I have to (basically) rewrite those functions in every class I use the first class in. If I don''t have access to the object how can I have access to its functions? Then what if I have a class object within a class object and finally within another class object ... that could mean tons and tons of "getting" and "setting" functions that have already be written.

Thanks everyone for the help so far, but this is obviously discouraging to see ...

Share this post


Link to post
Share on other sites
If you don''t like making getter/setter functions for the members, then just declare them as ''public''. Then you can access their functions directly. It''s up to you.

Share this post


Link to post
Share on other sites
It depends on how far you extend your privates... er I know that sounds wrong, but...

Anyway, let''s say you declare your Vector class, use private properties and then write ''set'' and ''get'' functions. If you then put an instance of this class into another class (lets say Body), depending on whether or not this Vector variable is declared private, you may or may not need to write another set of access functions. If you declare this[/]i variable private, then you will need to write access functions in order for outsiders to access the variable. But the Body class can still access the variable directly, yet it must use the access functions of Vector since Vector is the only class that can actually directly reference the data.

Share this post


Link to post
Share on other sites
I would add method(s) that make something happen - having a SetVelocity abstracts nothing, and therefore does no work.

Body::ApplyForce(vector vForce_N)
Body::ImpartImpulse(vector vImpluse_Ns)
Body::InterpolatePosition(float fElapsedTime_sec, vector* pvPosition_m);
Body::InterpolateVelocityPosition(float fElapsedTime_sec, vector* pvVelocity_mps, vector* pvPosition_m);

Body::IncreaseMass(float fAdditionalMass_kg);
Body::ReduceMass(float fAdditionalMass_kg);


I also can''t fathom a single item of a 3D vector that would need to be private nor protected.


Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

"What I see is a system that _could do anything - but currently does nothing !" - Anonymous CEO

Share this post


Link to post
Share on other sites
strtok,
I don''t mind making "getting" and "setting" functions ... I *want* to follow good programming practice. But, I see some major flaws with following it, and I am sure others have too, so I would like to know how to overcome it.

Zipster,
Thank you very much for that ... you are making some sense. It seems that now it is a matter of using names in context. I would need an accessor function for the body, but instead of "reset_vector" it is "reset_velocity." That still does not make me happy ...

Magmai Kai Holmlor,
A vector was just an example ... what if I then use a body object in a bigger class ... say Simulation_World. I would then lose all access to those "ApplyForce" and whatever else functions since the Body would be private. Therefore I would have to rewrite those functions for the Simulation_World class. That seems like a waste of time ...

Thank you all for the replies ... it is all good information for me to take in ...

Share this post


Link to post
Share on other sites
quote:
Original post by jag_oes
I don''t mind making "getting" and "setting" functions ... I *want* to follow good programming practice.


That''s a contradiction, imnsho.

quote:
Original post by jag_oes
A vector was just an example ... what if I then use a body object in a bigger class ... say Simulation_World. I would then lose all access to those "ApplyForce" and whatever else functions since the Body would be private. Therefore I would have to rewrite those functions for the Simulation_World class. That seems like a waste of time ...


Well, with a simulated world you would need a way to figure out _what body you''re dealing with.

Simlation_World:ick(point2D MouseClick, Body* pBodyClicked);
And once you have the body you clicked on, you can call ApplyForce on it...

Ug, don''t inherit Body from Simulation_World, SW should have some sort of tree of them.


Start off only using public inheritence - when you inherit (publicly) you''re saying that the new object IS the old object, and every method the was public in the old object applies to the new object. If that''s _not the case the design is flawed (sometimes you accept the flaw and press-on...).


Private inheritence means it''s implemented in terms of something else - you do this just so you don''t have to copy&paste code or redefine all the methods.

Protected inheritence has uses but requires an involved example.

Share this post


Link to post
Share on other sites
Pardon my ignorance, but I thought it was considered "good" to keep as many variables as possible private. If I am contradicting myself then it is out of lack of knowledge rather than hypocrisy. And what exactly is the "imnsho" supposed to be an acronymn for?

I understand what you are saying, and in my defense ... I was not planning on inheriting Body from Simulation_World.

I will pour over these posts until I understand ... or until I give up and go back to my old ways.

Thanks again ...

Share this post


Link to post
Share on other sites
Limiting the scope of variables is a useful tool, but you don''t have to use it just for the sake of it. Only use it where it serves a use... otherwise the extra effort of writing "get" and "set" functions is put in for nothing.

You should only make variables private when either no other object would have a use for the variable, or you want your "get" and "set" functions to do some sort of validation processing, or when it might be cause trouble for another object to change that variable (a "read only" variable).

For example, if you had a class enumerating the hardware on your computer, and it contained a string naming your graphics card, e.g. "GeForce2", then you should make this private, because there''s no reason for another object to change that variable. Any change would make it invalid.

Share this post


Link to post
Share on other sites
quote:
Original post by jag_oes
Pardon my ignorance, but I thought it was considered "good" to keep as many variables as possible private. If I am contradicting myself then it is out of lack of knowledge rather than hypocrisy.

The point is that there are no hard and fast rules in programming, and that "good programming practice" as you put it is a matter of judgement. In the case of the vector, it makes no sense to have any private data members (unless you''re doing something extraneous with them).

quote:
And what exactly is the "imnsho" supposed to be an acronymn for?

In my not so humble opinion.

quote:
I understand what you are saying, and in my defense ... I was not planning on inheriting Body from Simulation_World.

Simulation_World, as Magmai mentioned, should have a tree or list of Body objects, on which the methods can be called. And as he also said, you would have sensible methods on the collection that performed abstraction (like Body::ApplyForce()).

Finally, look up the friend keyword.

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!

Share this post


Link to post
Share on other sites
I think this is what you would like to do:


class Vertex
{
private:
//This is a private variable, but you want access to all its
//methods, right?
Color color;

public:
//You can do this:
Color &GetColor (void) {return color;}

//And this:
void SetColor (Color &_color) {color = _color;}
};

...
//Then later in your code, you do this:
some_vertex.GetColor().call_some_method_of_Color_class();
...


Since the getter returns a reference to your variable, you can access all of its methods without re-writing them. Of course you could simply make the variable public.

Share this post


Link to post
Share on other sites
Making properties private is a good idea - I have very very few properties that are public, but if you find yourself wanting a get/set for one you need to have a hard look at why.

I''ll grant you that get/set tuples seem to be popular in OOP circles, but the root of the problem is that abstract nothing and therefore accomplish nothing. In some languages you need them - but in C++ there''s usually a better way - either methods that actaully do something, or operator overloads - or just make it public (vector, matrix, complex, CWaveFormat : public WAVEFORMATEX).

Share this post


Link to post
Share on other sites
The purpose of "get-set tuples" isnt abstraction - its encapsulation.

Fantastic doctrines (like Christianity or Islam or Marxism or Microsoft-bashing) require unanimity of belief. One dissenter casts doubt on the creed of millions. Thus the fear and hate; thus the torture chamber, the iron stake, the gallows, the labor camp, the psychiatric ward - Edward Abbey

Share this post


Link to post
Share on other sites
I agree with Arild. You should always encapsulate your member variables in classes. This allows you to do extra management if needed, whether now or in the future. A few examples:

Lazy computations

Say you have a date class and want to store the date internally in a Julian format (number of days since 4713 BC) for easier computations. The user wants to retrieve the date in Gregorian format (day, month, year). If you make the month, day, year exposed as public variables, then you must convert the Julian date to the Gregorian equivalent every time the user adds/subtracts days, months, or years from the current date. So you add the CalculateGregorianDate to every function that changes the current date held.

However, later on when using this class with a program that performs many date calculations you realize this is just too slow. Instead you want to perform a lazy calculation on the Gregorian date. In other words, you don't convert the date to Gregorian until the user actually needs to retrieve the date.

Since you had your member variables exposed you must now change the interface to the class to encapsulate these variables, thus breaking every program that uses this date class.

Had you encapsulated these from the start the change would have been as simple as changing the get functions to this:

int GetYear()
{
if (m_date_changed)
CalculateGregorianDate();

return m_year;
}


Reusability

What happens when you need to change the way a class returns information when you don't have access to the internals of the class? The best way to do this is inherit a new class from the old class and override the functions required.

An example could be that you have a time class that returns the hour in an AM/PM format but you want it to return it in a 24 hour format. If they've exposed the m_hour variable then you must now override every function that could change the m_hour variable and perform a small calculation to change it to the 24 hour format. This could result in a lot of functions needing to be changed.

If they had encapsulated their variables you could do it with one function like so:

int GetHour()
{
return Calculate24HourFormat(m_hour, m_hour_suffix);
}


Lazy Initialization

I assume most of you are familiar with the Singleton class, so this doesn't need much explaination. Basically it allows you to initialize a variable only when it is trying to be used for the first time:

MyClass *GetInstance()
{
if (m_instance == null)
m_instance = new MyClass;

return m_instance;
}


Variable Access Standardization

If you know with 100% absolute certainty (*snicker*) which variables will never need to perform extra work when retrieving or setting a variable you can encapsulate those in get/set functions and keep the rest of your variables (whether in this class or another) as public.

The problem is that the users of these classes have no clue when they need to use the get/set functions and when they can directly access the variables. Access may be different for each class or even mixed inside the same class!

Obviously this just plain isn't good coding practice. You need to standardize access to your variables and stick to that implementation. Thus encapsulating all variables in get/set functions in the only answer since they are needed in some cases.


There are other reasons too I'm sure, but it's late and I can't think of anymore offhand .


- Houdini

Edited by - Houdini on January 1, 2002 11:47:49 PM

Share this post


Link to post
Share on other sites
quote:
Original post by jag_oes
I don''t mind making "getting" and "setting" functions ... I *want* to follow good programming practice. But, I see some major flaws with following it, and I am sure others have too, so I would like to know how to overcome it.



Part of the problem is the assumption that ''set'' and ''get'' methods are good programming practise. In reality (at least in my reality ) good practise is the separation of internal representation and the interface. It''s just that the ''set'' and ''get'' methods are the most common way to do this. If you just make every data member private then add a set and get method, you would have been just as well off making them public.

A vector is _not_ an x,y,z tuple - a vector is a direction and a length, that happens to be able to be represented as a set of three numbers, with the assumption that the start of the vector is at 0,0,0. For a particular application, it may be more efficient to store a vector in polar coordinates (2 angles and a length). In both cases, you''ll still want the same interface. (when you''re working on performance, you care about the implementation, when you''re actually using the vector class you don''t want to have to keep thinking about how it actually works. The more complicated a class gets, the more important that is, too.)

If an object has a position and a velocity (velocity is direction and speed) then these can easily be represented by vectors - but the interface to the object should be designed _entirely_ without regard to the fact that you intend to use a vector to store these.

In this case, I''ld probably look at having SetDirection(), SetSpeed(), GetDirection() and GetSpeed() methods, and have those use your private vector. (These may not be the best methods for what you''re doing, though - that''s one of the things you need to work out )

When you''re working out what interface to provide for an object, think about what it _means_ rather than how the data will be stored. If you have a thing called a vector, think about the where and how it will be used, and create methods that will implement that. If they happen to be Set/Get methods, that''s fine but at least you''ll know why you''re doing them, rather than doing Set/Get because that''s what everyone does.


quote:

A vector was just an example ... what if I then use a body object in a bigger class ... say Simulation_World. I would then lose all access to those "ApplyForce" and whatever else functions since the Body would be private. Therefore I would have to rewrite those functions for the Simulation_World class. That seems like a waste of time ...



If Simulation_World is the data structure containing all objects in the world (I assume when you mentioned ''Body'' that each object in the world would be of class Body), then you can create an iterator class that lets you loop over all objects. The iterator will then be part of the interface to Simulation_World, but the actual details of how the data is stored (list, array, tree, whatever) is not visible to the users of the classes.

An iterator contains operations to get the current object, advance to the next object, go to the previous object, and check if the iteration has completed (not all are required, if not necessary.) You can have multiple iterator accessors if necessary - eg get_player_iterator() to iterate over all player objects, get_enemy_iterator() to iterator over entities that need to have AI executed, and so on.

(btw, you probably should read up on STL iterators - whether you use STL or not, knowing how it works will help when you go to write your own complex containers and iterators.)

As yet another alternative, you can create a visitor which the Simulation_World applies to all data objects. (A visitor is an object that ''visits'' each object in a data structure, and can apply any operations to them, as necessary - once again, it lets Simulation_World know about the data structure, but other code can still access the objects through the public API.)

If you haven''t read Design Patterns at least a dozen times already, you need to get a copy - it''s the most useful book I''ve found on how to do OO programming. I''ld suggest following that with Large Scale C++ Programming (er, I think that''s the title - all my books are packed away til the weekend) by John Lakos. It focuses more on physical structuring of a program, and managemant of dependancies - this is another problem waiting to happen, once your programs start to grow.

Share this post


Link to post
Share on other sites
I think I know what you are going through and I also think that the solution you choose depends on what you are after.

"There are two peimary methods of extending classes to work with each other: inheritance and layering." and "If an object has an is-a relationship to another object, use public inheritance. If a has-a relationship describes the objects best, then use layering .

"Class Corvette is-a type of car."
"Class Corvette has-a type class radio."
Game Programming Gems. Charles River Media. p12

Please accept my apologies if I have misunderstood you, but it seems to me that you are worriyng in vain.

Let me give it a try:

You have a vector class with set and get functions. When you include this class as a member object you should not think of it as you have to write new functions to set and get the included vector object(s). Of course, implicitly you have to but whats the problem? You are not longer primarily setting or getting a vector, instead you are setting and getting the properties of the of object1 that belongs to object2 and really, see it as you are manipulating object2.

thisradio.setVolume() as opposed to
thiscar.setRadioVolume() it is THE car´s own radio or if you really want control use

CCar::getRadio() {return m_lpRadio;}
and
thiscar.getRadio()->setVolume(HIGH);

Think of it like an engine all by itself. You could start it by mixing some cables CEngine::Start(). Now if you include the engine in a car, you can´t just let the user start the engine by using a pair of cables(!), instead you let the user start the car by using a key. Now, usually it is two different things that are happening when you start the engine by itself or as a part of a car - it is PART OF A BIGGER SYSTEM. When you start it the electrical system checks different statuses etc, they are all objects encapsulated in the car.

I just felt poetic and might have put you in total disarray, sorry if so but I really cannot explain what I wanted in a understandable fashion.





I am actually a Swede, living in paradise.

Share this post


Link to post
Share on other sites
quote:
Original post by Arild Fines
The purpose of "get-set tuples" isnt abstraction - its encapsulation.


Um, care to define encapsulation? because I beleive you meant data-hiding.

Public or private, it''s encapsulated. Add a get/set tuple and it''s not hiden - all it does for you is allow you to create side-effects, which I detest.

You don''t really need classes to do encapsulation, but they work very well with it. (It''s part of modular code, and any API you use will exhibit encapsulation, like HWND and window functions in the Win32 API for instance, it begs to be a class in C++.)

quote:

You should always encapsulate your member variables in classes


If it''s in the class, it''s encapsulated. It''s really really hard not to encapsulate when using an OOPL.

quote:

Thus encapsulating all variables in get/set functions in the only answer since they are needed in some cases.


No They''re Not

Want a read only public property? Make it const. Cast away the constness when you want to change it inside the class.
Any case you can think of to use a get/set tuple is not needed with C++.

Lazy computations indicate a design problem - if a computation needs to be performed, shouldn''t there be a method name that indicates this and tell you something about what it does? InterpolateVelocity(...) is way better than a lazy computation performed using a property get function on a supposed Velocity property (imo anyway).

quote:

So you add the CalculateGregorianDate to every function that changes the current date held.


NO! You make the user of your class call the conversion fucntion if and only if they need to - what if they wanted a Julian date? Then we''d have wasted a ton of time calculating the Georgain date and it''s not even needed. It''s a convoluted mess otherwise (like VB''s GUI).
We use a get/set, and it''s inefficent, so we add lazy evaluation to make it more efficent. Now what problems are afoot with lazy eval? What will we need to add to fix them? Perhaps we''ll need a way to force an evaluation? That kind of tail-chasing is why I think get/sets are poor designs. When you run into code like this, it''s easier to start over and do it differently than fix the existing mess.

I''d have two classes; one for Julian dates and one for Gregorian dates - and a conversion method to switch between the two.

quote:

Since you had your member variables exposed you must now change the interface to the class to encapsulate these variables, thus breaking every program that uses this date class.


A problem that would have been avoided if you had used a properly named method for the operation instead of a get/set property. The get/set mentality _created this problem.
operator CGregorianDate(); is what I would have written.

The time example with reusability is poor. You''re talking about changing the behavior of the class - for all intents and purposes it''s a new class when you do that. Breaking the existing code and bringing this fact to the users attention would be the _nice thing to do.
Ignoring that, you''d never make a formated string a public property - you might make the stored time public, either as three enums for hour/minute/second (in the unambigious 24hr format) or a float data/time code ala Excel/Lotus style. Having a string with the AM/PM etc... means you should be calling a method that takes the stored time and converts it to the desired format. That way you _never need to change the behavior, since it''s up the programer or perhaps even the user how to display it.
FormatDateTimeCode(const char* Format, char* DateTime);
char szDateTime[32];
FormatDateTimeCode("MM/DD/YYYY HH/MM/SS AM/PM", szDateTime);

The singleton pattern is special case, GetInstance really means RetrieveInstance, unlike get/set tuples which really mean OnPropertyRead/OnPropertyWrite. For the singleton your accessing the object itself, not a property of it. On the surface it does seem very similar though.


Variable Access Standardization - well I see this as another reason not to use get/set... I know I need classes with public varibles that don''t use a get/set (Vector, Matrix, etc...) operator[] or operator() are what the user expects. In VB/COM/Java get/set is common, but it''s not the C++ way.

quote:

If you know with 100% absolute certainty (*snicker*) which variables will never need to perform extra work when retrieving or setting a variable...


I know that I will never program a side-effect, so I know I will never need to do extra work on reading/writing of a variable. I would make a method that made is obvious what extra work was being done. As such I have no need for them. So the crux of my arguement against get/set''s rest here.

For Side-Effects, for get/set. (Happy tail-chasing )
Against Sides-Effects, against get/set. (An extra line of code, the horror )


I''m not advocating making variables public, very few of my classes have any public properties; but I hearitly recommend using alternative means to set/get for manipulating the class.

Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee

"What I see is a system that _could do anything - but currently does nothing !" - Anonymous CEO

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor

Um, care to define encapsulation? because I beleive you meant data-hiding.


While the formal definitions of these terms may differ, in everyday speech they tend to be used interchangeably. Encapsulation r e q u i r e s data hiding.

quote:

Public or private, it''s encapsulated.


As long as you can access the internals of the object directly, its not encapsulated.


quote:

If it''s in the class, it''s encapsulated. It''s really really hard not to encapsulate when using an OOPL.


You seem to be referring to aggregation and/or composition.

quote:

Want a read only public property? Make it const. Cast away the constness when you want to change it inside the class.


Ewwww....ugly.

quote:

Any case you can think of to use a get/set tuple is not needed with C++.


Its still preferrable to some of the hacks you suggest.

quote:

We use a get/set, and it''s inefficent,


You know better than this.

quote:

In VB/COM/Java get/set is common, but it''s not the C++ way.


Since when?



Fantastic doctrines (like Christianity or Islam or Marxism or Microsoft-bashing) require unanimity of belief. One dissenter casts doubt on the creed of millions. Thus the fear and hate; thus the torture chamber, the iron stake, the gallows, the labor camp, the psychiatric ward - Edward Abbey

Share this post


Link to post
Share on other sites
Wow, I think this is the only time I''ve adamantly disagreed with you Magmai . Warning, this is a long post...


quote:
Original post by Magmai Kai Holmlor
Want a read only public property? Make it const. Cast away the constness when you want to change it inside the class.
Any case you can think of to use a get/set tuple is not needed with C++.



You''d actually require the class to cast away const to change variables that are meant to be changed? Shouldn''t this be the first clue that maybe they shouldn''t be const in the first place?

I''m not even going to mention how easy that makes it for people outside the class to cast away the const of those variables.

quote:
Original post by Magmai Kai Holmlor
Lazy computations indicate a design problem - if a computation needs to be performed, shouldn''t there be a method name that indicates this and tell you something about what it does? InterpolateVelocity(...) is way better than a lazy computation performed using a property get function on a supposed Velocity property (imo anyway).



Actually, I see not doing this as a major design problem. The user should not need to know how I internally store the date. They shouldn''t know anything internal to my class. All they care about is setting/modifying/retrieving the date. This is what black boxing is all about: you should be able to totally change the internal code of your class and not have it effect the interface of your class.

Black boxing is a Good Thing.


quote:
Original post by Magmai Kai Holmlor
So you add the CalculateGregorianDate to every function that changes the current date held.

NO! You make the user of your class call the conversion fucntion if and only if they need to - what if they wanted a Julian date? Then we''d have wasted a ton of time calculating the Georgain date and it''s not even needed. It''s a convoluted mess otherwise (like VB''s GUI).



You''d actually require that the user calls CalculateGregorianDate whenever the date changes? Not only is that going to create a lot of unecessesary code duplication for no reason, but it''s also guaranteed to cause bugs in their program because they will forget to call it sooner or later.

And worse yet, it can cause hard to track down performance issues when the they are calling CalculateGregorianDate unnecessarily.

Point of fact: CalculateGregorianDate is only required when the date has changed and the user wishes to retrieve the date values for the first time. You can do exactly this without requiring the user to do a thing and yet you think this is a bad idea?

But ok, for arguments sake, let''s say the user doesn''t mind calling CalculateGregorianDate, they call it every time they should, and they never call it unnecessarily. Life is good.

But what happens when you decide to change the way the date is being stored internally to Gregorian date instead of Julian? Well, now you''ve broken the external interface to the class. Either you''ll need to take out the CalculateGregorianDate function or it''ll be a useless function.

Changing how the date is stored internally should not effect the class interface.

Once again, this is why black boxing is a Good Thing.


quote:
Original post by Magmai Kai Holmlor
We use a get/set, and it''s inefficent, so we add lazy evaluation to make it more efficent. Now what problems are afoot with lazy eval? What will we need to add to fix them? Perhaps we''ll need a way to force an evaluation?



I don''t get the problem here. Since the only way to change to date is to do so through function calls, we can easily set a modified flag. If it''s set and the user tries to retrieve the date just calculate the date (which automatically resets the flag) and return the date. What problems are there?


quote:
Original post by Magmai Kai Holmlor
I''d have two classes; one for Julian dates and one for Gregorian dates - and a conversion method to switch between the two.



But the user doesn''t want the Julian date. They only want the Gregorian date. The reason I store the date in Julian is solely because, generally speaking, doing calculations in Julian is much easier than in Gregorian form.


quote:
Original post by Magmai Kai Holmlor
Since you had your member variables exposed you must now change the interface to the class to encapsulate these variables, thus breaking every program that uses this date class.

A problem that would have been avoided if you had used a properly named method for the operation instead of a get/set property. The get/set mentality _created this problem.
operator CGregorianDate(); is what I would have written.



Huh? The get/set mentality isn''t what created the problem. The get/set mentality is what caused this to never become a problem because you could automatically perform the calculation in the get/set accessors.

However you are right in that if you had required the user to call CalculateGregorianDate() before accessing the public variables, this wouldn''t be an issue either.

Of course, as I stated above, you are now locked on the way your date class internally stores the date. If you change it then your interface is now broken because the two are now linked.

Had you used the get/set accessors, this wouldn''t be a problem.


quote:
Original post by Magmai Kai Holmlor
The time example with reusability is poor. You''re talking about changing the behavior of the class - for all intents and purposes it''s a new class when you do that. Breaking the existing code and bringing this fact to the users attention would be the _nice thing to do.



I will agree the time class is a bad example, but I couldn''t think of a better one at the time.

However, I believe I didn''t explain myself clearly. What I had meant is that you have a time class that current code uses, which displays in AM/PM format. All you have is a header and lib file for this class, no source code. A new project needs a time class which displays in 24 hour format.

In other words, you need to create another time class to use for this new project.

The easiest way is to derive a new time class from the current time class which is bug tested and proven and change things to display in a new format.

If you used get/set accessors, then you just override them to return a 24 hour format.

If you exposed your class variables, you must override every function that changes the m_hour variable.


quote:
Original post by Magmai Kai Holmlor
Ignoring that, you''d never make a formated string a public property - you might make the stored time public, either as three enums for hour/minute/second (in the unambigious 24hr format) or a float data/time code ala Excel/Lotus style. Having a string with the AM/PM etc... means you should be calling a method that takes the stored time and converts it to the desired format. That way you _never need to change the behavior, since it''s up the programer or perhaps even the user how to display it.
FormatDateTimeCode(const char* Format, char* DateTime);
char szDateTime[32];
FormatDateTimeCode("MM/DD/YYYY HH/MM/SS AM/PM", szDateTime);



You are right, which is why the time class is a bad example. However, you still never know when you need to change the way data is presented to the class user. I stand by my reasoning in general, if not for this particular case.


quote:
Original post by Magmai Kai Holmlor
The singleton pattern is special case, GetInstance really means RetrieveInstance, unlike get/set tuples which really mean OnPropertyRead/OnPropertyWrite. For the singleton your accessing the object itself, not a property of it. On the surface it does seem very similar though.



I don''t see how it''s a "special case". In my singleton implementation I have a templated Singleton class where you pass the class type that will be used for it''s instance property , like so:

Singleton

So the user would not be accessing the object itself (the Singleton class), but rather a property of that class (the Log instance).

Either way, it''s still a property of the class. By your previous reasoning, you should be saying this:

"Lazy initialization indicates a design problem - if initialization needs to be performed, shouldn''t there be a method name that indicates this and tell you something about what it does? InitializeSingleton(...) is way better than lazy initialization performed using a property get function on a supposed Instance() property (imo anyway).

Now what problems are afoot with lazy init? What will we need to add to fix them? Perhaps we''ll need a way to force an initialization? That kind of tail-chasing is why I think get/sets are poor designs."

Tell me, why do you say it should be done this way with lazy computation, but not with lazy initialization? What''s the difference?


quote:
Original post by Magmai Kai Holmlor
Variable Access Standardization - well I see this as another reason not to use get/set... I know I need classes with public varibles that don''t use a get/set (Vector, Matrix, etc...)



You can use get/set functions just fine, and without any overhead.

As for Variable Access Standardization, I was under the assumption (apparently wrong assumption... well, except for when it''s convenient like in Singletons ) that you wouldn''t make every variable that the user may want access to, a public variable, and require the user to manually call what should be internal functions to the class before accessing these variables.


- Houdini

Share this post


Link to post
Share on other sites
actually, i think that c++ should support ''properties'', which would basically be a form of overloading, only the user would think hes directly accessing a member when hes really using accessors ->like VB.

ex:

class C
{
public:
property int x;

private :
int m_x;
};

property c::x() {return m_x);
property c::x(int setx) {m_x = setx);

void main()
{
C c;
c.x = 5;
int y = c.x;
}

Share this post


Link to post
Share on other sites
There are compiler specific extensions to support the notion of properties - both MSVC++ and Borland C++ Builder has them.

Fantastic doctrines (like Christianity or Islam or Marxism or Microsoft-bashing) require unanimity of belief. One dissenter casts doubt on the creed of millions. Thus the fear and hate; thus the torture chamber, the iron stake, the gallows, the labor camp, the psychiatric ward - Edward Abbey

Share this post


Link to post
Share on other sites