Top Mud Sites Forum Return to TopMudSites.com
Go Back   Top Mud Sites Forum > Mud Development and Administration > MUD Coding
Click here to Register

Reply
 
Thread Tools
Old 01-24-2003, 01:14 PM   #1
Vesper
Member
 
Join Date: Apr 2002
Posts: 67
Vesper is on a distinguished road
Send a message via AIM to Vesper
Exclamation

Hey all.

I've been interested in teaching myself how to code for awhile now and well, I went and downloaded Cygwin on my comp. I'm also told I need to dl a codebase after that, which will probably be some sort of ROM.

Now, my question is this: I want to go out and buy the much-needed coding book. But...what exactly is preferred?

C? C+? C++? In terms of wanting to learn to code and possibly write up some snippets for mud's one day, which is suggested?
Vesper is offline   Reply With Quote
Old 01-24-2003, 02:04 PM   #2
Yui Unifex
Senior Member
 
Join Date: Apr 2002
Location: Florida
Posts: 323
Yui Unifex is on a distinguished road
Send a message via ICQ to Yui Unifex Send a message via AIM to Yui Unifex
Question

Most existing mud codebases have been created using C. So C++ isn't going to help you much if you want to distribute snippets, because some codebases require conversion to be compiled with a C++ compiler. The newer codebases that I see people working on are almost universally written in C++, Java, or a language with greater abstraction possibilities than C.

If you just wish to modify an existing codebase, for example ROM, a book on C would most likely be your best bet.

btw, "C+" doesn't exist =).
Yui Unifex is offline   Reply With Quote
Old 01-25-2003, 02:49 AM   #3
Vesper
Member
 
Join Date: Apr 2002
Posts: 67
Vesper is on a distinguished road
Send a message via AIM to Vesper
Question

Ahhh...thank you. *grins* And you're right, of course, it doesn't exist, heh...I believe it was "C#" I was trying to think of...

So, that brings up a question of trends: Will the use of "C" eventually fade out...in favor of the newer "C++"...or does the more recent language not really apply to the MUD world?
Vesper is offline   Reply With Quote
Old 01-25-2003, 09:18 AM   #4
Yui Unifex
Senior Member
 
Join Date: Apr 2002
Location: Florida
Posts: 323
Yui Unifex is on a distinguished road
Send a message via ICQ to Yui Unifex Send a message via AIM to Yui Unifex
Question

I can only speculate, but I believe existing codebases are going to continue on with C. Most of the newer codebases that I see in development are done in C++, with some in Java and other languages. So it then becomes a question of whether or not the newer codebases will surpass the older ones, and I lack the clairvoyance to know that =). But C++ codebases will definately become more common I predict.

It is probably a good idea for you to start with C anyway, because C++ is very similar and will even compile most C code. There are also several C codebases to use as a reference point (although you should be careful about learning habits from them, as they are rather poorly designed). C is also much less complex than C++, so there are fewer areas to get confused about when you're starting out.
Yui Unifex is offline   Reply With Quote
Old 01-27-2003, 05:29 AM   #5
Ingham
 
Posts: n/a
C++ is not more complex then C imho. However, because it is an object-orientated programming language, it is definitely allot more abstract and harder to grasp because of it. Still though, if you try the basic of C first, C++ will be a piece of cake because some possibilities in C look quite alike objects in C++ (structs anyone?)

As for which language will fade out, neither of them I believe. C is being used as the standard language for Unix and Unix-like operating systems and C++ is more or less a "standard" language used for various reasons/applications. I don't know about speed differences among C and C++, but both are definitely faster then Java, because Java is basically a souped up scripting language instead of a programming language.

As for compilers, which can be tricky to find, look around on the net for Borland C++ Builder version 3.1. It's good, easy and not all that complicated. DOS based though, so be prepared to work in a 25x40 res with 32 diff colours if you want to use it. It's quite easy to use, does the job, even though it is not so much very legal to find and download.
  Reply With Quote
Old 01-27-2003, 07:06 AM   #6
KaVir
Legend
 
KaVir's Avatar
 
Join Date: Apr 2002
Name: Richard
Home MUD: God Wars II
Posts: 2,052
KaVir will become famous soon enoughKaVir will become famous soon enough
C is a relatively simple language (although it still requires a lot of time and effort to learn to use it effectively), while C++ adds a significant amount of complexity.

C++ is not an Object Oriented programming language. It is a multi-paradigm programming language that supports OO, as well as other styles of programming. It requires a lot more effort to write OO software in C.

Not true - I have encountered several people who had only learned C++, and they all did extremely poorly when it came to C interview questions (particularly with things like strings).

Regarding which language to learn: If you're only interested in learning so that you can write mud snippets, then I would agree with Unifex and suggest C. In fact I use several (of my own) C snippets in my own C++ codebase - I just encapsulate them in a namespace - even though they were originally designed to work on muds written in C.
KaVir is offline   Reply With Quote
Old 02-22-2003, 02:23 PM   #7
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
If you're just learning a first language, C is a much better choice than C++. The poster who said that C++ isn't more complex than C has obviously never had to tackle virtual inheritance, virtual functions with multiple inheritance, problems with dynamic casting and typecasts changing pointer values, operator overloading...

