Advertisement

Exceptions...

Started by April 28, 2000 07:39 AM
60 comments, last by null_pointer 24 years, 6 months ago
quote: Original post by Plutt

It''s pretty simple, an exception should be thrown if there is an error. A FileExists() function should not throw an exception if the file does not exist, it should return false, however, an OpenFile() function should throw an exception if the file doesn''t exist.


Ok... then do you consider this valid, or not?
if (FAILED(DirectDrawCreate(/* some parameters*/)))    throw DDrawException; 

After all, the name of the function implies that it -will- create the DirectDraw interface, not that it will test for the viability of such an action. However, it -does- return a useful error code, just like a ''test'' function. Is it ''wrong'' to transform that return value into an exception to handle my DDraw::Init() cleanup gracefully?
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_pointer
Sabre Multimedia
Advertisement
I am going to endeavour to keep this short. I am also going to admit defeat regarding this goal in advance

quote: Original post by null_pointer

1) Only 1 report() function needs to be written, in the base class for the entire hierarchy.

2) You are assuming that writing the classes takes more work than writing the strings, which is incorrect. See my example in the last reply.

3) How much time does it take to invent an empty class?


My mistake: I hadn''t realised you were using the type_info to do the dirty work of generating a string for each class for you I can see how that is one way of achieving what I do within the language, providing your exception class names are descriptive enough.

quote:
5) One, two and so on are not types of integers but particular instantiations of them, with one data member, value. (Note that for your exceptions example you had to use the word "type" to describe the method that you proposed, while here you did not. Check in your posts for the other times you see the word "type," and try re-evaluating those places with that idea in mind, just for a thought question.)

Right, but if I wanted to pass a number, I pass an integer. If I want to pass a message, I pass a string. A string can represent different types of error, just as different error codes in integer form can represent different types of error. I don''t think it is always best to create a whole new
type for each ''variety'' of error, especially when that particular variety will only -ever- be used in one scope.

quote:
6) In a real-world app (meaning something on the level of a commercial app), I don''t think you will run into a situation where all of the exceptions in a program can be handled in the same way.

I agree. But to make several extra classes just for the code within 1 set of braces seems overkill. Why introduce code elsewhere just to deal with a very localised case?

quote:
2) I can''t imagine a real-life situation where you would not access exceptions from outside the class in which they were declared without using return values to mimic this functionality. All you would be doing is dropping the required enforcement of the "error," as return values are hardly mandatory.

3) The header file is for declaring things; the .cpp file is for defining things. The two together form one module; not 2 separate modules. Any time you declare something in one function and use it in another, you declare it in a header file. Exceptions are no different (pun intended).

The example I gave showed a case where the exceptions had a scope and visibility of 2 blocks: the try block and the catch block. No more. If I needed to access them elsewhere, I would concede that there are better solutions. But one of the maxims in C++ is to declare things closer to where they are used, as opposed to C where you have to do it at the start of the block. Taking this along the logical progression, I won''t declare something in a header if I only need it inside 1 function.

quote:
2) Anyway, you may be making the sort algorithm faster, but it is 2x (or however many method you propose) more complex. Complexity introduces a chance for error. Why use 2 methods for exceptions when 1 method will work equally well in both situations? (The only thing REALLY limiting your use of the method I proposed is that you somehow believe that writing string descriptions is easier than writing class names as string descriptions.)

You''re contradicting yourself on the sorting algorithms. Usually one of the criteria of such an algorithm is that it works as quickly as possible. Sure, you introduce extra margin for error when you combine 2 algorithms into one, but once they work and are encapsulated, you''re done. If simplicity and a single method were all that were needed, surely bubble-sort is the way forward...?

quote:
3) More localized? Sometimes people try to substitute localization for organization. My room is like that sometimes...

I believe localisation to be an integral part of organization. Another example would be the reduction of global variables.

quote: 1) Definitions are objective. You don''t understand: logic is an objective method of taking something subjective and reconstructing the objective object that the subjective was viewing. Yes, it can certainly be made 100% objectively readable. You see? By taking the word "objective" you have immediately removed the "subjective" definition from the situation. They do not coexist in the same term at the same time. One word cannot have two different meanings, in the exact same context. A word, in a given context, has one definition. You are confusing comments with code.

