Advertisement

Classes Vs. Straight Code

Started by June 26, 2000 01:30 PM
91 comments, last by farmersckn 24 years, 5 months ago
Sean, by the way, thanks for replying!
( I appreciate you braving the flame-war to make your own opinions heard. )

We ALL have opinions, some of them educated, some of them perhaps indoctrinated at university etc etc etc.

quote:
It attempts to address the assumption that more features is better (despite the potential costs in terms of using other people''s code and the costs to compiler development) and the notion that since C++ is effectively C with more, it is therefore strictly superior to C, etc.


I don''t think I''d argue with that at all. I have to work with source code for libraries like Mesa and programs like POVray, they are written in C, and somehow I doubt that a straight "c++" port would be easier to read, because of the way it tends to force every little class into a new file. For projects of that size, in C++ with the file explosion, you need more than a "source file browser" to find your way through the code. Visual Studio does a bit of this, but not quite enough, in my personal opinion.
This is an argument against the general C++ programming style, I guess. I don''t think it''s nearly as mature as the most common C programming styles.

"Strictly superior"? Hmm, let me think about that again. Technically, using SOME of the features in C++, you could have an easier time writing certain C-programs. ( I''m thinking mostly of allowing declarations anywhere in the code, because of my personal experience with that... ). However, then the question remains if all those new features really need to be there, or if they should have been in much more clearly separated language dialects... I don''t have the answer to that. Adding more could make it worse.

quote:
C++ feels like a kludgish attempt to bring classes to C, and lots of hacking and complexity growth to try to make it all work somewhat sanely (but only somewhat: e.g. virtual functions during constructors).


*grin* You''ve run into that one too ey.
Again, I don''t think I''ll argue. C++ is an attempt to force OOP onto a language that was never really designed to be OOP. You made that point in the original article too I guess ( perhaps not as neutral as this time ). You need to be dedicated, and very focused, to do good OO in C++, because of the many ways you could write things that arent'' OO, and the many ways you can get caught out by the weirdnesses of the language.
I guess that because I''ve used it so much ( and I guess that Null_pointer has too, thinking about the HUGE messages he''s been posting about it ), you stop seeing the weird bits, because they become second nature. This COULD be limiting my ability to work within the OO paradigm, because it''s limiting me to the possibilities of C++.

( Actually, you kindof say that in your next paragraph ).

quote:
...and a response to my compiler-performance-issues comment that amounted to "you are wrong" with no argument or justification, I punted it.


Was that my comment about performance issues? ( Java vs C vs C++ ).
I wasn''t trying to make any better than another.
I''ll try to summarise:

1. C is a good procedural language, with VERY mature compiler support, and excellent standard implementation.

2. C++ builds on the C support, probably being the best OOP implementation that could be made without dumping C too much. However, after this discussion, I think that maybe it''s trying to be too little and too much. Plus, compiler support for the ENTIRE C++ standard is still lacking.

3. Java ( the only "OOP by design" language that I know a little ) stuck to it''s guns, and is a good OOP language. Unfortunately, the original idea of having it be "cross platform" and Sun pulling it back out of the standardisation process, are in my opinion limiting it severely. Good native support may exist, but I don''t know much about it.

Actually, thinking about what I''ve just said, is C# trying to adress the gap between C, C++ and java? Chopping out generic programming ( that''s for a different language ), and dropping backward compatibility stuff? I haven''t looked at the spec that closely to be sure.



Give me one more medicated peaceful moment.
~ (V)^|) |<é!t|-| ~
ERROR: Your beta-version of Life1.0 has expired. Please upgrade to the full version. All important social functions will be disabled from now on.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.

Hi null_pointer,

I am the "anon" w/o a handle so I will use zx495.

I am only being pedantic because it seems a lot of people make these same kinds of errors and am not trying to be a pain in the butt.