C++ takes C as a starting point and adds a huge amount of new stuff. It's more complex. Seriously. It contains all of C as a (small) subset. How can it *not* be more complex?

You can get away with using fewer of the complicated, nasty C++ features if you only use your own code. But if you ever plan to have another coder on your MUD (you do, right?) you'll have to deal with them. And while everybody seems to agree that C++ is a combination of okay stuff and gross, horrible hacks, nobody seems to agree about which is which. So he'll be using some stuff you consider to be gross, horrible hacks.

I believe that C is the clean part of C++, and almost all of the rest is made of gross, horrible hacks :-)
angelbob is offline   Reply With Quote
Old 03-10-2003, 05:45 PM   #8
Lindahl
New Member
 
Join Date: Feb 2003
Location: California, US
Posts: 5
Lindahl is on a distinguished road
angelbob-

Which would you consider cleaner?
----------------------------------------
class IntObject
{
IntObject &operator +=(int val)
{_val += val; return *this;}

operator int( )
{return _val;}

int _val;
};

IntObject i;
int v = i += 3;
-------------------------------
Or?

struct IntObject
{int _val;};

IntObject *PlusEqual( IntObject *i, int val)
{i->_val += val;}

int Value( IntObject *i)
{return i->_val;}

IntObject i;
int v = Value(PlusEqual(&i, 3));
----------------------------------

To me, the C++ version (first version) is a lot cleaner and more intuitive.

I'd have to say that the design details of a program determine which language produces cleaner code (mainly whether the problem is more naturally described as objects (C++), or proceedures ©).

In the case of a MUD, the design is CLEARLY object-oriented (Server, Connection, Player, Character, Object, Room, Area). Thus, using a language that has object-oriented capabilities would most likely produce the cleanest code.

I'm guessing that you confused the cleanliness of a piece of code with complexity of a language.
Lindahl is offline   Reply With Quote
Old 03-11-2003, 06:31 PM   #9
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
First, I note that you're using a complex structure where you should be using an int. Passing a pointer to a structure with a single int makes for ugly C, passing a reference to a structure with an int makes for ugly C++, and passing an int around is pretty clean -- and identical in either language. But I'd say both are quite ugly, and both are about equally ugly, but it's very slightly more obvious what the C version is doing.

Second, by talking about how MUDs are an obvious place to use object-oriented programming I'm assuming you're talking about the objects themselves (like, "physical" in-game objects). I'm with the Skotos folks on this -- data inheritance is appropriate, code inheritance not so much so. Code inheritance is the only kind that C++ provides.

Third, if you're talking about inheritance in the "physical" in-game objects, then you're talking about doing it dynamically if you have any OLC facilities. Any modern MUD does. Unless you recompile on the fly (like DGD does -- I'm actually serious, although C++ isn't a good language for this, nor is C), you're going to have to build your own stuff. So you're back to implementing all your own data inheritance.

I agree that there are a couple of specific instances where C++'s version of OO is cleaner than doing the same thing in C. User interface code (windowing and whatnot) is the only place I've seen where it's consistently true. And yet GTK+, the windowing toolkit for GNOME, uses C instead of C++. Why? Because C++ is incompatible between compilers, doesn't link object code between multiple compilers, has the usual fragile base class problems and can't inherit and runtime. The fully inheritance-based solution used by GTK+ is done in C and built out of macros. Unlike the C++ solution, it links to a variety of languages, allows implementation of new widgets in a variety of languages, doesn't require RTTI (which doesn't link between different C++ compilers) and works quite happily if you add new stuff at runtime.

Fourth: your C solution above is attempting to do operator overloading in C. That's its primary problem. You can do what you're doing relatively cleanly in C, but you can't make it look like C++. Why would you want it to look like C++?
angelbob is offline   Reply With Quote
Old 03-11-2003, 06:50 PM   #10
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
Here, lemme make it clearer what I mean about the "using a complex structure instead of an int" and "make it look like C++" bits.

Your example could be less trivial -- vectors and matrices are the cleanest example I know of in C++, and the best example of why operator overloading might not suck. Every other example that I know of is thoroughly horrible, and I absolutely include "cin" and "cout" in that. I mean, c'mon, they're using bit-shift operators for input and output. How clean and intuitive is *that*?

It's hard in C and ugly in C++ to pass big complex structures around as though they were regular builtin data types. That's pretty much what you're doing above. You can do the same with matrices and define addition, multiplication and (with some stretching) things like inner products, inversion and solving. Of course, nobody but you will ever guess your operators on the first try for anything except addition and multiplication, and they'll need to check your documentation to see if you're doing real matrix multiplication or just going element-by-element.

So instead of something big and nasty and C-like like this:

Matrix *A,*B,*C;

A = MatrixInit(7,7);
MatrixFileLoad(A, "mydatafile.dat");
B = MatrixInit(7,9);
MatrixFileLoad(B,"myotherdata.dat");
C = MatrixInit(7,9);
MatrixMultiply(C, A, B);

You can instead have something smaller and C++-y like this:

Matrix A(7,7), B(7,9);

A.FileLoad("mydatafile.dat");
B.FileLoad("myotherdata.dat");
C = A * B;

Cleaner, smaller, and not much slower if you do it right. The bit of slowness added is because you'll be copying C after that matrix multiply with its copy constructor. You could avoid even that if your compiler is really clever (it's not -- check the code if you use GCC, or the execution time if you use VC++), and the stack space hit doesn't matter in this day and age, at least for MUDs. I used to work for Palm, I notice these things. Anyway.