Just because logic exists, does not mean everything can be qualified in an objective manner. Readability is relative to the reader. And readers are subjective by their whimsical human nature Objectively 100% readable implies everyone can read it. Perfect English is unreadable to someone who only speaks French. Which is most readable:
int function_name(int param){    // code}intFunctionName(int param){    // code} 

etc etc... this is opinion. To one person, extra white space is helpful, to another it spreads the code out too far and makes it less concise.

quote: 2) Yes, ''objective'' definitions in a dictionary are chosen by ''subjective'' humans, but it is, nonetheless, objective. It is an agreed-upon standard that expels any doubt as to the way it must be used.


If it were an agreed-upon standard, we would only ever need 1 dictionary for each language This is not the case.

quote: Tell me again how you can take the meaning of a term in a language as whatever you wish and not lose any of the communication afforded by the intended meaning?

I''m sure you can find several words with more than 1 similar yet different meanings...

Besides which, you are treating the language as some global standard. Sure, there are usually global standards for real languages, but individuals and their groups speak their own dialect. Me and my compiler have our own dialect. We understand each other.

quote: 3) You are way off with the "rearrangements" theory. C++ code is not simply "rearranged" assembly. In that case, everyone would use MASM. C++ stands for something that is not dependent upon assembly code for its meaning.

Ok, rearranged is a bad word. However, C++ was designed with system limitations in mind and can only ever accomplish the same as the underlying system''s machine code, albeit in less time and with more evident structure. This implies that a different language could manage to implement certain structures more effectively than C++, and probably some worse as a tradeoff. This means that there will not always be "maximum efficiency" in C++ just because you follow the rules of the language. Following the rules, you may get perfect C++ (which is nearly always going to be a perfect result, I concede) but this doesn''t necessarily mean the way the language was intended is perfect for all needs.

quote: Actually, I replied to it.

Now I''m not sure whether a linked list of Window* is correct. If the windows truly do not need to know the type of their parents or children, then why is the type required at load time? It must be known to create an object of the type. Or, perhaps allocators should be used? I''ll figure it out eventually. And objectively. There -is- one best solution to this problem.

Make all windows of the same type, and use a switch statement (Said 99% tongue-in-cheek, but it is actually easier for the loading. Shame it screws up any structure in the rest of the program...)

Ok, this "very reasonable and polite" man is done.
quote: Original post by chippydip

I would still say that 99% of these logic errors should be able to be prevented pre-release in which case I think using asserts is still a better answer, but there are some cases where its really impossible to ensure that nothing illogical happens during your programs execution.


Asserts are a thorny subject: many experts in the field consider them to be perfectly ok, and others consider them anathema to be avoided at all costs. Here is my subjective opinion - asserts should only be used for checking code that has no contact with ''the outside world'', for example in a private member function. The reasoning for this is that they should only be in code where -you- are responsible for calling it, and therefore can guarantee the inputs, and also are in control of both the calling function and the function with the error. No end user should ever be exposed to an assertion. But since asserts are used in code which should never go wrong, an idealist would argue that you could use either asserts or exceptions: it doesn''t matter, as that bug -has- to be gone by the time you ship.
quote: Original post by null_pointer

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.


You seem to be implying that even experts cannot agree on what is good code. If this is so, either (a) they know as much as anyone, and therefore there is no ''One True Way'', or (b) if the experts don''t know, maybe it exists but no human will ever find it

Seems to imply you''re fighting a losing battle in search for ''the truth''.

Btw, I checked out your project site, very interesting
Well, I guess I''ll start using quotes so that my posts can be really long too! Atcually just so that they are a little easier to follow. So anyway...

quote: null_pointer:

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.)


I agree that eiffel is considerable slower than C++ (15% is a figure I seem to remember from somewhere) but I think that it is definitely easier to write readable code with. I wasn''t trying to say that eiffel was faster, more reliable, etc. I was just trying to point out that there are some features which C++ does not have. Sure, it is possible to implement your own version of design by contract in C++, but it is not a language supported feature which was all I was trying to point out.

As Kylotan said,

quote: Here is my subjective opinion - asserts should only be used for checking code that has no contact with ''the outside world'', for example in a private member function.