"The examples you gave are from ANSI C''s compatibility with K&R C, ..."
Wrong. See A8.6.3 of Appendix A of The C Programming Language Ansi C version and 5.2.6 sec 6 etc. of ISO/IEC 14882 First edition 1998-09-01 Programming Languages - C++.

Syntactic sugar and operator overloading.
I did not say it was not a nicety I said it was not necessary. You could define the language such that there is a different symbol for each. So you could have ''+_Int'' when adding integers, ''+_float'' etc. I agree that it is nice that you can write ''1 + 2'' and ''1.1 + 3.4'' and have two different operations. See next paragraph as well.

Elementry algebra texts do not describe number systems from first principles. The notation of ''5'' or ''+'' are not necessary just convient. See Betrand Russell''s works for instance or even Stoy''s description of Denotation Semantics for an easier read.

"Regarding the definition of Object-Oriented programming, data encapsulation is an essential principle. It''s the whole driving principle behind objects, really, or they wouldn''t be objects. "
I can have objects w/o data encapsulation (class with all public members) and I can have data encapsulation w/o objects (create static global variables and define exported functions to read and write each variable). They are orthogonal.


"Your argument is like saying that power saws are stupid and useless because in the hands of a minor they might hurt someone."
No, I am saying that power saws can cut off you hand if you are not careful. You cannot just say that because there is a safety guard that you cannot hurt yourself.

I agree that C is not necessarily better than C++.

----
zx495
Advertisement
Sean, whether you read this or not, I''m going to post it so that everyone here may understand why I wrote the reply, and why I wrote it the way I did.


"FACT:" Indicates a basis for disproving the arguments, which, if the "FACT:"''s are incorrect, obviously take away my points. Other people list things like this, but they don''t use the word "FACT:" to indicate them. In other words, they were the things that I took as fact during the writing of that post. I simply wanted to get rid of all of the petty emotionalism floating around here on this topic, and in reply (of course) I received comments like "you are the most arrogant C++ programmer I''ve ever seen" etc. If I''m wrong, please show me.


"CORRECTION:" Indicates something that I am pointing out to the readers here, so that we at least have a factual basis to start out on. I also use it to flag assumptions or misconceptions, the effects of which are disproven later.


Second, I was wrong about "Sean Barrett doesn’t know squat about language design, or programming methodologies, for that matter." and I apologized in my last post. I apologize again.

BTW, it was not a character attack but a (very) stupid mistake. Look at this:

"I guess I''m just a whiner if many of my problems boil down to C++ requiring too much typing. Typing is such a tiny fraction of programming that it''s not that big a deal. Yet it grates to see such extra ''accidental'' (in the sense of Fred Brooks ''No Silver Bullet'', i.e. in opposition to ''essential'') work required for no good reason."

Now re-read that with a different definition of the word "typing," this time referring to data type-ing. (There is a common newbie complaint against C++''s typecasting rules.) Anyone who would say that data typing is such a small part of programming would obviously know very little about language design, hence my earlier comment. Again, I''m sorry for my blunder!


If I''m not mistaken, you also took the liberty of saying a lot of things in the beginning of that rant without any immediate proof. Why? Most people state the things they are going to prove at the beginning of a written work. Then they proceed to prove them, or to disprove the other written work (if it''s an argument). So while I listed things in the beginning, the proof is in the discussion about your points, in the middle and the end of my post, and that''s where I must debate them. It was necessary to point out that your work was just a rant, and not intended as some kind of evidence to settle the language war...

I really wouldn''t blame you if you didn''t read through my post.


There has already been a LOT of discussion here, and many things have been beaten to death, especially the optimization and speed differences between C and C++. I was so fed up with the people who say "C++ is slower" but have no idea why. Then they cite the "this" pointer as something they have heard causes slow-downs. *groans* Most of it comes from people who really have little or no experience in C++. And it''s kind of irritating when they have no proof...