I'll mention in passing that the library implementing this stuff will be much nastier in C++ than in C. But you could point out that you only write the library once and you write code with it many times. You'd be right. Of course, you maintain the library and deal with bugfixes constantly, and the C++ version does a lot more under the covers. For instance, if you had a bug in the copy constructor or one of the operators in the C++ version (for instance -- does A *= B work? Maybe...) you'll have a much nastier time tracking them down and finding all the functions that are called. I'd say a good debugger would help you, but GDB and VC++ both have serious issues with a lot of very standard C++, let alone godawful things like most proprietary Unix debuggers.

You can say "but I'd write the library right' or "but I'd debug and test it well". You'd probably be right. Good for you. Now, are you the only one working on your project? I've seen a lot of very bad C++ with very hard-to-find bugs. Much more so even than C, especially if I can use a tool like Purify on both.
angelbob is offline   Reply With Quote
Old 03-11-2003, 06:52 PM   #11
enigma@zebedee
Member
 
Join Date: Mar 2003
Posts: 70
enigma@zebedee is on a distinguished road
If planning to code on an LP Mud (or any older mud) then I recommend C as C++ and C# both have significent differences. A lot depends on the mud you want to code on though - I recommend finding and playing the mud before you decide to code for it. Once you know that then the admin there will be able to tell you what language they are using.

Certainly on Zeb we don't let people become coders until they have played the game (the usual rule being at least one character to legend level) and we feel that they are ready for the responsibility.

As a side note C# is basically microsofts bastard cross-breading of C++ and Java. It has some nice features but I don't see it being used much for muds in the immediate future - although I am using it a lot at work.
enigma@zebedee is offline   Reply With Quote
Old 03-12-2003, 10:47 AM   #12
Yui Unifex
Senior Member
 
Join Date: Apr 2002
Location: Florida
Posts: 323
Yui Unifex is on a distinguished road
Send a message via ICQ to Yui Unifex Send a message via AIM to Yui Unifex
Question

I think that much is obvious, but if there were added functionality I'm not so sure that this would be a great idea. If the IntObject were something like CheckedIntObject, which checked assigned values against a valid range and threw an exception when something went out of bounds, it would be a great deal more intuitive and easily extendable with C++ -- after all, it would react exactly like an int, save for the operations one specifies, which makes it easy to typedef and modify if some logic changes.

The objects he mentioned were "Server, Connection, Player, Character, Object, Room, Area". Three of those are not physical objects (Server, Connection, and Player, I think), and depending on the design, physical transformations between the other three may not exist. So data inheritence in that sense is useless because the types do not share data. Since you've stated that you're talking about in-game objects, inheriting data is as easy as writing a copy constructor. I don't think that something so simple needs specific language support. But C will have just as many problems as C++ here -- do you do deep or shallow 'inheritance', and what functions provide it? With C++ you can do deep copying automatically in the copy constructor; this is something that would take one extra step in C, never mind the fact that you'd lose pass-by-value semantics due to the lack of a destructor. IMO, "string" objects are very clearly superior to char * memory pointers because of this.

Correct -- you would lose functionality because it can't look like C++:
[code] typedef mytype int;
void dosomething (mytype &m) { m = 5; }[/quote]
When that typedef is changed to IntObject (or something more functional, like my above CheckedIntObject), you would have to go back and insert functions to perform all of the assignments.

Not just this, but for templated functions that depend on certain operations working across the board with user-defined as well as built-in types, operator overloading is essential. STL algorithms work on all sorts of types because of this, and it's another thing that C can't achieve.

I don't think they'd need to guess -- you would simply overload operator* to handle both matrix and scalar multiplication, so the operations would flow as they do in mathematics; the operations would be type dependant just as they are in the problem domain.
Yui Unifex is offline   Reply With Quote
Old 03-13-2003, 12:43 PM   #13
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
(Quotes here are from Yui Unifex)

This is true, and I've seen some impressive similar stuff done with using pointers for transparent reference counting. It's pretty nifty as long as no bug ever exists in it (hint -- check every implementation of pointers for refcounting that you use... When reassigning, do they increment the new reference count BEFORE decrementing the old one?).
Of course, if a bug ever happens that doesn't crash your code, you have to debug it. I'm a big fan of knowing when functions are called. C++ experts can generally tell you the order of function calls in, say, this:

C *= myType(9,4,"bob")

It definitely gets hard to follow, though, especially if (in the example above) you haven't defined your own *= operator and C++ has to wing it. It will, in fact, do so, but the choices it makes for this and for typecasting aren't always intuitive, and a lot of stuff (like typecasting) happens silently in conditions that are just weird.