I totally agree, but only becasue the assert macro does a poor job of implementing assertion checking. This is why I consider the assertion checking that eiffel provides to be a missing feature of C++. I challenge either of you to come up with a robust solution for implementing design by contract in C++. I''ve tried a couple things myself but have been unsuccessful, but this is something that I''d love to be proven wrong about! I think that design by contract is a very powerful methodology that can make it much easier to write correct code. The other advantage of the eiffel implementation is that checking can be set at different levels and turened off completely in the final product once everything is working correctly.

(Just as a side note, I am pretty sure that this is not the reason for eiffel''s performance loss. One of the biggest contributors is the automatic garbage collector.)

quote: null_pointer:

Just because something is not tangible does not mean that it does not exist.


True, but just because something exists does not mean that it can be measured. Most concepts are difficult or impossible to measure qualitatively. For example, there is no universal scale to measure beauty. It can be measured relatively (I can say that one thing is more beautiful than another) but relative comparisons do not always hold among different people. For example, I might think thing A is more beautiful than thing B, but you might think it is the other way around. Neither of us is wrong, because we have no shared (ie external) scale on which to base our "measurements" of beauty.

Readability of code is the same way. While it certainly exists (as does beauty) there is no universal scale to measure it by. Given two snippets of code I might think that snippet A is more readable and you might think that snippet B is more readable. Again, neither of us is wrong, we simply have differing opinons on a topic that cannot be resolved. Because of this, readability is subjective.

As a final example of Kylotan''s language idea I have a little story. When I was taking my first programming class (in Pascal) there was a Russian exchange student in our class. One of the assingments that we had regularly was to look at each other''s source code and comment on the correctness, efficency, readability, etc. This was an excellent excercise, but when it came to reading this exchange student''s code the task became much more difficult. She named all her varibles in russian so, while I''m sure it was quite clear to her what each varible was supposed to hold, I had to keep refereing back to the declarations and previous code to see what type these random strings of characters where and what values had been stored in there before. Readability really is subjective. Period.

quote: null_pointer:

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.


This is essintially what I''m talking about. If you can compare two things to a standard, then you can compare them to each other in a meaningful way.

quote: null_pointer:

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?)


I think you aren''t quite understanding what I''m getting at. As long as you can define what the theoretically best solution is (ie, no time, space, etc.) and you have some system to evaluate how close you are to the ideal (say, f(x, y, z, w)) and this function is smooth, then there will be an infinite number of possible inputs that will generate a given output value which represent "distance from perfection."

Now, remember, this function must take into account the realative weights of the different input varibles, but in order to evaluate how close to perfection a given solution is, you imply that some ruberic such as this does, in fact exist. This function can be as complex as you want, but is will have only one global minimum where the ideal solution is (this function is measuring "distance" from the ideal solution.) If f is continuous, then we can consider level sets of f which will be some subgraph of f, then we can see that there will (usually) be more than one point in this level set. In fact, as then number of input variables increases, so does the number of possible inputs that will map into a given level set of the graph of f.

Lets now consider the level set that contains a "best" solution. Obviously, not all of the points in a level set can be generated by valid inputs, but if even one other point in the "best" level set can be reached, then there are two "equally good" solutions.

Finally, I will concede that there is no way I can prove that such a second point will exist is all or even most circumstances, but similarly you cannot prove that such a point will not exist or will be unlikely to exist. This discussion then comes down to which side seems more probably and I have just tried to explain the ideas behind my view.

quote: null_pointer:

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.


I don''t think that there is always a "best" solution for these things either. Using if() or switch() is largely a readability issue. If the two are truely interchangeble in a given piece of code then most likely they will be compiled into identical code so the efficency issues become irrelevent. This leaves only readability which, as I have shown (I hope) is subjective. The only way this could be resolved is if a universal "readability" standard were developed upon which a comparision could be made. If this is not possible then, like you said, the comparision is subjective.

As to the other things that you mention, I think that these can be adequetly modeled with the above perfomance function that I described in which case it may be possible that multible alternatives exists which are equally valid solutions.

Wow! That was a long one, but I think I''m done

Check out the GPI project today!
Advertisement
quote: Original post by Kylotan

Right, but if I wanted to pass a number, I pass an integer. If I want to pass a message, I pass a string. A string can represent different types of error, just as different error codes in integer form can represent different types of error.


There goes the word "type" again! If you aren''t going to use the type of the exception (i.e., switch statements or catch() type-checking, etc.) that''s fine. But then you don''t need the word "type," do you? It would be a "description." You are confusing different types of exceptions with different descriptions of the same exception.