I was not the one who brought your rant into this discussion. I didn''t go searching thoughout the web, hunting for someone to make fun of or to take down a notch. There were a few C programmers here who read through it and agreed that "he makes a few very good points" and as I could find but one (a minor one), I wanted to see why in the world people thought it was so great. I''ve seen your rant quoted a LOT in these type of "language wars." So I read it. The more I read it, the more misconceptions I found. And those misconceptions have been cited in so many places on the web as fact (meaning they''re kind of typical), and it was as big a collection of those that I had ever seen, that I wanted to put a stop to them. Man, if you had the chance to correct simultaneously the writers of many articles, books, tutorials, etc. and all the things you needed to disprove were put in a nice, neat package before you, what would you do? Take it as fact and forget about it? Ignore it, and let the people wallow in their own misconceptions? Laugh at them behind their backs? None of those solutions seem adequate. So I decided to pull everything I knew about C++ and language design and work on it.


You''re entitled to your opinion and I don''t mind if you start posting C++ rants or witty criticisms or whatever on your home page - that''s your business (providing it''s legal ). But when it''s used as proof here, that''s a different issue entirely.


BTW, about language complexity, I have an explanation for my statements. We know that higher level languages such as C and C++ are broken down into lower level code called assembly at compile time. That is, assembly contains all of the basic operations, which are used either alone or in combinations to make up the higher level code. That means that if we give assembly 10 instructions (just for example), C as a language is going to be many times larger than assembly if it intends to provide equivalent functionality. After all, there are keywords (which turn into certain assembly instructions, or combinations of instructions), variations on keywords and syntax for the new data types, combinations of keywords (if...goto, do...while, for()...break, etc.), etc. As the language goes to a higher level of abstraction, it must either continue to provide all of the functionality of the underlying assembly code or limit it in some way. If it continues to provide all of the functionality, then it must continually grow more complex as it uses higher- and higher-level methodologies.

So, if C++ is going to retain C''s functionality while adding support for new methodologies (like OOP and generic programming), then C++ is going to be more complex. And if other languages are going to keep the functionality of assembly instructions that C also affords, they have to be about as complex. Otherwise, they may limit things to bring down the complexity, but that limits functionality as well. In effect, you could say C++ is a very flexible OOP language. And I think that C++ has the capacity to produce faster, more efficient code than other OO languages precisely because of the greater complexity. In simplest terms, flexibility = capacity for efficiency.

The obvious argument is that if there is too much flexibility, the programmer will have too many options and efficiency will drop. I can happily say that C++ is not so overly complex that you can''t learn it enough to use it efficiently. I know just about every keyword and syntax, and I''m no genius (that should be obvious ).

The second most obvious argument is that other languages may implement a better design, and by doing so they will have a better efficiency/flexibility ratio. I have not found an unnecessary feature of C++. Of course, I''m not in a position to compare languages, as I only know C and C++. However, if you still hold the same arguments as in that rant, then I don''t think you know C++ well enough to compare it with other languages (regardless of how much you know about other languages, or language design in general).


BTW, virtual functions shouldn''t be used in constructors because the objects they use haven''t been constructed yet, which means the constructors of the object''s data members haven''t been called. If another OOP language can do this, then they must be limiting the functionality of the constructors somehow (no initializer lists, etc.) or it won''t work in certain situations, or the former may just be preventing the latter.


MadKeithV: He was referring to my comment about optimization, so don''t worry.




- null_pointer
Sabre Multimedia
MAKE_HANDLE(zx495): hi!


quote: Original post by zx495

I am only being pedantic because it seems a lot of people make these same kinds of errors and am not trying to be a pain in the butt.


Welcome to the club!

Actually, I''m glad people decided to get pedantic instead of emotionalistic. At least this way we learn something (other than swear words).


quote: Original post by zx495

"The examples you gave are from ANSI C''s compatibility with K&R C, ..."
Wrong. See A8.6.3 of Appendix A of The C Programming Language Ansi C version and 5.2.6 sec 6 etc. of ISO/IEC 14882 First edition 1998-09-01 Programming Languages - C++.


