Advertisement

Exceptions...

Started by April 28, 2000 07:39 AM
60 comments, last by null_pointer 24 years, 6 months ago
Well, considering you opened this topic with "does anyone have an idea about how to use exceptions?" and now you are attempting to tell me the ''right'' way to use them, I am glad I have spurred you into thinking all this through, if nothing else.

quote: Original post by null_pointer

First, you did use strings to replace type-checking, whether you meant it or not (and BTW no one every really means to replace a language feature, unless they''re going slightly screwy. )


My exceptions only served one purpose: to show a message. No other operation differed based on the ''type'' of exception. Therefore, it made sense for there to be only one type with several possible values. Why invent a different class for each message? At no point was I ever doing any conditional branching based on that message. Saying there -needs- to be a separate class for each message is like saying that you shouldn''t use integers, and instead derive class One : public digit {}, class Two : public digit {} and so on! It certainly doesn''t involve any more work than it would to write all these separate virtual report() functions.

quote: How is that not simple? In fact, it is much simpler to keep track of, even if you are both throwing and catching the exceptions yourself.


I will concede that it scales much better to a larger project. But I was supplying a use of exceptions in a localised way that (a) doesn''t require any kind of hierarchy to produce the logically correct response, and (b) produces that response whether the events it reacts to were ''exceptional'' or not. The code I produced was isolated from any outside module, and therefore keeping track of it here is -easier-, as to create specific exception types for this one function would split the routine across more than one file (probably this CPP file and the accompanying H file).


quote: (Note also that they are not catch handlers but catch statements; that means that more than one catch statement may be necessary to handle different parts of an exception. Stop being subjective with the language and start using the definitions provided with it.)


I''m not being wilfully subjective: I apologize for any error in my terminology, however I do not have a ''Book Of C++ Definitions'' handy...

quote: The only thing you accomplished was a work-around for type-checking. You didn''t eliminate any code. You didn''t make it any easier to read.


I believe that, for the example given, my solution was more concise and more localised. I do not believe it scales as well as your solution. I liken this to the way a lot of sort algorithms work: if the data set is smaller than a certain size, use Method X, otherwise, use Method Y. There is not a ''best'' way for all situations unless you count the algorithm encompassing that choice to be the best. In my case, I would choose a simple string-based system for small and localised cases, and a hierarchy with a virtual method returninga string in larger cases, as you have shown.

quote: Readability is, by nature, subjective? No, it has two different definitions: the objective and the subjective. The definition used depends solely on the purpose of the atecedent. If that purpose is solely for proper communication, then the objective definition is used: "that can be read; legible", and if that purpose is for emotional or psychological benefit, then the subjective definition is used: "easy or pleasant to read; interesting: Treasure Island is a very readable story. " A term can have only one definition in a given context.

By your ''objective'' definition, all code is perfectly readable. However, the reader of the code is never 100%objective and never can be, therefore the point is irrelevant: code cannot always be made 100% objectively readable.

Aside: so-called ''objective'' definitions in a dictionary are chosen by subjective humans, too.

quote:
I would like to point out that the language is already given. You are not given the chance to re-define it. You were not asked how it should be when it was made. It is there, and if you wish to use it, if you wish to communicate with the computer, you must use the definitions given.


There is often more than 1 way to say effectively the same thing, whether in English or in C++.

quote:
Of course there isn''t a specific design for anything! If there was, C++ wouldn''t be flexible! The C++ language is just a set of tools -- and tools, when used according to the way they were designed, will achieve maximum efficiency. That is precisely why I asked whether there is a tool missing in the language.

Are there tools missing from x86 assembly? If so, then whatever C++ provides on top by way of re-arranging that assembly, another language could provide more or better tools. Just because I don''t know of those tools due to my inexperience, doesn''t mean they don''t exist. Maybe you can tell me what a closure is, for instance. I know other languages have them and C++ doesn''t, natively. Or local functions, which you have to work around with either a private function or a function object. If you would say there are no tools missing from x86 assembly, then all tools are merely rearrangements of other tools: and therefore rearranging C++ to suit my needs would be just as valid as the existence of the language itself...

quote:
There is only one thing I can think of: RTTI should be extended so that it allows creation of objects from a stored type_info object. Or, perhaps just one of the strings from the type_info object.