That doesn't address your point, though. Your point is that C++ will fake a builtin data type and make it call arbitrary other functions silently to an extent that C won't.
Yep. You're right. And it's a massive debugging headache that it'll do so.
Perl does this "right", too. Perl is the only language I know with a worse reputation for syntactic and semantic cleanliness than C++. Coincidence?

Fair enough. I'd argue that not much inheritance is appropriate for Server, Connection and Player objects -- there usually aren't very many kinds of them. But you're right, they're not physical.

Well, sort of. That doesn't change them if the parent changes, which is my favorite use for data inheritance -- a tree of archetype objects. Skotos' ur-objects are an example of this. Anyway, back to C++.

Yes. Either one will have to build its own inheritance, effectively. It's just that the C++ people will yell at you for not using the built-in language inheritance and then stonewall when you ask "so what do I do about inheriting at runtime?" :-)

But seriously -- true. I still argue that C++'s extra complexity isn't generally worth the benefit in any environment with more than one coder. When you say that C and C++ break down to the same thing for a given problem, I argue that that supports my argument. They wind up using essentially the same methods to deal with the problem, but C++ has all the extra nastiness you're not using at the moment.

But somebody else on the project may be, and it's allowed to mess you up.

Actually you'd just need an explicit function call rather than implicit one, or a function that copies and passes it back (which is the same thing, basically). But you're right, it wouldn't happen automatically, which can definitely be irritating at times.

I won't argue with you over this one. String should probably have been built into C long ago. Of course, it should also have been built into C++ (or at least the standard library) long ago, and that hasn't happened either.

Clever. By calling this "lose functionality" you skip over the fact that it's just syntactic sugar. Nonetheless: it's just syntactic sugar. C++ used to be implemented with a preprocessor over C, and you know, it wasn't even a very complicated preprocessor. Big, but not complicated.

And to get the speed of an unchecked int you'd have to add an extra function call for unchecked assignments and go through the headache of remembering which you're using. Plus, you can detect errors if you get a problem in a function call. How do you detect an error in the middle of "equals"?

That's true. That's another thing C can't achieve. Looking at the implementation of templates, I frequently sigh in relief that C can't "achieve" that. While this is probably relatively clean with your "checked int" example (when's the last time you genuinely used one of those, BTW?), I'd argue that it's fundamentally backwards to do the same thing with vectors, matrices, or anything where using "+" or "*" is a stretch for the operator involved. It makes for clever, small code (and massive binary size since you're using templates) but you're fundamentally applying very different concepts to a different set of objects using the same syntax. Urgh.

That's only true in cases where the problem domain is well-defined and well-documented, and already defines + and * unambiguously. There are two ways to multiply a pair of 4x4 matrices -- only one is written as multiplication by actual mathematicians, though they don't actually bother to put a star. In fact, if they *do* put a star it frequently means they're talking about inner product, which is a very different operation.

But for most things, it's a lot less obvious what + or * represent. Using operator overloading for math is reasonably clean. The vast majority of the time it's not used for math.

For instance, have you noticed that cin and cout use the bit-shift operators? Eeeeeeewwwww! And that's just in the standard library! You could argue that it sorta makes sense ("look, they're little arrows. Kinda. And arrows mean input and output. Kinda. And we didn't allow overriding the actual arrow, plus it doesn't come in reverse flavor."). But if you did, I'd laugh at you.

I've found that's a better example of the way people choose and overload operators in the real world, which is why I don't touch other people's C++ code any more. There's one exception, but Tom's even pickier than I am about this stuff and he rewrites everything three times to get a clean design.
angelbob is offline   Reply With Quote
Old 03-13-2003, 01:40 PM   #14
Yui Unifex
Senior Member
 
Join Date: Apr 2002
Location: Florida
Posts: 323
Yui Unifex is on a distinguished road
Send a message via ICQ to Yui Unifex Send a message via AIM to Yui Unifex
Question

I don't seem to have any troubles with it. gdb treats user-defined operators the same as other functions. (more on this below)

Not sure what you mean here. In code, copy constructors cascade parent copy constructors down the line. If it's in-game data that's dealt with via an encapsulated datatype, the copy constructor should handle copying it.

Right -- it's an extra step in userspace.

No, it's a legitimate concern. I can write a library of code using these templates (supposing for the moment that C had templates) and never have to worry about the user being able use it with built-in types as well as user-define types. This bit of "syntactic sugar" is very important in reducing the amount of duplicated code and thus errors.

I'm sorry? To get the speed of an unchecked int you would use an unchecked int as the template argument. The "headache of remembering what you're using" can be easily alleviated by a quick dosage of glancing up at your variable declarations =).

Use a debugger =). (From above) gdb allows debugging of operator=() just as it does an equals() function. So long as one remembers that operators can be overloaded and assert their assumptions, everything should be fine.

Oh indeed -- if the operation is not clear then they should be renamed to alleviate this problem. This applies to both overloaded operators and function names, of course =).