The function() syntax without variables is K&R C, but I didn''t know it was adopted into Standard C. Can you give me a link to view that online? Or possibly just the URL of ANSI site if it exists?


quote: Original post by zx495

Syntactic sugar and operator overloading.
I did not say it was not a nicety I said it was not necessary. You could define the language such that there is a different symbol for each. So you could have ''+_Int'' when adding integers, ''+_float'' etc. I agree that it is nice that you can write ''1 + 2'' and ''1.1 + 3.4'' and have two different operations. See next paragraph as well.

Elementry algebra texts do not describe number systems from first principles. The notation of ''5'' or ''+'' are not necessary just convient. See Betrand Russell''s works for instance or even Stoy''s description of Denotation Semantics for an easier read.


Even though _most_ elementary algebra texts do not describe number systems (immediately), that is how it works, and it is the basis for the all of the fundamental properties.

If we had +_int and +_float, we could have +_matrix, and the properties would still be changed with the data type. (IMHO, that''s mimic-ing operator overloading, which is what the mind does naturally.) Anyway, from what you are saying:

FACT: Operator overloading is used in algebra.

Thus it would just be fantasizing to think that the operators would keep the properties regardless of the data type. C++ provides code to match the algebraic implementation; C++ didn''t re-write algebra or go with some crazy new syntax called operator overloading.


quote: Original post by zx495

"Regarding the definition of Object-Oriented programming, data encapsulation is an essential principle. It''s the whole driving principle behind objects, really, or they wouldn''t be objects. "
I can have objects w/o data encapsulation (class with all public members) and I can have data encapsulation w/o objects (create static global variables and define exported functions to read and write each variable). They are orthogonal.


Hmm...then my book is wrong. Why is it that I can''t seem to find a definition of the term "OOP" other than my book, which everyone says is wrong? Or perhaps it''s come incredibly vague term that no one understands but everyone bickers over?


quote: Original post by zx495

"Your argument is like saying that power saws are stupid and useless because in the hands of a minor they might hurt someone."
No, I am saying that power saws can cut off you hand if you are not careful. You cannot just say that because there is a safety guard that you cannot hurt yourself.

I agree that C is not necessarily better than C++.


My example with the power saw indicated that strong typing is just a tool - it depends on the user. I assumed a competent C++ programmer would know how data typing works, but apparently incompetent C++ programmers are the assumption these days.


BTW, thanks for correcting my "FACT:"''s!



- null_pointer
Sabre Multimedia
null_pointer:

Yes, sorry for the ''typing'' confusion. Perhaps I should have written ''keyboarding''?

I don''t believe I made any C++ performance comments; I''ll reiterate the comments I *did* make in the next paragraph. Clearly, a C++ program written using only the C subset need not run any slower than an equivalent C program (unless the compiler uses a sloppy implementation of exception handling). The implicit this pointer may cost something, but only if you use it; and writing "simulated" classes in C requires just passing around the pointer as well. On the other hand, I know that the guy who wrote the System Shock renderer optimized all the function calls by moving parameters into global variables to reduce parameter copying/pushing; this is not an option with implicit this. But I don''t think that''s a big attack on C++, since you can always alter performance-critical C++ code into the C style.

My comment, as I recall it, was rather different. In the real world, real vendors ship real physical compilers. Given a fixed amount of compiler development time, and given the requirement to meet the C spec or the C++ spec, the authors of a C compiler will have more time after meeting the correctness requirements to address performance (optimizations on the output code). A C++ compiler author will spend significantly more time implementing the base features of the language, and making them correct, leaving less time for optimizations--again, assuming a FIXED, equal development time for each.