Yeah, is there no way of doing something like this?
CloneAnything(BaseObject theObj){    type_info type = typeof(theObj);    AddToCloneList(new type);} 

I don''t think there is, but you can do it in UnrealScript, for instance.

quote: But how can it read in the proper classes, even if the user derived some new classes? It would only re-create Window objects, not the derived objects. So, because of this problem, it is not possible to load a GUI from disk, except to create your own "version" of RTTI for the task. But that shouldn''t be. That is why I think the language needs extended in that direction. RTTI is certainly not the solution to every problem, but in that particular problem it would be a life-saver.

Did you see my plea for help on almost exactly this same subject elsewhere in this forum?

quote: Yes, there should be a better method, or at least allow both modes. I think the video memory architecture is tied down by old standards, and should not require exclusive access to function at a reasonable speed. What is a multi-tasking OS good for if you are not going to allow other programs to function while your program is running?

I think this is the difference between a single-user multi-tasking OS and a multi-user multi-tasking OS. UNIX has to cater for all users at the same time, whereas a single-user OS should be at the discretion of the user: if they want to consume all resources, they should have that option, if possible.

Having said that, the whole issue of memory architecture is a bit irrelevant as although an OS could simulate multiple accesses, there can only really be one flow of electrons into any circuit at any one time. The exclusive access is just enforcing this at a higher level.

quote:
Since I''m finding that I have to explain, in every reply, the method of exception handling that I would like to use in my library, I am going to show exactly how it works.

That''s exactly how I do my program. Except I could catch the string in main() and then add catch handlers to trace it back up
WOW! Finally I can reply... this is quite a long thread you guys have going to try and wade through in one sitting, but anyway.

I thought of several things while reading it and I hope that I can remember most of them.

First, I would argue that you aren''t using the exceptions at all in the way that they are intended to be used. When an exception in thrown it signifies that something about your operating environment is not ideal (ie, out of memory, currupted file, whatever) but you seem to be implementing them to cover situations that should NEVER occur during the program''s execution. Your exceptions signal a problem with the programmer''s logic in writing the program, not an unexpected operating state. I would suggest that instead of using these exceptions to help teach programmers how to use your library that you enforce a precondition/postcondition/invariant checking system within your library. This can be done with asserts or some other method that you devise to point the programmer in the right direction to fix his errant ways. This assertion checking should be able to be turned off in the final release build since none of these usage errors should be present in the final code.

If you are looking for a programming feature that C++ does not support, then I would present the assertion checking just described. There are no builtin language features which correctly and robustly handle assertion checking and handling. If you are interested in the way that this should be done you can check out the Eiffel programming language (www.eiffel.com) for and example of how this is done.

Next, I would just like to comment on the way you defined the different parts of OOP. You said that nouns were represented by classes, verbs were represented by functions, etc... This is an overgeneraliaztion. A verb can very easily be implemented as a class. Its a special type of class, however, called an interface. For example, I could have an Attack class with a method DoDamage(). Now, if I wanted to have a Sword class and a Spell class which can both be used to attack I can simply inherit the interface. Now I can DoDamage() with either a Sword or a Spell.

I must comment also on your use of logic. I have a friend who argues much like you do and as I read this post I began to think that you just might be a Vulcan Logic is a wonderful tool, but it is just that, a tool. Nothing more, nothing less. It is a very powerful tool in many cases, but it can be abused if one tries to force its application in areas where its uses is not necessarily helpful. What I find often happens is that some people begin to use logic for some valid purpose but then they just can''t stop to take a step back at the bigger picture becasue they are so engrosed in proving or disproving minucia. The other thing that I''ve come to realize is that there probably isn''t much I can do to provide a convicing argument about that fact that some times logic isn''t the best tool since doing that would require using logic to show that logic is not useful. (I know, I know... there are circular arguments and illogical statements all over that explaination, but I don''t think there is any way of getting aroud them so you will either have to just try and take a step back to understand the point I''m driving at or just leave it alone and continue as if I had never said any of this.)