Just recently, that's why it popped in my mind =). I was just writing a spacial system module where my coordinate-types are templated. However I was having a problem with my movement setting my coordinates out of the bounds of the node in which I was currently located. A quick CheckedFloat object thrown into the template for my coord (which normally uses regular floats) and I was able to find the problem in a few minutes.

IMO, it should match the way the problem domain works as closely as possible. If it's not possible to match the problem domain, then making up an operator is as you say, likely to cause pain. But this isn't a problem with operator overloading, this is a problem of the discipline of the coder. To argue that C++ or even Perl facilitates undisciplined coding is disingenious because one could easily apply those arguments as reasoning for why everybody should use VB.

You don't have to use it for operations you don't embrace =). If someone on your project uses it against your will then that's an issue that you two need to handle, not a programming language designer. A document on coding standards is important for large projects, and if it's a point of ire for developers then things should be clarified in this document, rather than spoiling the broth by restricting the entire language. This is a big complaint I have about Java.

<grins> The methods I've seen for doing that kind of output have been:
+ operator (Supported by C++)
& operator (VB)
. operator (PHP)
<< operator (C++)

What operator or method (if it's not using operators) would you suggest be used for stream input?
Yui Unifex is offline   Reply With Quote
Old 03-13-2003, 05:18 PM   #15
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
angelbob:
Yui:
How often do you debug other people's code?

angelbob:
Yui:
Knock yourself out:


angelbob:
Yui:
Yup. And yours is still an extra step, just invisible at the language level. I tend not to call that "user space" because I'm used to "user space" meaning "not kernel space".

Yui:
angelbob:
Yui:
In general I semi-agree with you. You can do this with void pointers but it's ugly. It works, but it's ugly. It's also far smaller (in the final binary size) since it doesn't duplicate all the code. It's also more portable since you don't have to worry about template instantiation concerns. And it tends to run faster since you have a smaller amount of code in cache. Plus it doesn't require the extra symbol space that templates do -- you'll note that VC++ generates constant extra errors in STL because the symbols are too long. But you're right, it's uglier, especially if you like angle-brackets.
Templates, though, are a syntactic answer to a semantic problem. Plus they have all the problems I mention in the previous paragraph. And I don't particularly like angle brackets more than stars, just personally :-)

angelbob:
Yui:
So you're not in favor of detecting errors at runtime, then? Operator overloading precludes handling an error if it's returned (because it can't be returned). If your function ever needs to return an error (*cough* stream output *cough*) then there's no good way to deal with this.

There are exceptions, but the way C++ handles those is just *evil*. I'm not saying they can't be done right, but C++ certainly doesn't. They're hard to bolt onto a language after the fact, and C++ barely even tries.

angelbob:
Yui:
Any operator which you can't do in C to a builtin data type has no clear operator name. So operator overloading, which only allows you to use the builtin operator names, has no clear way to name it. What's the correct operator to mean "inner product" for a matrix? How about "outer product"? For a vector, how about "cross product"? I've seen all of these as "*", incidentally. It's probably the best match for all of them. See why I don't trust "*" to be one specific thing?

Yui:
So you're saying that using operator overloading for any problem domain that the operator doesn't perfectly match is a lack of coder discipline? But we'll get back to cin and cout in a minute.

Yui:
The fact that it's possible to affect these things in ways that are invisible means that I have to look through all new submitted code before I can trust using it -- it's not obvious, looking at a declaration, what code is being called. It's not enough for me to set guidelines, there has to be a way to check it. One way to check it is for a function call to be syntactically obvious, so I can say "oh! a function is being called here."

No two developers agree what parts of C++ are an abomination. You use operator overloading and templates, two of my favorite whipping boys. Incidentally, if I were to restrict the use of templates in one of my C++ projects (I don't have any in C++, but let's pretend) then there would be folks like you complaining about that since I'd be "spoiling the broth" on that as well. Where do you draw the line?

I draw the line by saying "no C++". That means I never have to deal with a developer saying "yeah, you have to use templates and overloaded operators, but only on the stuff in my module."

angelbob:
Yui:
None. There is no operator that matches the problem domain so there should be no operator overloading for it. Remember when you said that an operator that doesn't match the problem domain should be renamed?
angelbob is offline   Reply With Quote
Old 03-13-2003, 08:31 PM   #16
Yui Unifex
Senior Member
 
Join Date: Apr 2002
Location: Florida
Posts: 323
Yui Unifex is on a distinguished road
Send a message via ICQ to Yui Unifex Send a message via AIM to Yui Unifex
Question

Quite often. Now what does that have to do with anything? Or are you telling me that since other people do bad things, we should automatically take away all things that have the possibility of being bad?

How could a language possibly add support for ths? This is basically constructing a type from the data of its parent types. But for a language to add support for this, they would have to know how this construction is handled! I think the existing functionality is more than adequate to handle something so simple.

It's quite visible at the language level. But not the user of that library's level. I'm not sure about you, but I use the objects in libraries far more often than I write them, so the 'extra' step ends up paying for itself the moment I use it more than once.

Nope, you can't even do this with void pointers. You would still have to overload an operator. And how would the function know which type to cast as to perform the operation?

If I have a performance problem, I'll profile. Debugging symbols add far more to my binary size than templates do, and I usually keep those in for safe measure. Maybe when we're talking about performance problems will these points be valid.

So when I use a compiler that doesn't support the standard formalized *5 years ago* I'll worry about this ;). Until then, unless I'm writing code for ancient SCO machines, I'll continue to use the feature that's been in every compiler I've ever used across dozens of platforms.

Coupling the error system to the *return type* of the function is stupid. What do you do if you have a legitimate return type but an error condition may also be raised? Exceptions are the answer. And even if you don't like C++'s implementation of them, they work very well for the vast majority of people that don't bother with what is almost always an insignificant performance issue.

No, you even gave an example of a user-defined data type that had a clear operator name in that of operator* for multiply. Your later attempting to show how people overload this for inner and outer product only shows that these people wrote bad code, not that overloading operator* is bad in all cases. Of course you don't trust operator* to be one specific thing, but I've seen factorial() functions that compute the sum rather than the factorial. Therefore using your logic, we should all never use functions, or any abstraction at all. See where the argument falls apart? Overloading operators are no different than any other kind of abstraction, excepting the bizarre stigma you've attached to them.

Yes. But you don't seem to understand that cin/cout, and even plain function calls don't match the problem domain for input/output streaming. It has no defined domain like mathematics does. Therefore they're fully justified in coming up with operators to make it more conveniant to use. Just like the mathematicians of old came up with special characters -- operators shall we say -- to represent certain operations. Going against the problem domain is a lack of coder discipline; tackling an undefined domain and making it more managable is a sign of the opposite.

This is what 'abstraction' is all about! It's not obvious, looking at a function declaration, what code is being called. But any programmer knows that he needs to make an assumption that the name of the function conveys this necessary information. Likewise, when a programmer is working with a class he needs to make an assumption that the type of class *and* the operator being used conveys this necessary information. If it does not, then the operation or the class needs to be renamed. This is a very simple concept.

No two developers agree on how many spaces to indent -- or even if spaces should be used at all in place of tabs -- but that's no excuse for avoiding coming up with coding standards for it on a large project.

Umm. Let's see here:
1) I say that restricting a feature from an entire language because some can do wrong with it is "spoiling the broth".
2) You say that restricting a feature from your own project because some can do wrong with it would have people like me claiming that it is "spoiling the broth".