As I said, the reality is that there is no longer any such thing as a "pure C" compiler, AFAIK, only C/C++ compilers. As a result, our C compilers have "lost" performance from what they could have had C++ not come along and similar budgets still been given to them. But the key issue here is that the more the language is complex, either by adding lots of features or by adding features which interact in complex ways, the less time there is available to optimize it, and this can cost performance. On the other hand, compiler vendors may be able to justify bigger budgets for bigger languages, which changes the rules. Certainly they can justify bigger budgets for more popular languages, so Stroustrop''s decision to aim for popularity may have avoided this problem (compared to, say, Python).

Finally, to your "size" claim, I definitely disagree. Most ASMs have many more keywords than C has keywords/tokens. This is partly due to the introduction of types to C; machine language with have separate opcodes for byte addition, word addition, longword addition, float addition, and extended-precision float addition; for multiplies or non-twos-complement-machines, separate instructions for unsigned byte, unsigned word, unsigned long operations. C decouples the type from the operator, allowing fewer keywords and unique tokens to express the same number of operations. C allows you to introduce your own variable names, whereas x86 ASM has, umm, 28 different predefined register names (I think that''s more than there are C keywords).

It''s not clear that the "size" of a spec is fairly represented by the number of unique keywords, especially in a language like C++ where some keywords (like "static") have entirely different meanings in different contexts. I think it''s widely accepted that Ada and C++ are relatively large languages, and C is much smaller. I consider Smalltalk significantly more powerful than C, and it''s much smaller than C++ (not sure compared to C).

Of course, the extra size of C++ provides features not available in Smalltalk, such as templetization. On the other hand, I find it unfortunate that C++ complicates things with multiple semantics and syntax. Wouldn''t it be nice if you could just use the normal class polymorphism syntax and add a keyword to say "specialize this"? Of course, the normal C++ class polymorphism isn''t powerful enough to do everything you need, so we end up with what''s effectively another preprocessor. Compare this to the work done in Self (which was leveraged for some JIT java compilers, I believe), where specialization was done at runtime on heavily used methods--specialization purely for performance, not with a different semantic. This sort of specialization can be done without growing the language at all, and gets most of the benefits. (Of course, the fact that Smalltalk is so datatype promiscuous helps, but there are other languages which are more polymorphic than C++ and yet are strongly typed, I forget offhand what, ML maybe?)

Sean Barrett
So...trying to sum up what I think was said in these last few posts...

C needs less "Compiler Intelligence", because less can go wrong. With average "Programmer Intelligence", you can get a pretty decent implementation.

C++ needs more "Compiler Intelligence", because there are some constructions that are internally much more complex than they look from the outside. However, standard compliance tends to lead to reduced "Compiler Intelligence", because less time is available, or the standard is compromised, in which case you may be missing some of the ways that "Programmer Intelligence" might leverage C++.
So generally speaking, because of lacking "Compiler Intelligence", C++ requires a more-than-average "Programmer Intelligence" to get to the same level of performance as C. However, this is possible in nearly all cases.

There are languages out there, that are perhaps unfortunately unknown, that address the same issues that C++ addresses, but in a much more direct way, because they do not try to be compatible with anything else, aside from perhaps the paradigms of OOP.
These languages, with the same budget and time allotments, would probably provide more "Compiler Intelligence", and require less "Programmer Intelligence" to achieve the same results.


Is that about right?

Ps: Null_pointer: Nobody can agree on what exactly OOP is, every book has a different definition, so really it''s damned hard to talk about it . I think it generally amounts to a "data oriented approach" as opposed to an "algorithm oriented approach".
Perhaps this is why it''s not so popular in Games? Most of the time technology is advancing in the algorithms, and not in the dataset or data representation...


Give me one more medicated peaceful moment.
~ (V)^|) |<é!t|-| ~
ERROR: Your beta-version of Life1.0 has expired. Please upgrade to the full version. All important social functions will be disabled from now on.
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
Advertisement
MadKieth:

I tend to get caught up in replying point by point, so I guess I''ve been failing to point out the forest, only the trees.

So, yes, I believe your summary is roughly correct. I''m not sure I''d put the "compiler intelligence" thing that way, but I guess one point is that, yes, there are other (either real or potential) languages that should have all the benefits of C++ but fewer of the drawbacks.