quote: Original post by Kylotan

I agree. But to make several extra classes just for the code within 1 set of braces seems overkill. Why introduce code elsewhere just to deal with a very localised case?


Why not throw an int then? Define some const int''s at the beginning of the function and throw them when you need to throw an exception. Or strings, if you like.


quote: Original post by Kylotan

You''re contradicting yourself on the sorting algorithms. Usually one of the criteria of such an algorithm is that it works as quickly as possible.


No, I was just pointing out your apparent contradiction.


quote: Original post by Kylotan

quote:
--------------------------------------------------------------------------------

3) More localized? Sometimes people try to substitute localization for organization. My room is like that sometimes...
--------------------------------------------------------------------------------


I believe localisation to be an integral part of organization. Another example would be the reduction of global variables.


Yes, but so is separation. Like two sides of the same coin, neither can function without the other. To make one more important than the other would be crazy...


quote: Original post by Kylotan

Just because logic exists, does not mean everything can be qualified in an objective manner. Readability is relative to the reader. And readers are subjective by their whimsical human nature Objectively 100% readable implies everyone can read it. Perfect English is unreadable to someone who only speaks French. Which is most readable:

int function_name(int param)
{
// code
}

intFunctionName(int param)
{
// code
}

etc etc... this is opinion. To one person, extra white space is helpful, to another it spreads the code out too far and makes it less concise.


I don''t seem to remember saying "everything" if objective. (Where do people get these ideas?) Also, this argument makes no real sense because it cannot possibly be evaluated objectively using the methods I listed anyway. Where is the speed difference to the code in these two methods? Is it as efficient or as optimizable as possible? I''m not talking about naming conventions and personal preferences that have absolutely no bearing on the code! In other words, those two examples are the same thing to the compiler. I''m talking about what language feature to use in what situation.


quote: Original post by Kylotan

If it were an agreed-upon standard, we would only ever need 1 dictionary for each language This is not the case.


Languages are just standards for communication.

(BTW, there are committees that decide on the language standards, meaning human languages, too. Like C++ compilers, dictionaries follow the standard as it improves.)


quote: Original post by Kylotan

Ok, rearranged is a bad word. However, C++ was designed with system limitations in mind and can only ever accomplish the same as the underlying system''s machine code, albeit in less time and with more evident structure.


Limitations give form to the language, and aren''t necessarily bad.

The more I study C++ though, the more I''m convinced that it is a much better language than its rivals. That is personal opinion though.


quote: Original post by Kylotan

Make all windows of the same type, and use a switch statement (Said 99% tongue-in-cheek, but it is actually easier for the loading. Shame it screws up any structure in the rest of the program...)


I don''t think you understand the problem. The user of my library must be able to derive his own window classes to manage his own "messages" and his own drawing code, etc. I can''t do a switch() statement for that... I''m going to have to use allocators or something very similar.


quote: Original post by Kylotan

quote:
--------------------------------------------------------------------------------
Original post by null_pointer

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.


--------------------------------------------------------------------------------


You seem to be implying that even experts cannot agree on what is good code. If this is so, either (a) they know as much as anyone, and therefore there is no ''One True Way'', or (b) if the experts don''t know, maybe it exists but no human will ever find it

Seems to imply you''re fighting a losing battle in search for ''the truth''.


1) No, as I have said in other posts, *dons titanium suit*, I see terrible examples of bad coding from the "experts." Didn''t you see that rant a while ago (there was a link on the GameDev news page) by one of "experts" in the field of programming? He said C++ virtual functions, operator overloading, RTTI, templates, etc. were USELESS! Needless to say, it was refuted quite easily by someone much less "experienced."

What makes a person a game development expert (subjective definition)? Certainly not good coding. No, what is required is to make a great game. That implies good coding, but does not require it (and there are monthly examples of bad advice by the "experts"). The only thing that is really required is a knowledge of two-bit hacks and a very supportive development team (artists, etc.). Mostly luck. As Sun Lee (sp?) used to say, "Luck is happy combination of foolish accidents."

That being the case, I would much rather turn to language experts for the "one true way" you keep talking about. The language experts seem to be quite agreed on how the language should be used. I hope to be a language expert someday...or perhaps a logician. (And just what is this "one true way"?)