Do you see the fallacy now? There's a staggering difference in scale between a *language design* and your own project's guidelines. You are free to do whatever you'd like in your own project. But the moment that you step out of your bounds and claim that since you have never seen a great use of something, then mandate that it is useless for everybody else is the moment that I cry foul.

reply.output(poster.name());
reply.output(", you're saying we should not use operator overloading for output streaming?\n");
reply.output("Well, ");
reply.output(poster.name());
reply.output(", I guess we disagree.\n");
Yui Unifex is offline   Reply With Quote
Old 03-17-2003, 06:04 PM   #17
angelbob
Member
 
Join Date: Feb 2003
Location: Bay Area, CA, USA
Posts: 39
angelbob is on a distinguished road
angelbob:
Yui:
Roughly, yes. For instance: I believe that goto's existence in C is an artifact of when the language was designed, and that we'd all be happier without it. Do you believe that goto-less languages should all add it since somebody might use it well at some point?

Yui:
I wasn't suggesting that C++ should do it, just that MUD inheritance in "physical" MUD objects is almost always data inheritance, and only more rarely code inheritance. Thus, I was suggesting that C++'s language support for code inheritance wasn't any great shakes for the MUD environment specifically. There was a point much earlier that a previous poster made claiming that inheritance was very well suited to the MUD environment.

So I'm saying: here's what the MUD environment seems to particularly call for. I don't feel it's a good match for C++'s inheritance. I feel that C++'s inheritance is not a good match for this specific problem.

Clear?

And incidentally, yes, you *can* add language support for it, but the only languages where that would be appropriate are languages for pretty specific applications. MUD scripting languages, for instance.

angelbob:
Yui:
You can't overload the operator in C, no. We still disagree about whether operator overloading is a good thing (surprise, surprise). You can call a function to get the same result, though.

Yui:
True. Most of the performance points I brought up are minor details.

Compilers I've used that don't support "standard" template instantiation: g++ on Linux, SGI's C++ compiler on SGIs, HP's C++ compiler on HP/UX, Sun's C++ compiler on SunOS4 and Solaris. Time during which they haven't supported this: each within the last 5 years. Perhaps they've all been fully fixed since then to fully support it. Would you put money on that? I wouldn't, especially since template specs are actually a *lot* older than 5 years.

Compilers I've used that support namespaces, also a long-standing standard, fully and completely: Um... VC++, maybe? I know there are bugs, but mostly, I think. That haven't: Metrowerks (didn't test templates so I didn't list it above), G++ (fixed now?), SGI C++ compiler, HP C++ compiler, SunOS4 C++ compiler. Didn't test Solaris.