As to the first point, the "programmer intelligence" vs. "compiler intelligence"...

Stroustrop''s clever realization was that all such languages are not back-compatible with C, and do not have the avenue to success of bootstrapping C programs and programmers that C++ has, and that therefore a "compromised" language like C++ would be more likely to succeed than an "uncompromised" language, like Python or Squeak or Self or ten million other OOPLs (and I''m not sure where Java falls on this map, but that''s another story).

Now, some people know this, but they keep their heads down and just code. There''s nothing to be done about it--if Stroustrop hadn''t "compromised" his language, it would never have succeeded, and either someone else would have written a C-with-classes (that presumably would have been just as compromised) which succeded, or we''d all still be writing plain C code, which would be annoying when you really wanted read-only-function-pointer-table-sorts-of-behavior (to oversimplify).

Some other people think C++ is god''s gift to programmers, the best possible programming language, the best in all possible worlds.

My bone to pick isn''t with them. It''s with the ones who are smart, who know C++ isn''t perfect, but who believe that C++ is *strictly superior to C*.

I do not think we''d all be better off writing C all the time. But I do think there are some deep negative consequences of C++ which are all properties of the real world, where you use real compilers and work with other programmers and other people''s code: optimization quality, dialectization, maintainability of poorly-designed-overusing-C++-features, and a few other things. So I guess if I have a point, that''s it.

As stated before, my rant was entirely inspired by my frustration with people''s reaction to the iMac, and my analogy of that to C++. As such, I did not have anywhere near as coherent a point at the time as the one I''ve described above, so anybody who didn''t manage to get that idea from the rant shouldn''t worry about it--it wasn''t there.

Sean Barrett
Heres my thought on original question.
I think that with large Projects as big games OOP is the way to go. NO DOUBT ABOUT IT
quote: Original post by null_pointer

heh heh no one likes my post but they didn''t refute any of my points



points? hmm.. I must not have made it that far.
Sean: I'm sorry, it took me a while to reply because I haven't been online much in the past few days. I see what you are saying, but I still don't agree. Maybe I won't agree until I learn other languages.

(hehe BTW, the guy could have used static member variables. The only use for globals in C++ is main(), and grudgingly, at that. )


And about optimization, you meant future developments in optimization? You did say "any lowered performance in C++ would no doubt also be seen in C..." which I took to mean "removing past optimization work," and not "limiting future optimization work" (if that makes any sense). In my original words, performance isn't going to be "lowered." However, I never said the increases wouldn't be slower.


To my knowledge, Intel assembly has types (albeit very few), and allows variable naming. Perhaps that's just another MS extension (I was looking at the MASM reference). Anyway, I suppose you could say that the size of the spec is fairly represented by the number of keywords and their context. If you separate keywords from context, you get far fewer keywords, but each keyword has multiple meanings. If we do "keywords * context = complexity" then that seems fair enough. Each assembly keyword has one context, so if there are 255 keywords the complexity is 255, right? I'd wager that C either meets or exceeds that level of complexity, and C++ has an even higher level of complexity. That is, if I had any money.

The second through fourth paragraphs of my argument about language complexity would still stand, then?


I still don't understand why you would ever want polymorphism to work with templates. That would limit the use of the templated classes and functions to derived types, and intrinsic types would require wierd workarounds like this:


class map_key_int
: public magic_class
{
public:
operator int () { return value; }

private:
int value;
};



And you couldn't even write a template class to make that easier, because you'd need the workaround to use the intrinsic types, which would require having the magic wrapper class, which would require the workaround, etc.

Not to mention all of the dynamic_cast-ing and temporary pointers the compiler _must_ do to retain type safety:


magic_value* lookup_function(map_key_int key)
{
return dynamic_cast&ltmagic_value*>( map_object[key.value] );
}