Finally, I would also like to point out that your argument against 2 equally good solutions (instead of a best solution) existing is incorrect. You assume that, when given some set of inputs which completely describe a given solution to a problem, these inputs can be plugged into some function which will generate a "goodness" value for the given implementation. Ignoring subjuctivity, I would agree with this fact, but what you fail to notice is that it is quite possible for this function to take on equal values given completely different sets of inputs. You seem to be arguing, however, that given a large set of variables, it would be unlikely that the values would be the same, but this implies that you are assuming that the inputs must be the same as well (not what you meant). The inputs, however, will likely vary quite greatly and, therefore, the more inputs you have, the more likely the variations will cancel each other out. This implies that as project size grows, so does the number of equaly good solutions. As an example, consider a system where all that matters are speed and space. If one algorithm take a certain amout of time and space and the other takes 1/2 the time, but twice the space (assuming space and time are equally valuable... you may scale acordingly, however) then both solutions will be equally valid for the given problem.

Well, I guess that''s enough for one post (its getting quite late... er, early now I guess ) This is quite an interesting dicussion, though and I hope that I didn''t come accross as being overly argumentative.

Goodnight
--Chip

Check out the GPI project today!
Advertisement
Although I seem to agree with you on 90% of what you said, one part of it doesn't ring true...

quote: Original post by chippydip

First, I would argue that you aren't using the exceptions at all in the way that they are intended to be used. When an exception in thrown it signifies that something about your operating environment is not ideal (ie, out of memory, currupted file, whatever) but you seem to be implementing them to cover situations that should NEVER occur during the program's execution. Your exceptions signal a problem with the programmer's logic in writing the program, not an unexpected operating state. I would suggest that instead of using these exceptions to help teach programmers how to use your library that you enforce a precondition/postcondition/invariant checking system within your library.


As you may have seen from my previous posts, I don't believe in not doing something just because someone else didn't want it doing that way

But there is another flaw in your argument: many parts of the standard library throw 'out of range' errors when you fail to access an element of a container class. This is part of the -standard- language distribution, and if one cannot take that as an indication of how the language 'should' be used, what can you take?

Therefore I feel justified in using exceptions to handle logic errors as an alternative to assert(), as well as to provide a common exit point from a function, call all relevant destructors, etc.

Edited by - Kylotan on 5/5/00 2:26:52 PM
I''ve read through all this post - thanks for all your views on exceptions guys.

Reading it, I find myself smiling because I think of two very reasonable and polite men sitting down trying to have an argument without offending or disagreeing with each other.

One thing that did bother me was some of null_pointer''s comments about logic.
A view of logic is relative - saying there is only one logical solution I find myself disagreeing with.
Take this example, it''s a bad and illegal one, but I can''t think straight right now, QC signup is clouding my mind.

You don''t have a game. You want it.
Solution A: Buy it.
Solution B: Warez it.

You could argue that solution A is correct because it does not break the law. People without the money would argue differently.
what I''m trying to say is that logic can be relative.

It''s all crap in the end - I don''t know what I''m saying

Take it easy,

-Mezz
About the exception thing (don''t wanna touch the logic ) I think null_pointer is correct. This method with inherited exception classes is used in both the Borland VCL and the Java API.

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. Then it''s up to the user to decide if he should check if the file exists before opening it, or try to open it and catch a File::FileNotFound exception. That seems logical to me

/Pelle
Also member of Sabre Multimedia
quote: Original post by Kylotan

Well, considering you opened this topic with "does anyone have an idea about how to use exceptions?" and now you are attempting to tell me the 'right' way to use them, I am glad I have spurred you into thinking all this through, if nothing else.


Happens to me quite a bit...can't figure out why, though. I think it is because these debates make me think out the gray areas in my theories, and logically evaluate them. (There, I just did it again! To ask the question is to answer it. )

Anyway, I've done a lot of thinking about this (meaning about 5-6 hours per day, since the original post), so I wouldn't be so surprised if I had actually come up with something. At least something more than daily headaches... Anyway, I was mainly looking for intelligent conversation and not just "screw you!" or something similarly irrational. Thanks!

(BTW, I did solve several problems that I had with my theories from the original post )



quote: Original post by Kylotan

My exceptions only served one purpose: to show a message. No other operation differed based on the 'type' of exception. Therefore, it made sense for there to be only one type with several possible values. Why invent a different class for each message? At no point was I ever doing any conditional branching based on that message. Saying there -needs- to be a separate class for each message is like saying that you shouldn't use integers, and instead derive class One : public digit {}, class Two : public digit {} and so on! It certainly doesn't involve any more work than it would to write all these separate virtual report() functions.


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?