Do you know how long it took them to come up with a "standard" Ada compiler after the language was spec'd? Green Hills makes about the only one in existence, and they certainly aren't the only people who've tried, or the only people that want the Department of Defense contracts involved. Standardizing doesn't make it so.

Yui:
Actually, I don't much care about the performance issue, though it certainly looks significant compared to normal function call overhead. I care about the questionable semantics C++ has for most of this stuff, and the fact that it was bolted on poorly as an afterthought.

I'm aware that they're slow to use, but mainly I'm bothered by the fact that they're *hard* to use, at least correctly and without ugly corner cases.

Yui:
The difference is that there are operations which are named incorrectly, and there are operations that are impossible to name correctly. Multiplication can be named incorrectly -- you can name something you need to do with a name that means something else -- by calling inner produce "*" for instance. But then, if you need to do inner product and you don't call it "*", what do you call it? There IS NO correct operator name.

You could make it a function call instead. But then what happened to all your arguments that operator overloading is better than function calls for that kind of thing?

Yui:
But unfortunately, the symbols you have to work with all have defined meanings in other domains, and in *common* other domains. Function names are usually chosen to avoid other common meanings, and because text is very expressive it's reasonable to avoid most other common meanings. If you choose function names arbitrarily ("I call this operation frobzorgle") then it's not very helpful. But if you call it something misleading ("I choose to call my inner product function 'addition'") it's even worse. Like your factorial example above.

If you overload an operator like bit-shift that has a defined meaning in a related domain, you're being worse than arbitrary. You're being specifically misleading.

Or to put it another way:

cout << "Half the sum is " << sum << 2 << " or at least I hope so.\n";

Can you fix this with parens? Sure. But you're being confusing. The operator is bit-shift and text output in the same expression regardless of how many parentheses you add to it. It's the same problem as using + for string concatenation -- it's inherently confusing when stuck next to + for integer arithmetic. So choosing one of a number of existing symbols with existing meanings (like operators) rather than a richer vocabulary (like words, used for function names) is guaranteeing that you have a lot of unrelated baggage attached to any name you give an operation unless that operation already matches the symbol you're using. As you point out, there is no symbol that matches cin/cout -- they could have used xor (^) or function call with dereference (->) or any of many other operators -- and those would have been confusing, too.

angelbob:
Yui:
One with a very "interesting" execution, but yes. As I argue above, I believe that operator overloading gives a misleading name to almost every operation. If the only available function names were "add", "subtract", "list_reverse" and "dereference" I'd make the same argument about them. I'd argue that if you wanted to sort a linked list and call it "list_reverse" that it would be misleading, even though I don't think "subtract" or "dereference" is a better match for that concept.

So you're saying "but what better matches are there?" and I'm saying "choosing a small fixed number of names with existing different meanings is foolish."

If I were going to write a list reversal function I probably *would* call it list_reverse. I'd still say that a language feature that made you choose from those possible names, even if it were very convenient, would be basically misguided. And that's basically what operator overloading makes you do.

angelbob:
Yui:
No two developers agree on how to make Perl work cleanly -- and as a result, they never use it on big multiperson projects, or they do it so that it exists only in little chunks that can't touch each other, or anything else. There are exceptions, and they tend to be ugly. (Incidentally -- I *like* perl, don't get me wrong, and I use it frequently, but I still wouldn't build a MUD in it).

So when the original poster (remember when we had a topic?) asked "C, or C++?" I said "C". You're right, having a standard will help to prevent whatever subset of C++ you don't like from getting into the project. In practice it rarely works that way since you wind up having to rewrite submissions from people that didn't read the standards, but we'll pretend it always works. Fine.

Still, I believe that operator overloading is essentially wrongheaded, and that it should be avoided. I believe that a fine way to avoid it is to use a language that doesn't support it. If there was a variant dialect of C++ that added only features that you hated, would you declare that your project didn't use them, or would you just use the compiler that enforced the set of features you used?

Would you police your project standard by using a tool that did so for you, or would you say "well, I shouldn't discriminate against the language" and use the compiler that didn't?

I have a guess which one you'd do. And I *know* which one I do.

Yui:
The question in the original post was "C or C++". I chose C. You're welcome to say I'm being pigheaded and unreasonable by doing my MUD projects in C (old ones -- my new one is in LPC, which also doesn't have operator overloading).

So when I say "you should use C on your project. I do. Here are the features you avoid other people using, and some reasons I dislike them", you say I'm spoiling the broth. Of course, you also claim I'm altering the design of C++ by using C, but I'll ignore that for the moment, shall I?

cout << poster.name() << ", I am indeed.\n";
cout << "While I agree that your way works better for "
<< output_code.bold() << output_code.color("green")
<< "some" << output_code.unbold()
<< output_code.color("white");
cout << " things, I think there are others that help to";
cout << " counterbalance them.\n";

printf("Right-side formatting, for instance. And tables.\n");
printf("So, %s, I do say that. And yes, %s, we DO "
"disagree.", poster_name(), poster_name());
angelbob is offline   Reply With Quote
Old 03-17-2003, 08:27 PM   #18
Yui Unifex
Senior Member
 
Join Date: Apr 2002
Location: Florida
Posts: 323
Yui Unifex is on a distinguished road
Send a message via ICQ to Yui Unifex Send a message via AIM to Yui Unifex
Question

Actually, I was going to bring up this point myself =). I do think that goto-less languages should put it on their todo list. Despite Djikstra's warnings on the harmfulness of goto, Knuth has shown that it can be used to create elegant algorithms. Steve McConnell, author of Code Complete, has an excerpt from his book on the subject that goes much further in-depth than I could.