map&ltmagic_value_base*>* build_map(magic_value_base* objects, int number_of_objects)
{
map&ltmagic_class*, magic_value_base*>* = new map&ltmagic_class*, magic_value_base*>

for( int iterator=0; iterator < number_of_objects; iterator++ )
{
dynamic_cast&ltmagic_value*>( *map[magic_class(iterator)] ).object = objects[iterator];
}

return map;
}



Ugly.

And how would it work with the lookup function? How could the map class possibly know that each map_class* is really a pointer to whatever type you thought up, with whatever key value you wanted? All the map can do with the "polymorphism" method is to use the class instances (i.e., pointers) as lookup values, which means you've got all your objects stored in random places throughout the map. You may even be overwriting them, because it depends on whether the compiler will re-use the temporary magic_class object's location or not. How could this possibly work?

And even if those things _could_ be optimized out, the messy syntax would remain. Or should we "bend" the rules a bit with templates? Allow implicit dynamic casts? etc. In short, why would you want templates to use polymorphism if you aren't even making use of polymorphism? Your method is not doing anything; it's _just_ a workaround, providing more work than is necessary, and eliminating a lot of options in the process. If you want to use polymorphism, just make it a map of pointers. Forcing all templates to use polymorphism to work would really make them useless.

Look at this piece of code, which I use all the time with DX:


template &lttypename pointer_type>
inline void safe_release(pointer_type& pointer)
{
if( pointer )
{
pointer->Release();
pointer = NULL;
}
}



That makes it kinda simple - anytime during shutdown that you want to release a DX object, you just call safe_release(). If you need to have redundant cleanup code somewhere, you can call it twice on the same pointer with no ill effects. I use a similar version for heap objects called safe_delete(). Templates make the safe_release() function very simple and very useful during debugging. If the class has a Release() method, then it compiles fine with no complaints, but if the class has no Release() method, a compiler error is thrown to indicate that the function won't work with it.

Do you know the all the workarounds I would have to implement to use it with the "polymorphism" method? They would completely destroy any benefit I might have gained by writing the safe_release() function. Here's a sample:


class direct_draw_object
: public magic_value_type // what does this have to do with DX objects?
{
public:
LPDIRECTDRAW p;

operator LPDIRECTDRAW()
{ return p; }
};

class direct_draw_surface_object
: public magic_value_type
{
public:
LPDIRECTDRAWSURFACE p;

operator LPDIRECTDRAWSURFACE()
{ return p; }
}
};

// etc. - how many DX object types does a DX game use?



Templates are absolutely invaluable for small utility classes and simple, type-safe but generic functions. Not to mention all sorts of container classes. And they really show the power of function overloading. If we used the templates with the "polymorphism" method, writing templates would be a worthless waste of time, because all of the time gained by encapsulating principles in generic templated code would be spent in workarounds, which happen to make the code look even less clean than void pointers (yuck!).


BTW, dynamic_cast should only be used _rarely_ - overuse of it indicates poor design and unnecessary use of polymorphism. Polymorphism is one of the most overused things in C++. You only _need_ polymorphism for a few classes in a typical game. Classes are powerful enough without polymorphism (and darn fast, too) for most chores:


class input_wrapper
{
public:
virtual void read(void*, int) = 0;
};

class output_wrapper
{
public:
virtual void write(void*, int) = 0;
};

class io_wrapper
: public input_wrapper, public output_wrapper
{
};

class file_wrapper
: public io_wrapper
{
public:
virtual void read(void*, int) { /* ... */ }
virtual void write(void*, int) { /* ... */ }
};



That example would be obvious overkill for something that simply wraps file access with some special formatting. All you really need is this:


class file
{
public:
void read(void*, int) { /* ... */ }
void write(void*, int) { /* ... */ }
};



Real, working, efficient C++ code is incredibly small.