4) What if you need to do conditional branching at some point? You must then adopt another method for doing exceptions, as the two methods are not compatible. (also, you did use conditional branching earlier to justify the method you proposed)

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

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.


quote: Original post by Kylotan

I will concede that it scales much better to a larger project. But I was supplying a use of exceptions in a localised way that (a) doesn't require any kind of hierarchy to produce the logically correct response, and (b) produces that response whether the events it reacts to were 'exceptional' or not. The code I produced was isolated from any outside module, and therefore keeping track of it here is -easier-, as to create specific exception types for this one function would split the routine across more than one file (probably this CPP file and the accompanying H file).


1) There is no need of scaling to a smaller project, as that is where it starts (one class). The number of classes needed is directly proportional to the number of exceptions needed, with the ratio being 1:1.

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


quote: Original post by Kylotan

I'm not being wilfully subjective: I apologize for any error in my terminology, however I do not have a 'Book Of C++ Definitions' handy...


Just a dictionary will do fine. C++ keywords were given English names to accurately and fully describe what they do. The only reference work that I used in this post to prove anything was a dictionary.


quote: Original post by Kylotan

I believe that, for the example given, my solution was more concise and more localised. I do not believe it scales as well as your solution. I liken this to the way a lot of sort algorithms work: if the data set is smaller than a certain size, use Method X, otherwise, use Method Y.


1) Simpler is better, remember?

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

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


quote: Original post by Kylotan

By your 'objective' definition, all code is perfectly readable. However, the reader of the code is never 100%objective and never can be, therefore the point is irrelevant: code cannot always be made 100% objectively readable.

Aside: so-called 'objective' definitions in a dictionary are chosen by subjective humans, too.


So, everything is both relative and subjective? We should all let each other alone and just do our own coding styles? LOL Where do you get "learning" in that model? Vague goals do nothing...

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.

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 you wish to use a standard, use it correctly or you will only disrupt the communication that standard affords.


    Objective - 1. Existing in a concrete or observable form; material: Physics deals with objective material. 2. Real; actual: objective facts. 3. Not influenced by emotion or prejudice; impartial: an objective account of a revolution.

    Subjective - Existing within the mind or perception of an individual and not capable of being observed or experienced by someone else.


Code is objective.

3) Not all code is equally objectively readable because not all code uses the terms by their definitions. Your bit-shifting versus multiplication/division is like that. It uses proper syntax, to be sure, but it ignores the purpose of the code.


    Definition - A statement of the precise meaning or meanings of a word, phrase, etc.

    Meaning - 1. That which something, as a word or sentence, means or signifies: Look up the meaning of the word "beauty" in your dictionary. 2. That which something intends to show, convey, or indicate: What was the meaning of that remark?

    Mean - 1. To have the sense of; signify: Do you know what the word "beauty" means? Your dicionary tells you what words mean. 2. To act as a symbol of; represent: In his poems the budding flower means youth. 3. To be likely to result in; be attended by. 4. To bring about or to have as a consequence. 5. To intend to convey or indicate. 6. To have as a purpose or intention. 7. To intend or design for a certain purpose or end. 8. To be of a specified importance.


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?


quote: Original post by Kylotan

There is often more than 1 way to say effectively the same thing, whether in English or in C++.


1) Of course. But the problem is how similar are they? Is one better? I say yes; you say no.

2) Show me a situation where two methods say the EXACT same thing, and I will show you an error in your reasoning. One way will always be more efficient and more readable, because two terms in the C++ language will not have the same definitions (unless they exist for compatibility, in which case the newer term would be more readable).


quote: Original post by Kylotan

Are there tools missing from x86 assembly? If so, then whatever C++ provides on top by way of re-arranging that assembly, another language could provide more or better tools. Just because I don't know of those tools due to my inexperience, doesn't mean they don't exist. Maybe you can tell me what a closure is, for instance. I know other languages have them and C++ doesn't, natively. Or local functions, which you have to work around with either a private function or a function object. If you would say there are no tools missing from x86 assembly, then all tools are merely rearrangements of other tools: and therefore rearranging C++ to suit my needs would be just as valid as the existence of the language itself...