But my point was that with this code:
[code] typedef mytype int;
void dosomething (mytype &m) { m = 5; }[/quote]
You would have to go back and insert function calls if you later decided to use a user-defined type. This drastically reduces the genericity of the code. Even though the result may be the same, you have to jump through a lot more hoops to bring it about.

I don't know about all of those compilers, but for a few (like g++ and VC++), the only unsupported important operation is 'export', which would require a restructuring of both C and C++ compilation methods. But you were concerned about 'template instantiation concerns', which is portable across all systems I've come across. If that weren't portable, those systems wouldn't be able to support the STL, a great deal of the C++ Standard Library, which would cause even more problems. The lack of export, while unfortunate, does not mean that most valid C++ template code is unportable, however.

Yes, g++ 3.x supports namespaces. Can't say for the other compilers, as I haven't used them recently.

Wait, I thought operator overloading precluded handling an error was what concerned you? Regardless of how you think C++ exceptions are implemented, that statement is false.

I agree, if there is not a valid operator for the operation, one should not overload an operator for it. Exceptions to this statement are when there are no valid functions either, as in input/output streaming, and when the operator is similar to what one has come to expect, as in overloading operator[] with a char * for an array index.

No, I never said that operator overloading was better than making function calls in all cases. I said that it is better when it meets a certain criteria, defined above. I do agree that inner product should be implemented as a function call. But I also think that multiplication (scalar and matrix) should be implemented as overloaded operators because it is far more intuitive and easy to genericize than the alternative.

I agree. But I don't think that the domain of bit-shifting is at all related to that of input and output. Or rather, it is at least as related as the original bit-shift operator and the relational > and <. Because of the finite amount of symbols in the western alphabet, nearly every operator has different meanings in different contexts. Is that # for number or # for sharp? ^ for XOR or ^ for raising to the power of or ^ to denote superscript? As you can see, just because it's possible to use the same operator on another object doesn't mean overloading that operator for a different object is necessarily bad. Especially when it has such advantages over the alternatives [more below].

Ah, but you've stumbled upon one of the major shortcomings of format strings. Namely, they cannot handle user-defined types. If poster_name() returns a 'string' object or something else, you would have to go back and insert convertors into every one of your output methods to convert it to the right type. Whereas with the cin/cout method, I simply change the return-type of my operation, and I'm done.

There are several libraries that solve the attribute problem by overloading operator<< so that one may use format-strings just as you do for printf(). These are immune to the problems I mentioned, though, because one should not insert the actual data using these formatters.

No, operator overloading does not "make you" choose an operator when a function name would be more appropriate. All it does is add more choice so that you can pick the best option available. Positing that an optional feature restricts choice more than languages that don't have such a thing is ridiculous.

I would be hard-pressed to say that I hated a particular feature, granted that it was really a feature (case insensitivity comes to mind). Anything that adds to my programmer's toolbox and increases the expressiveness of my code can only bring good, IMO. I think it's incredibly difficult to assert that a feature is always bad. Even case insensitivity has its uses =).

No, not at all. I said that if one were to assert that operator overloading was always bad (You said that they, along with templates, were an abomination: "No two developers agree what parts of C++ are an abomination. You use operator overloading and templates, two of my favorite whipping boys". But you also said that it was clean for math operations: "Using operator overloading for math is reasonably clean"), that it would ruin it for those of us that find the feature useful. I think it's perfectly alright, encouraged even, to actively advocate why one likes / dislike certain things, so long as one realizes that there may be untold uses for certain things.

No. Where did I claim this? I said that a language designer need not be concerned if there are potential abuses for otherwise useful features (that is, they should not be too concerned -- they should of course try to minimize the chances and impact of abuse).
Yui Unifex is offline   Reply With Quote
Old 03-18-2003, 02:43 PM   #19
shadowfyr
Senior Member
 
Join Date: Oct 2002
Posts: 310
shadowfyr will become famous soon enough
shadowfyr is offline   Reply With Quote
Old 03-21-2003, 09:59 AM   #20
Kastagaar
Member
 
Join Date: Apr 2002
Location: Hampshire, UK
Posts: 117
Kastagaar is on a distinguished road
Send a message via Yahoo to Kastagaar
Kastagaar is offline   Reply With Quote
Reply


Thread Tools


Which is preferred? - Similar Threads
Thread Thread Starter Forum Replies Last Post
Preferred Role Playing Level enigma@zebedee Advertising for Players 27 04-23-2003 07:01 AM

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off

All times are GMT -4. The time now is 05:51 AM.


Powered by vBulletin® Version 3.6.7
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Style based on a design by Essilor
Copyright Top Mud Sites.com 2022