If you are going to use abstraction properly, it is the "weeding out" of unnecessary details, and in program design it serves to eliminate unnecessary work. In a typical program, the programmer understands how files work, and the similarities and differences between file I/O and other I/O. But those relationships (like from what classes the file example was derived) are unnecessary baggage (and useless code) unless they actually _do_ something for the programmer. Form follows function, as they say. The base class concepts were totally unnecessary in the example - they accomplished nothing, except to slow the code down a small bit versus regular class functions. If you are only deriving one class, it isn't polymorphism, is it? Of course, if you were deriving another class like "network" then the virtual functions would start to become very useful, and could eliminate a lot of other code in some places. Polymorphism is a nice tool, but it shouldn't be used everywhere for everything.

That said, I think templates were one of the best additions to C++. The extra size of the language required to support templates is almost trivial, isn't it? One new keyword, two new contexts, and it adds a new methodology to the language (after procedural, structural, OOP, there comes generic). The hard part of learning templates I attribute to hype and poorly written "tutorials." After all, you aren't learning a new type of class or function per se, it's more like learning how to use existing classes and functions in a different way. In other words, using templates allows you to define classes and functions that work with any data type that supports the minimum of stated features (for example, a templated min() function would require only comparison operators). Specializing generic programming would eliminate its use.


Also, the file class (without polymorphism) could be written in this way, which shows how nice the sizeof operator really is:


class file
{
public:
template &lttypename data_type>
void read(data_type& data) { /* use sizeof(data) */ }

template &lttypename data_type>
void write(data_type& data) { /* use sizeof(data) */ }
};



(Remember, the sizeof() operator would have been used and its return value passed as a parameter to read/write anyway. Templated functions like this eliminate the chance of user error (passing the wrong type to sizeof()), because the compiler knows the type.)


Of course, you could probably go further and create templated operators. And on and on... templates really make life much easier for the user of the class. Of course, you could optimize that by: 1) making read/write inline, 2) creating a protected overloaded version that uses byte*, and 3) placing the common code from the templated functions into read and write. This eliminates the need of the user to use the sizeof() operator before every read/write operation, without even generating much work for the file class programmer. Here's the modified file class:


class file
{
public:
typedef byte unsigned char;

template &lttypename data_type>
inline void read(data_type& data)
{ read( reinterpret_cast&ltbyte*>(&data), sizeof(data) ); }

template &lttypename data_type>
inline void write(data_type& data)
{ write( reinterpret_cast&ltbyte*>(&data), sizeof(data) ); }

private:
void read(byte* data_pointer, int data_size)
{ /* call fread or something */ }

void write(byte* data_pointer, int data_size)
{ /* call fwrite or something */ }
};



A little bit of typing, a creative use of templates, and now the user of the file class can do this:


int x;
float y;
char z;

file.read(x);
file.read(y);
file.read(z);



Instead of this:


int x;
float y;
char z;

file.read(x, sizeof(int));
file.read(y, sizeof(float));
file.read(z, sizeof(char));



Because templates enable the compiler to juggle the types and generate the proper code. And there is no slow-down over the traditional method, because the public templated read and write functions are inline and only use the sizeof operator to call the commonly used function: read(byte*, int).


Well, I've probably bored everyone to tears by now...

Thanks for your time, Sean


quote: Original post by MadKeithV

Ps: Null_pointer: Nobody can agree on what exactly OOP is, every book has a different definition, so really it's damned hard to talk about it . I think it generally amounts to a "data oriented approach" as opposed to an "algorithm oriented approach".

Perhaps this is why it's not so popular in Games? Most of the time technology is advancing in the algorithms, and not in the dataset or data representation...


Then what a stupid term...why in the WORLD do people have -vague- goals and -vague- methodologies? Just put organize your code so that it treats objects as more important than algorithms, but don't take it to the logical end so no one can really debate it without disagreeing? I'd rather create my own methodology. Maybe I'll start a thread about methodologies...




- null_pointer
Sabre Multimedia

Edited by - null_pointer on July 9, 2000 8:38:48 AM

This topic is closed to new replies.

Advertisement