1) See statement in previous reply:

"In other words, I would estimate that: the case of not using the language correctly exists 99% of the time, and the case of trying to do something not covered in the language exists 1% or less of the time. Although many cases appear to be of the second type, they are really of the first type through the ignorance of the programmer."

2) I do not know what a closure is, so please tell me. However, I have not seen a piece of code where you were actually inventing something new, and you say that you do not know of any tool that is missing. You do believe they exist. And that is fine. However, beliefs cannot disprove anything in and of themselves, so I will continue on in my belief.

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.

4) How can you think outside the box if you don't even know what the boundaries of the box are?

(I probably have less experience than you do about most topics, except perhaps code design which is more or less a hobby with me. I would also like to withdraw the statement about using RTTI to new() "unknown" classes, as it doesn't make much sense now that I examine it. Again, instead of hitting the "limits of the language" I have hit the limits of my own logic. Only when you realize your limits is it possible to expand them. )


quote: Original post by Kylotan

Did you see my plea for help on almost exactly this same subject elsewhere in this forum?


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.


quote: Original post by Kylotan

That's exactly how I do my program. Except I could catch the string in main() and then add catch handlers to trace it back up


That's how I do mine too! What a coincidence! Except that I could catch the description in main() and then add catch handlers to trace it back up... Maybe you ought to try something like that, too?


quote: Original post by chippydip

First, I would argue that you aren't using the exceptions at all in the way that they are intended to be used. When an exception in thrown it signifies that something about your operating environment is not ideal (ie, out of memory, currupted file, whatever) but you seem to be implementing them to cover situations that should NEVER occur during the program's execution. Your exceptions signal a problem with the programmer's logic in writing the program, not an unexpected operating state. I would suggest that instead of using these exceptions to help teach programmers how to use your library that you enforce a precondition/postcondition/invariant checking system within your library. This can be done with asserts or some other method that you devise to point the programmer in the right direction to fix his errant ways. This assertion checking should be able to be turned off in the final release build since none of these usage errors should be present in the final code.


1) A user's logic flaw means an invalid operating state for my library, which means an invalid operating environment for the user.

2) Ideally, exceptions should not occur. Therefore all exceptions are invalid?

3) How is a precondition/postcondition/invariant checking system different from what I am doing?

4) Assertions are merely a bad form of exceptions.

Check out STL, and Bjarne Stroustrop's (he's the creator of C++) appendix on exceptions (URL: http://www.research.att.com/~bs/). Exceptions are meant to enforce correct handling of exceptional conditions between layers of software. An exceptional condition results when a class is not used properly, for example.


quote: Original post by chippydip

If you are looking for a programming feature that C++ does not support, then I would present the assertion checking just described.


// one way
if( condition ) throw exception;

// another way
assert()

You cannot stop the debugger at the point of the exception by a C++ keyword; however, I do not consider that good coding (or indeed at all necessary) as it makes the user wade through the source code in another layer of software instead of looking things up in the docs. Assertions are just another type of exception, and they are incorrect in stopping the code execution and throwing the class implementation at the user. They provide no mechanism for safe cleanup, and that is totally unacceptable. They merely freeze the problem in time. Progress is moving in the right direction, even if it involves moving backwards or sideways a little first to go forward in the future. Assertions make no progress towards solving the problem.


quote: Original post by chippydip

Next, I would just like to comment on the way you defined the different parts of OOP. You said that nouns were represented by classes, verbs were represented by functions, etc... This is an overgeneraliaztion. A verb can very easily be implemented as a class. Its a special type of class, however, called an interface. For example, I could have an Attack class with a method DoDamage(). Now, if I wanted to have a Sword class and a Spell class which can both be used to attack I can simply inherit the interface. Now I can DoDamage() with either a Sword or a Spell.


Look up verbals in any high school level (and probably lower) english grammar book. Words can easily be different parts of speech in different contexts. Attack() is a verb and is one function. It is required to: do damage, inflict status ailments, etc. Swords and spells are used by the character to attack. The sword or spell does not just decide to attack. In other words, that capability to attack is a method of the character. You can use a sword to attack, but (so far as I know) swords have arributes (data members), like sharpness, rigidity, etc. and cannot attack on their own. You are simply incorrectly modeling the character class, and it has carried over into the other classes that must be formed to compensate for the flaws in the model.

If I may, can you send me your source for those classes (stripped down to remove all but the order of the calls and general descriptions of the functions, if you like)?


quote: Original post by chippydip

I must comment also on your use of logic. I have a friend who argues much like you do and as I read this post I began to think that you just might be a Vulcan Logic is a wonderful tool, but it is just that, a tool. Nothing more, nothing less. It is a very powerful tool in many cases, but it can be abused if one tries to force its application in areas where its uses is not necessarily helpful.


"in areas where its use is not necessarily helpful." I don't know where you get the idea that individuality has something to do with the best code. Why are you introducing subjectivity into an area where it does absolutely nothing, and then making it into some kind of standard of good code and bad code?

The individuality of the programmer does not serve to create better code. It has nothing to do with how fast a particular block of code executes, whether it has memory leaks, etc. If I write the same exact code while having a different attitude, it will not make the code any faster or slower. Moreover, I simply cannot change the meaning of any keyword to suit my particular "style." Individuality is utterly lost on computers, and in a computer language you are talking to (surprise!) computers. Labeling a coding "style" under individuality merely removes it from debate. You do not want other people reviewing or saying how you should code anything; that is understandable at first, but eventually you will realize that you are protecting something that either: 1) is not even yours, or 2) doesn't even exist.

