Hi! I haven''t had much time to do anything online lately -- been landscaping and digging and planting and mowing and getting a really nasty case of sunburn!
To top it off, AOL would let me connect fine yesterday but I would get logged off after about 10 seconds each time...
quote:
Original post by chippydip
If you haven''t checked out the eiffel site I suggest you do and search for an explaination of design by contract. I think this is a potentially VERY useful tool that C++ lacks. Now that I think of it, I belive it is implemented with exception throwing similar to what you are trying to do so I guess your way is the best that can be done in C++.
I don''t see where the Eiffel implementation comes close to C++ in terms of speed AND reliability... People just don''t use much of C++, so they don''t think it''s very flexible. (Check out the little file class below.)
quote:
Original post by chippydip
Speaking of readable code, I would like to point out what I think is a flaw in your aregument of objective readability. I completely agree that code is an objective object. It exist, no argument. But readability is a characteristic of code (similar in some ways to the beauty of a piece of music.) This characteriscit is a subjective quality of the code (it does not exits in any physics form... its just an idea about the code.)
Just because something is not tangible does not mean that it does not exist. Concepts can form a real base, and a logical extension. Even incorrect concepts have a logical end. Consider the syllogism:
MAJOR PREMISE: all men have beards
MINOR PREMISE: I am a man
CONCLUSION: I have a beard
Now, I do not have a beard, but the logic is correct. What is the problem, then? With the major premise, of course. Let''s try another one.
MAJOR PREMISE: all men have beards
MINOR PREMISE: I have a beard
CONCLUSION: I am a man
While the conclusion is correct, the logic is not. Even if all men have beards, and I have a beard, that does not mean I am a man. (Although women do not usually have beards, and women are the only other "type" of people, those facts were not listed, so the logic is incorrect.)
Also, the major premise is incorrect, which proves that it is possible to arrive at truth with both incorrect logic and an incorrect major premise (However, the operation then has no meaning, because you have not "proved" anything. That is, the arrival at either truth or non-truth is random.)
MAJOR PREMISE: If it rains, I will go to town.
MINOR PREMISE: It did not rain.
CONCLUSION: I did not go to town.
What is incorrect with this train of thought? The conclusion is incorrect, because nothing was said about what I would do if it did not rain. The logic was invalid.
But I am digressing. Let''s do the real problem.
MAJOR PREMISE: Readability doesn''t exist in any physical form.
MINOR PREMISE: Ideas don''t exist in any physical form.
CONCLUSION: Readability is an idea.
Was that your train of thought? The conclusion is not correct because the reasoning process is invalid. That is, the major and minor premises were true, but that doesn''t mean that readability is an idea.
The fact that everyone (especially industry "experts") refer to "good" code and "bad" code implies that a standard does exist. What is rather odd is that no one seems to be able to put it down on paper or to follow it.
quote:
Original post by chippydip
The idea here is that it would be nice for a character object to not have to worry about how every single weapon/spell that they could possible have should do their damage. All the character should care about is the fact that the object can do damage (and possibly if he has the skills to use the item.)
It''s that last part that shows the misconception. It is the weapon that does not have to know anything about the user, and not the user of the weapon that does not have to know anything about the weapon. The weapon was created by a person, but as it exists it needs to know nothing about the character wielding it. Character is the controlling class, and sword is the controlled class.
The weapon could have a function to determine damage when wielded in a certain way (and a weapon may have been designed such that it can be wielded in different ways). You could include accuracy, etc. However, neither class is totally independent of each other.
It would be nice if a character could use a weapon without knowing how, but that is just not possible. It is not a real situation. There is no "abstract" weapon interface that has a button to press and it deals damage, while automatically choosing the best attack method and positioning the character''s arm, etc. (You might argue that a gun has that interface, but you had to use the word "gun," which is a type of weapon. That is, "gun" is derived from the abstract "weapon" class; not every weapon has a trigger.)
Here is what I see of the problem:
class weapon
{
public:
float get_hit_modifier() { return( hit ); }
unsigned int get_damage_modifier() { return( damage ); }
protected:
float hit;
unsigned int damage;
};
class gun : public weapon
{
public:
class ammo
{
public:
get_force() { return( force ); }
protected:
unsigned int force;
};
public:
unsigned int pull_trigger() { if( ammo_remaining ) { return( cartridge[ammo_remaining--].get_force() + damage ); } else return( 0 ); }
protected:
vector cartridge;
unsigned int ammo_remaining;
};
You see, use of the gun class requires knowledge of how to use a gun -- it cannot be transparent to the user. The character class would then take the gun class (which also has an ammo class) and call pull_trigger() to generate a force. Where the bullet (or whatever) goes and whether it hits its target is up to the user of the gun. Why did I provide the get_hit_modifier() and have it in the gun class by inheritance? Well, guns (as far as I know) will never have 100% accuracy, although they might come close. That is, the user expects 100% accuracy from a gun and must adjust his aim to compensate for the manufacturing flaws in the gun barrel. So, the user calls gun::get_hit_modifier() and applies that to his own hit value, decides on a target and adjusts his aim accordingly, and then pulls the trigger. The pull_trigger() function generates a force that is used, along with the armor value of the opponent, etc. You cannot make the gun class dependent on the armor value of the opponent, either, because guns in real life don''t know those things.
MAJOR PREMISE: The goal of OOP is to model real-life circumstances.
MINOR PREMISE: Real life circumstances will provide correct software design.
CONCLUSION: OOP ensures proper software design.
Once you have a correct model of real-life, you have captured all of the essential dependencies and interactions and relationships into one neat model, which can then be easily studied. OOP generates the "skeleton" of the program, while you fill in the blanks with the code.
quote:
Original post by chippydip
I''m not an OOP expert (as you may have guessed) but it seems like there are circumstances where you would want to implment a class with functions but no data members (basicaly an interface.) I would guess that in many (most? all?) of these cases, the class does not represent an object or other noun, but some sort or action or behavior (verb)
*laughs light-heartedly* I''m not an expert either! I learned all of this from
C++ for Dummies, 3rd Edition. Anyway, objects have actions, verbs are actions. That is, you cannot have a verb without a subject. If verbs were objects, then you would be implementing all your classes as empty classes with one function each, which is really off. Some objects (or abstract classes that are combined in different ways to create new objects) may have only one verb, but an object is an object.
Consider the naming collisions (a sure sign of bad code design) that occur when making the verb into a class:
class attack
{
public:
void attack() = 0;
};
class serialize
{
public:
void serialize() = 0;
};
You are duplicating names (not to mention writing illegal constructors), which merely take up needless space in the user''s brain. You give classes names according to their use, and functions that further describe their use. That is, a class name can only (logically) be a noun. For example, this would be the proper name for the second class:
class data
{
public:
serialize() = 0;
};
Data is serializable, but it would be meaningless to say that a serializable object is serializable. You know that just by the name, and that is all that the class can do. In other words, you would limit the class to only one function, with no data members. Rather than using multiple inheritance (unless you need it for some operation), it is better to give them similar function names for similar function purposes. That is, not every function with the same name has the same purpose, but it might be a
similar purpose. It would be wrong to use multiple inheritance to give classes the same function names for anything other than the same function purposes.
Class declarations provide a sort of description about the class. That is, you should be able to look at the class declaration and see exactly how the class should be used (if you know anything about what it models -- and this is awfully close to design by contract
).
class file
{
public:
// generic file::exception
class exception : public ::exception {};
// specific exceptions - derived from file::exception
class invalid_name : public exception {};
class file_not_found : public exception {};
class end_of_file : public exception {};
public:
file(string name) throw( invalid_name );
virtual ~file(); // auto-closes
public:
// open/close the file - must be open for read/write
void open(bool erase_contents) throw( file_not_found );
void close(); // safe
// read and write raw data
void read(void* memory, unsigned long size) throw( end_of_file );
void write(const void* memory, unsigned long size) throw( end_of_file );
protected:
// locale encoding - used by read and write
void* encode(const void* data, const unsigned long size);
void* decode(const void* data, const unsigned long size);
protected:
string name;
FILE* data;
};
You should be able to tell how the class operates from the description. Nothing but the implementation is a secret.
quote:
Original post by chippydip
To clarify, however, the "fuction" I was talking about was not the program itself, but another outside "evaluator" that determines which of two solutions is better. The inputs are some sort of rankings that determine how readable the code is, how memory efficent, how fast, etc. and outputs an overall value that can be used to compare two different solutions to the same problem.
That''s not exactly what I meant, although I might have given the wrong impression. The code is first evaluated objectively to discover the relevant variables. Also, relevant variables are taken from the problem to generate a problem domain (correct term?). The code variables are then evaluated in the problem domain. Finally, the adjusted code variables are compared to the code variables for the perfect solution (100% of everything good, or good_code) which is not always possible. (Note that best is not necessarily perfect but means "as close to perfect as can be obtained given the sitation.") These code variables (after the second adjustment) are returned, and stored for comparison with other snippets of code that also try to solve the problem. The one that has the lowest values (meaning the least difference between it and good code) is considered the best solution.
I''m not sure it is possible for several solutions to have equally good values and be equally "best." (I think you mean something like ~5,5,5,10 = ~5,10,5,5.) Certainly not when considering the problem domain! If for some reason they are, then the problem domain is not being abstracted correctly or the code variables are not accurate. (Or it is possible (though unlikely) that these things might arise from not prioritizing the different code variables, using something like a weighted average?)
You see, if you compare the solutions with each other, then you make it subjective. But if you have an objective standard, and objectively compare everything to it, then the solution will be objective.
quote:
Original post by chippydip
An example of this could very well be a sorting program. If memory is, say 10 times less important than running time, we might have two sorting algorithms, one that takes 10 seconds to sort the input, using 1000KB of memory and another which takes 100 seconds, but only 10KB of memory. Furthur assume that they are both simple algorithms so that the code is eaually readable in each case. Then I would say that these two solutions are equally good at solving the problem.
You don''t have enough variables. The case is never that simple in real life. Does the user''s machine have enough memory? What about the speed of the user''s computer? Should both methods be used under different conditions? We''ve hit it directly on the head! The best method may or may not be to use one or the other; perhaps the best method is using both under different circumstances?
I wasn''t talking specifically about these things -- I meant something more along the lines of when to use if() statements, when switch() statements are appropriate, when should I use RTTI, how should I store the data, how to model classes, etc. Things that can be solved easily by simple logic. In other words, not what to code but how to code. I think that it can be logically extended to cover everything, though.
Kylotan: I think Plutt said "it is up to the user," meaning the situation (which the user considers) determines what should be done. Anyway, Plutt might not get back to this post for a while.
-
null_pointerSabre Multimedia