2) That''s thinking inside the box, remember? (If other people didn''t discover it, what chance do we have?)


quote: Original post by Kylotan

Btw, I checked out your project site, very interesting


Is that good interesting or bad interesting?

Anyway, thanks. We are in the process of converting the source code to the STL style and also "merging" it with STL (Actually, having the library use STL and allowing the users of the library to use STL).


quote: Original post by chippydip

I agree that eiffel is considerable slower than C++ (15% is a figure I seem to remember from somewhere) but I think that it is definitely easier to write readable code with.


1) Why must readability differ from speed?

2) The words "I think..." mean a subjective view of readability, but that would not be binding on me, would it? Meaning, I could say that writing readable code is much easier with C++. (It''s your own argument -- don''t get mad at me! )


quote: Original post by chippydip

Sure, it is possible to implement your own version of design by contract in C++, but it is not a language supported feature which was all I was trying to point out.

...

...only becasue the assert macro does a poor job of implementing assertion checking. This is why I consider the assertion checking that eiffel provides to be a missing feature of C++. I challenge either of you to come up with a robust solution for implementing design by contract in C++. I''ve tried a couple things myself but have been unsuccessful, but this is something that I''d love to be proven wrong about! I think that design by contract is a very powerful methodology that can make it much easier to write correct code. The other advantage of the eiffel implementation is that checking can be set at different levels and turened off completely in the final product once everything is working correctly.

(Just as a side note, I am pretty sure that this is not the reason for eiffel''s performance loss. One of the biggest contributors is the automatic garbage collector.)


1) If it''s a slow language no matter what you do, why use it? I have never understood why people use garbage collection as it seems to me to hide bugs and waste processor time doing what the programmer should have done.

2) Seriously, I don''t understand what C++ lacks. C++ is such a logical language from the ground up, that most languages are more like customized versions of C++. That is, you can implement garbage collection if you want. You can do nearly anything that you want (so long as it is logical). This "design by contract" thing seems to be a concept that has been used by programmers for ages: responsibility. You can enforce it with exceptions, and type-checking, scope resolution, etc. There are so many tools in C++.


quote: Original post by chippydip

quote:
--------------------------------------------------------------------------------
null_pointer:

Just because something is not tangible does not mean that it does not exist.


--------------------------------------------------------------------------------


True, but just because something exists does not mean that it can be measured. Most concepts are difficult or impossible to measure qualitatively. For example, there is no universal scale to measure beauty. It can be measured relatively (I can say that one thing is more beautiful than another) but relative comparisons do not always hold among different people. For example, I might think thing A is more beautiful than thing B, but you might think it is the other way around. Neither of us is wrong, because we have no shared (ie external) scale on which to base our "measurements" of beauty.


No, beauty is purely subjective. "Beauty" (physical beauty) is only a subjective view, and is not "real" in the sense that it exists outside the perspective view. Beauty doesn''t exist in an objective form, but objective code does exist.


quote: Original post by chippydip

As a final example of Kylotan''s language idea I have a little story. When I was taking my first programming class (in Pascal) there was a Russian exchange student in our class. One of the assingments that we had regularly was to look at each other''s source code and comment on the correctness, efficency, readability, etc. This was an excellent excercise, but when it came to reading this exchange student''s code the task became much more difficult. She named all her varibles in russian so, while I''m sure it was quite clear to her what each varible was supposed to hold, I had to keep refereing back to the declarations and previous code to see what type these random strings of characters where and what values had been stored in there before. Readability really is subjective. Period.


(Must have been fun. )

Anyway, I think you are confusing subjectivity with multiple languages. Just because the Russian exchange student named her variables in Russian, does not indicate the absence of a standard, but the multiplicity of standards. If you want to understand her code, you learn Russian (a standard). Or get a Russian-to-English dictionary. However you put it, the C++ keywords (which are the meat and potatoes of my theory, so to speak) are in English and have a definite standard of their use.

English limits the C++ keywords to specific usage, but that is how humans define things. Limitations clear away the things that don''t exist to make reality more obvious. In other words, the C++ keywords, as represented by words in the English language, merely serve to eliminate perceived functionality. They do not eliminate real functionality. Further, because the language people chose to limit a certain keyword to a certain task, they would have most certainly had to think about how the tasks eliminated by the limitation of one keyword could be done by other keywords, and if the task is even logical. Most often, the last reason is why a language feature does not exist.