You can, however, add in comments in your own particular style, if you wish, as comments are not code, but instead the interpretation of it by the individual. Comments supply the only useful individuality to the language.


quote: Original post by chippydip

The other thing that I've come to realize is that there probably isn't much I can do to provide a convicing argument about that fact that some times logic isn't the best tool since doing that would require using logic to show that logic is not useful. (I know, I know... there are circular arguments and illogical statements all over that explaination, but I don't think there is any way of getting aroud them so you will either have to just try and take a step back to understand the point I'm driving at or just leave it alone and continue as if I had never said any of this.)


Actually, there isn't anything logically wrong with what you said: you used two different definitions of the word logic, so it was like two totally different words, which means no circular reasoning. It would be illogical to extend logic past its logical purpose. (pop quiz: write a paragraph explaining that sentence.)

I'm not so "Vulcan-like" normally; just when the situation warrants that approach. I do enjoy poetry, music, games (of course! ) etc. Life would be as meaningless without subjectivity as without objectivity.


quote: Original post by chippydip

Finally, I would also like to point out that your argument against 2 equally good solutions (instead of a best solution) existing is incorrect. You assume that, when given some set of inputs which completely describe a given solution to a problem, these inputs can be plugged into some function which will generate a "goodness" value for the given implementation. Ignoring subjuctivity, I would agree with this fact, but what you fail to notice is that it is quite possible for this function to take on equal values given completely different sets of inputs. You seem to be arguing, however, that given a large set of variables, it would be unlikely that the values would be the same, but this implies that you are assuming that the inputs must be the same as well (not what you meant). The inputs, however, will likely vary quite greatly and, therefore, the more inputs you have, the more likely the variations will cancel each other out. This implies that as project size grows, so does the number of equaly good solutions. As an example, consider a system where all that matters are speed and space. If one algorithm take a certain amout of time and space and the other takes 1/2 the time, but twice the space (assuming space and time are equally valuable... you may scale acordingly, however) then both solutions will be equally valid for the given problem.


Hmm...you had to oversimplify your example of adding more variables to get it to work.

1) Differences in probability do not cancel each other out but instead increase exponentially the chance of a particular unique solution occuring. Let's examine that a bit closer. If I have 10 functions existing in my program, between 0 and 10 of them are correct. If I add 10 more functions, between 0 and 20 of them are correct. You see, the middle range seems more probable, but only because it is much bigger (5-15). That doesn't decrease the probabability of it being either good code or bad code. Ratio of the range of good code to medium code to bad code is 5:10:5, which is the same as 2.5:5:2.5, which is the same as 1:2:1. Now, how do they cancel each other out? We could add 980 functions to that model, bringing the total to a nice round 1,000 functions, and the ratio is 250:500:250, or 1:2:1 also. You saw the increase in the middle range, but didn't see the relatively equivalent increases in the high and low ranges. That is, you have no more chance at arriving at a middle range program by merely adding more functions.

2) You made some big assumptions in your model. All functions in my program are independent of each other? All functions are relatively equal in terms of their goodness or badness? All functions compose an equal portion of the program? Two resources can be equally valuable in real life? None of the circumstances are probable, let alone occuring in real life. Finally, I am not talking about a whole program, but individually each and every piece of code in it. there is no real scale of bad to worse in the end, as each is either accepted or rejected and re-compared until one piece of code is found to be the best. In other words, the return value is the whole purpose of the function.

3) I would estimate that a typical solution to a given problem (of the complexity of using linked list or array or whatever) has a ratio of < 1:1,000,000 of being programmed in the exact same way. That is, there are many, many variables found in both the problem and the solution. (Note that the less than sign there means that the second number grows bigger while the first number stays the same; i.e., 1/1,000,000 is bigger than 1/2,000,000)

4) The input must be the same? The function will take on equal values? What are you saying? Perhaps you misunderstood me, so I'll expound on it:

The inputs are comprised of: a) the problem and b) the solution. The constant (or another way of putting it would be the function) is good code, and the input variables (parameters) are the relevant variables of the particular problem and solution. The return value is based on equivalence to good code, returning either true or false for each statement. (If it should happen that all solutions fail this function, they are all compared to one another based on the variables relevant to the problem and the variables relevant to each solution.)

3) I'm sorry, but you didn't state the problem. Without the other half of the input, you will get undefined results.


quote: Original post by Mezz

Reading it, I find myself smiling because I think of two very reasonable and polite men sitting down trying to have an argument without offending or disagreeing with each other.


LOL I nearly fell off my chair when I read this!


quote: Original post by Mezz

One thing that did bother me was some of null_pointer's comments about logic.
A view of logic is relative - saying there is only one logical solution I find myself disagreeing with.



    Logic - 1. The study of the principles of reasoning, especially of the forms and relationships between stateements as distinguished from the content of the statements. 2. Rational thought; clear reasoning. 2. A particular system or method of reasoning. 4. A way of thinking or reasoning: the political logic of frontier people.


1) Where do you get subjective from that? I am talking about #2. If that definition of logic was subjective, it would not exist as it could not possibly fulfill its purpose.


quote: Original post by Mezz

You don't have a game. You want it.
Solution A: Buy it.
Solution B: Warez it.

You could argue that solution A is correct because it does not break the law. People without the money would argue differently.
what I'm trying to say is that logic can be relative.


1) Logic, as a set of defined laws and principles, is not relative. You must mean definition #4, a way of thinking. I was talking about definition #2. Definition #4 includes all the rationalisms that commonly go with the logic (here meaning #2) applied to a particular situation.

2) How dare you bring the warez people into a rational discussion!?! Warez is just stealing; stealing includes no definition of purpose intentionally, because it can be done for any purpose. Stealing is punishable by law. Stealing also disrupts the normal economics of a given system by changing the rewards for capitalism. However, I do not wish to get off topic with a discussion on pirated software.


Everyone: Without a standard there is no comparison. Without comparison you cannot say "good" code or "bad" code. That means a standard must exist. What is the standard?

And BTW, does anyone know how to fix the scroll wheel of a Logitech mouse?



- null_pointer
Sabre Multimedia


Edited by - null_pointer on 5/6/00 3:26:54 PM
Advertisement
Yeah, Kylotan, I guess I should take that part back. Now that I think about it a little more. Orignially I had thought that the assert() macro would be better to use since I was assuming that the logic errors could not (or at least should not) pop up in a final program. Things like array bounds checking (and lots of other things, now that I think of it) could actually be dependent on the program environment, user input, etc. 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. I would guess that this is why the standard library uses exceptions for some logic errors, but in general I think that exceptions should be used only if there is a chance that they might be triggered in the final code. I don''t think that they should be used in a possition where they are only meant as a debugging tool. That''s really what I was getting at.

Agree? Disagree?

Check out the GPI project today!
null, apologies for bringing in stuff on warez - couldn''t think of a better example right then.

I agree that standards are needed (but not too strict) I can''t believe I''m going to do this. Actually, I won''t, if you want the example I was going to give then e-mail me (no, it isn''t like my last one )