quote: Original post by chippydip

This is essintially what I''m talking about. If you can compare two things to a standard, then you can compare them to each other in a meaningful way.


Voila! Objectivity!

Note that comparing things to one another by means of a standard is quite different from comparing things to each other without a standard. That is the essential difference between objectivity and subjectivity; one has a standard (exists externally) and the other does not (exists only internally).


quote: Original post by chippydip

Lets now consider the level set that contains a "best" solution. Obviously, not all of the points in a level set can be generated by valid inputs, but if even one other point in the "best" level set can be reached, then there are two "equally good" solutions.


You are saying, in effect, that since it all boils down to one number, and the number will never reach the perfect number, it is possible for two "best" solutions to arise...

I would say that is highly improbable. Indeed, I would say that it is impossible, given that two "best" solutions cannot arise...or, as you call them, "equally good." Humans prioritize things -- one method will be better in a given solution, provided it is an accurate model of real life circumstances.


quote: Original post by chippydip

I don''t think that there is always a "best" solution for these things either. Using if() or switch() is largely a readability issue. If the two are truely interchangeble in a given piece of code then most likely they will be compiled into identical code so the efficency issues become irrelevent. This leaves only readability which, as I have shown (I hope) is subjective. The only way this could be resolved is if a universal "readability" standard were developed upon which a comparision could be made. If this is not possible then, like you said, the comparision is subjective.


1) Universal readability standard: English

2) Think about it: if readability was purely subjective, then it would be truly useless.


WOW! All these long posts without editing...are we good or what?


- null_pointer
Sabre Multimedia
quote: Original post by null_pointer

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.)

You see, use of the gun class requires knowledge of how to use a gun -- it cannot be transparent to the user.



You''re designing the data model incorrectly; while in real life you need to know pretty much everything about a certain weapon before using it, but in a game, using an objectified approach, you can use abstractions to correctly model the solution. These abstractions don''t need to model real life at all. (Since we''re dealing w/ the C++ Standard here, take a look at how streams and iterators were adapted to coexist with each other.)

Weapons, in general, have several traits: they can be equipped, they deal damage, they have accuracy modifiers, and they alter the current appearance and reaction of the equipping character. All these traits can be expressed in a base class, with the derived classes providing specific functionality.

quote: Original post by null_pointer


    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.




This is blatantly incorrect. Object oriented programming is not designed to model real life; it is a paradigm that treats the problem domain as a set of objects that interact with each other, where an object is a collection of data that can respond to messages. While objects tend to coincide with how people generally view the world, they do not have to model the real world AT ALL.

null, while your philosophical approach to software engineering is admirable, you have to realize that, in the end, it is engineering, not philosophy, and as such needs to be more strongly grounded in reality. Waxing philosophical is nice, but you have been missing out on the basic tenets of programming in general. Real life and software life are two completely different realms.

MSN
quote: null_pointer:

We are in the process of converting the source code to the STL style and also "merging" it with STL (Actually, having the library use STL and allowing the users of the library to use STL).


Cool, that was something I was wondering about when I checked out your site... why provide an array class and a string class when there are already standard tools to handle these things? I''m glad to see you are making the switch

quote: null_pointer:

1) Why must readability differ from speed?

2) The words "I think..." mean a subjective view of readability, but that would not be binding on me, would it? Meaning, I could say that writing readable code is much easier with C++. (It''s your own argument -- don''t get mad at me! )


1) Readability and speed are not necessarily different, but they are not directly related. Indirectly they have an effect on each other, though. For example, ASM (if used properly) will produce the fastest code possible. C++ will be a bit slower, but for that price you get a language that it more highly abstracted from the underlying hardware and, therefore, more readable (by most peoples accounts.) As a general rule of thumb, readability and speed are inversly proportial across different languages. Within a single language specification readibility is corolated even less with speed. Sometimes readable code will be faster and sometimes slower than less readable code.

The issue to consider here is that what gives you speed within a language is essentially readability by the compiler. The better a compiler can guess what you mean to do, then the more it will be able to optimize the asemply code it generates. This translation process is what caused the performance degredation in higher level languages in the first place.

2) Right on! Can''t argue with the logic there