In response to "What is the Standard?"

There is no one standard.
A standard depend on what you are doing. I simply mean that a standard for writing code is different than a standard for writing a sentance. e.g. C code has a standard "all statements must end with a semicolon"
English language has a standard "All sentences must start with a capital letter" I think those are correct, if they are not then hopefully you will get the idea of what I''m trying to say.

Ok, I''ll go with you on talking about definition #4.
But logic as a defined set of laws and principles - well it was probably relative to whoever designed them in the first place

Ok, take it easy, I''m not sure I''ll read this thread any more because it takes my browser some ungodly time to load it all.

Have fun.

-Mezz
(Oh my! I think this is my shortest post!)

Mezz, check out this site. Some of the things are outdated (because the standard added better support for inline functions, templates, etc.) But most of the things are excellent ideas for what good code ought to be. I know that there isn't a Standard, but everyone seems to act as if there was one. I did say that it depended on both the problem's and solution's relevant variables, and everyone seems to agree. But the standard (the function body) remains the same.

But why do people talk about good code and bad code as if everyone had to code according to one standard? And then they say that everyone should have their own standard? (This occurs in many, many threads here, especially when helping newbies.)


(Oh no! Here I go again...)

chippydip: Assertions are terrible for debugging. They don't allow you to release resources properly and have absolutely no advantages over exceptions as far as reporting errors. When using APIs like DirectX and Win32, these resource cleanups are very important. Otherwise you will get very strange behavior after about 2-3 assertions. Could you please tell me why assertions are better than exceptions? (I suggest you read Mr. Stroustrop's appendix on the subject, or at least its introduction. Straight from the horse's mouth, so to speak.)

Exceptions, on the other hand, are marvelous cleanup and enforcement tools. They were made to enforce proper use of code, and to cleanup in case of an exceptional condition. With exceptions in debugging, I can write nearly anything, and as long as it doesn't crash in the Win16 Mutex, it'll shutdown properly and restore my desktop. With exceptions I can sit here online chatting to a friend and work on a buggy DirectX exclusive mode app without fear of having to reboot. It's especially good when working on problems together over the Internet.



- null_pointer
Sabre Multimedia


Edited by - null_pointer on 5/7/00 7:37:20 AM
null_pointer: Ok, I give in. The more I think about it, the less I think that assertions (the C++ implementation or them) are a good thing. I tried to check out that link about execptions, but it didn''t seem to be working... I''ll check back later. At any rate, I guess I''m a little spoiled here working on a Win2K system than can easily handle a program that doesn''t terminate properly and clean up after itself. I guess since I have this luxury I don''t care quite so much how the program terminates durring development as long as it doesn''t crash and burn in a release version.

With that said, I still like the idea behind assertions, preconditions, postconditions, and assertions. 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++. The nice thing about the eiffel implementation, though, is that it allows the assertion checking to be turned on and off (and set to different in between levels.) I like this feature b/c it helps to eliminate the conditional tests and overhead associated with exceptions in places where they are not needed anymore. If a set of exceptions are only meant as a debugging tool, then there is no need for them to even be compiled into the final release build.

Also, (I''m sorry, it was really late when i wrote the original post) I was completely wrong with my statement that a greater number of inputs tend to cancel out deviation. I was thinking about there being more ways to reach a certain combination, but the probability of two sets of inputs being the same still decreases (as there are more possible outputs) 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. Now this function will have a single maximum where running time = 0, space taken = 0, readabilty = 100%, etc. but for every program that I know of such a program is not possible (hence it is not part of the domain.) It is possible, however, that two different solutions will produce solutions that are equaly close the the ideal (and there are no better solutions in the domain.)

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.

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

Finally, the example of the Attack class was completely artificial. I have no code (but I could make some if you are really interested.) 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.) If I were to write a system like this, I would like to be able to say

sword->DoDamage(ork);

and be done with the attack. Maybe I would have another method before that like

if (sword->CanHit(ork))
sword->DoDamage(ork);

or something similar. I havent''t thought through the specifics, but it seems that this would be a useful modeling tool in some cases. 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)

P.S. I''m glad I read and got involved in this discussion... I''m learning quite a bit about some of my misconceptions about programming and software design.

Check out the GPI project today!

This topic is closed to new replies.

Advertisement