quote: null_pointer:

2) Seriously, I don''t understand what C++ lacks. C++ is such a logical language from the ground up, that most languages are more like customized versions of C++. That is, you can implement garbage collection if you want. You can do nearly anything that you want (so long as it is logical). This "design by contract" thing seems to be a concept that has been used by programmers for ages: responsibility. You can enforce it with exceptions, and type-checking, scope resolution, etc. There are so many tools in C++.


C++ doesn''t fundamentally lack much in the way of fundamental features. (It is missing at least one thing that can be done is ASM, a bit rotation...) Anyway, the point is that you have to implement tools for handling things that the language doesn''t directly support. Sure garbage collection can be implemented in C++, but the fact is it HAS to be implemented, it is not already there to be used. The same is true of design by contract: you can implement a system to enforce the resposibility of functions and classes, but that is extra design and implementational work that you have to do in C++ that has already been done for you in other languages.

Which is better? That''s really a personal choice. You have to decide how much speed you are willing to give up in return for extra features so you don''t have to do as much work. That''s why there are a range of languages. If you need lots of speed, you use ASM. If you need a highly abstracted language you use something else, if you want the middle ground, then you use C++ or something similar.

quote: null_pointer:

No, beauty is purely subjective. "Beauty" (physical beauty) is only a subjective view, and is not "real" in the sense that it exists outside the perspective view. Beauty doesn''t exist in an objective form, but objective code does exist.


I should have been clearer. I was thinking more along the lines of a painting, piece of music, or other art form. These all exist in some physical form, yet the evaluation of thier beauty it completely subjective. The same is true of computer code. It exists in a physical form, yet its interpretation as "readable" is purely subjective. The biggest difference between these two examples is that programmer''s views of readability are generally much closer than artists'' or musicians'' views of how aesthetic their respective arts are. Despite this pseudo-standard view of readability, there is still no definite, external, standard so readability still remains subjective.

quote: null_pointer:

Note that comparing things to one another by means of a standard is quite different from comparing things to each other without a standard. That is the essential difference between objectivity and subjectivity; one has a standard (exists externally) and the other does not (exists only internally).


Exactly!

quote: null_pointer:

I would say that is highly improbable. Indeed, I would say that it is impossible, given that two "best" solutions cannot arise...or, as you call them, "equally good." Humans prioritize things -- one method will be better in a given solution, provided it is an accurate model of real life circumstances.


Humans do prioritize things, but that is what the function is for. The function should be designed so that these priorities are accounted for. If you can''t quantify your evaluation criteria, then they are no longer objective and have crossed over into the realm of subjectivity. As long as these preferences can be quantified, however, they can be worked into the evaluation function so that the final value is a definitive and meaningful representation of how good an algorithm is.

Like I said, however, once you have this function, the probability that two "best" solutions exist is really a subjective evaluation. I think that it is quite possible and you think that its nearly impossible.

quote: null_pointer:

2) Think about it: if readability was purely subjective, then it would be truly useless.


Sort of. If everyone had a different idea of what made readable code then the idea would be truly useless. Programmers in general tend to have similar (but not identical) views of what makes readable code. This makes it useful to aspire to generally readable code, but there is no exterior standard which can be used to say that one coding style is more readable than another. The final judgement is subjective.

Check out the GPI project today!
quote: Original post by null_pointer

Original post by Kylotan

Right, but if I wanted to pass a number, I pass an integer. If I want to pass a message, I pass a string. A string can represent different types of error, just as different error codes in integer form can represent different types of error.


There goes the word "type" again! If you aren''t going to use the type of the exception (i.e., switch statements or catch() type-checking, etc.) that''s fine. But then you don''t need the word "type," do you? It would be a "description." You are confusing different types of exceptions with different descriptions of the same exception.

You are using my labels to enforce definition again Just because you use a language construct only as it exactly matches the name, doesn''t mean I will, -especially- not when using English

To someone looking at my little error-catching code, they see several calls to functions and would be justified in saying "each function indicates a different type of error". But all I care about in this example is knowing which one, and so I can throw a string.

I must point out here that when I refer to my original example, I was just throwing a string, and not ever reading that string to make any decisions based on it.

The alternative model, a single Exception class with a string parameter, was something I proposed for argument''s sake. You could give it 2 parameters, 1 for the function-name that threw the exception, and 1 for the error message. RTTI could give you the error message, given explicit and long-winded enough typenames, but it won''t give you the function in which it was thrown. So you need 1 parameter anyway, may as well have 2. If, in your design you never need to execute conditional code based on the nature of exceptions you catch, a hierarchy is overkill.

I am not saying a hierarchical system of exceptions is bad, wrong, or anything like that. But I am saying that, given certain knowledge about one''s design, a much simpler solution would suffice. Most of my small programs don''t need any kind of ''special'' exception handling except to say "An error happened here."



quote: Yes, but so is separation. Like two sides of the same coin, neither can function without the other. To make one more important than the other would be crazy…

Use the right tool for the job Separate things that should be abstracted from each other. And ''types'' or variables that you will only need in one function, should be declared in that function, or as close to it as possible.

On that note, C++ lacks local functions. This could perhaps be considered a deficiency in the language. You can simulate them with private members, but then any other member could call that function when it makes no sense to do so. You could also simulate them with objects having an overloaded operator(), but that doesn''t seem right either.

quote: (BTW, there are committees that decide on the language standards, meaning human languages, too. Like C++ compilers, dictionaries follow the standard as it improves.)

Doesn''t matter: the average person doesn''t speak any kind of standardised language, nor will they ever. And dictionary writers tend to have their own committees and researchers, producing different definitions for the same word.

quote: The more I study C++ though, the more I''m convinced that it is a much better language than its rivals. That is personal opinion though.


See Why C++ Sucks for an alternative view.

quote:
Original post by Kylotan

Make all windows of the same type, and use a switch statement (Said 99% tongue-in-cheek, but it is actually easier for the loading. Shame it screws up any structure in the rest of the program…)


I don''t think you understand the problem. The user of my library must be able to derive his own window classes to manage his own "messages" and his own drawing code, etc. I can''t do a switch() statement for that… I''m going to have to use allocators or something very similar.
Right, sorry. I was more referring to a hierarchy which is entirely under your control, like the one I am using. Although, is there anything to stop the use of a switch to call virtual functions (which may have to be overriden by further switches in user code)? Ugly.

quote:
Original post by Kylotan

Btw, I checked out your project site, very interesting


Is that good interesting or bad interesting?

Seems like a worthy project. If I had any measurable amount of free time I''d offer to help with anything but the exception code

quote: Anyway, thanks. We are in the process of converting the source code to the STL style and also "merging" it with STL (Actually, having the library use STL and allowing the users of the library to use STL).

Allowing STL algorithms to be used on your containers, etc? (Sorry if you don''t have any containers, my memory is bad )

Even just having an STL style interface is good as it cuts down the learning curve. Learn 2 tools for the price of 1.


quote:
1) If it''s a slow language no matter what you do, why use it? I have never understood why people use garbage collection as it seems to me to hide bugs and waste processor time doing what the programmer should have done.


Interesting viewpoint… you say to use typechecking, which allows the compiler to do checks for us, rather than needing to use switch statements or string comparisons… and I agree. But garbage collection is built on a similar premise… tell the system when you need memory, and let it worry about checking whether it is still needed or not. The same goes for auto_ptr as mentioned in the other thread. It''s about standardising (your favourite process ) the access to a certain system, process or routine and minimising the interface to reduce the chance of programmer error. Having to remember an explicit ''delete'' to match each ''new'' is a source of many bugs and memory leaks. I would agree that if a C++ programmer moved to a garbage-collected language, then yes, they would introduce hidden bugs, but only because they don''t really appreciate how the allocation model works. Once you have it mastered in your head, it is cleaner. (Quicker/more efficient? That''s another story. Choose the right tool for the job. )

quote: This "design by contract" thing seems to be a concept that has been used by programmers for ages: responsibility. You can enforce it with exceptions, and type-checking, scope resolution, etc. There are so many tools in C++.

*gasp* You''re not suggesting that a single feature can be implemented in numerous different ways, are you?

Design by contract is a standardised way of removing errors from your code. It reduces flexibility compared to C++, but does its job well.

quote: WOW! All these long posts without editing…are we good or what?


Oh, there are probably hundreds of typos in my message, I just can''t be bothered to check. It takes long enough to read the replies, never mind my mini-essays as well

This topic is closed to new replies.

Advertisement