Top Mud Sites Forum

Top Mud Sites Forum (http://www.topmudsites.com/forums/index.php)
-   MUD Coding (http://www.topmudsites.com/forums/forumdisplay.php?f=9)
-   -   Which is preferred? (http://www.topmudsites.com/forums/showthread.php?t=317)

Vesper 01-24-2003 01:14 PM

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?

Yui Unifex 01-24-2003 02:04 PM

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

Vesper 01-25-2003 02:49 AM

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?

Yui Unifex 01-25-2003 09:18 AM

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.

Ingham 01-27-2003 05:29 AM

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.

KaVir 01-27-2003 07:06 AM

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.

angelbob 02-22-2003 02:23 PM

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

Lindahl 03-10-2003 05:45 PM

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.

angelbob 03-11-2003 06:31 PM

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 03-11-2003 06:50 PM

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.

enigma@zebedee 03-11-2003 06:52 PM

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.

Yui Unifex 03-12-2003 10:47 AM

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.

angelbob 03-13-2003 12:43 PM

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

Yui Unifex 03-13-2003 01:40 PM

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?

angelbob 03-13-2003 05:18 PM

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?

Yui Unifex 03-13-2003 08:31 PM

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");

angelbob 03-17-2003 06:04 PM

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());

Yui Unifex 03-17-2003 08:27 PM

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

shadowfyr 03-18-2003 02:43 PM


Kastagaar 03-21-2003 09:59 AM


angelbob 03-26-2003 02:59 PM

Your argument (Yui) that every feature is a good feature because it improves the expressivity of the language is interesting. Are you a massive fan of Perl for large projects for that reason?

My problem with C++ in practice has been that the average quality of code I've seen is terrible, even compared to similar projects in C. And the code I'm talking about is actually at professional software companies I've worked at. By "terrible" I mean "prone to crash/deadlock and hard to debug". The problems have been that different people use different subsets of the language, nobody knows the whole language, and you have to debug the code of people that use a different subset of the language than you do.

In a programming project that you control, you get to be the autocrat and spend a lot of time tearing misused or "wrong" (i.e. forbidden) features out of code other people submitted. As in a professional software environment, nobody reads the coding standards and nobody follows them, so you still have to go in and fix the results afterward.

Fair enough.

Goto is a fine example of the same principle. There are specific examples where it's basically acceptable. Palm (the company) used it for about the same purpose you list above, though with a couple more restrictions. Nonetheless, the vast majority of C code I've seen using "goto" is quite bad. Overall, its existence has done far more harm than good for the maintainability of the code I've seen in my professional career. In my private code I don't work on C++ projects with other people so it's a non-issue.

I'd like to again draw attention to the phrase I used above, the one that goes "nobody knows the whole language". C is a pretty snappy little language, and a clever fellow can figure out the whole thing and know the vast majority of the subtleties (what does "++bob++" do if "bob" is an integer? Is it legal? Which has higher precedence?) within a couple of years of regular use.

I've interviewed with a guy who was on the C++ ANSI standards committee. I've worked professionally in C++ for several years, and I've worked with many people who use it very regularly. I've built C++ parsing code, code to produce it from a template, debugged massive systems and worked under about four different template libraries in it at three different major companies. What I have never done, though, is to meet somebody with a very firm grasp of all the current standard language subtleties and how they work together.

By contrast, I've probably met about six people who could say that for C and who actually keep up with all the latest ANSI standards. Perl, like, C++, seems to have no full-on experts. It's simply too big, too varied and too weird.

Like you say, we could just rule out big chunks of the language and be an expert on the rest. If you believe that will work, you've worked on very different projects with very different people than I have. At least at the companies I've worked at and on the OSS projects I've worked on, you can't get people to follow the project's coding standards without constant and painful enforcement.

Though I suppose, if you had any significant number of contributors, you could just reduce your whole role to "constant and painful enforcement". That's what I've been doing primarily on my project lately -- and I'm using a simpler, cleaner language than C++.

Yui Unifex 03-26-2003 05:13 PM

I don't believe that every feature is good because some features are 'forced', or are mutually exclusive with other features. Case insensitivity is an example I gave of one such feature that has advantages at some times, and disadvantages at others. If there's a large project, knowing how to take advantage of Perl's features gives me an edge over someone who does not know how to take advantage of those features. So if the large project is something like a system administration front-end that is heavy on the regular expression parsing (see the Cobalt RaQ's backend system), Perl would indeed be a good choice. If the large project is very performance intensive, then Perl would probably not be. It's all about choosing the right tool for the job; I will never blindly advocate that one language is the best for all purposes.

This is a fair judgement. My experiences have been mixed: I've had to debug C programs written to control PLC-enabled conveyor systems while talking to an Informix database. Problem ended up being a bug in the linked list structure that the previous programmer (now long gone) had rolled. In my business (basically an employed software consultant), I get to talk to a *lot* of software development houses, and I almost always end up wondering how in the world these people stay afloat with their limited knowledge. I would not be so quick to trust their code with any language.

If you're having problems with people not reading and following coding standards in a professional environment, something's not right. This is one of the easier things for the coders to grasp; all they need to do is consult a list.

Just to make sure that you're not arguing for this: Language designers, to an extent, should not be responsible for these problems. They arise mostly from user-error; to remove it would be like removing 'dd' from unix systems because it's possible to destroy the hard drive with it. There are certain things they could do to reduce the desirability of goto, such as using named breaks to take care of the issues that shadowfyr raised, and these are things that language designers rightly should be concerned with.

As languages get higher and higher level, and people are able to express more and more constructs in them, it will indeed be difficult for programmers to learn the subtleties of an entire language. But I don't see this as a bad thing; if one absolutely requires that there be no subtleties at all, one should then use a language with no subtleties. But if one wants to make use of higher-level features such as closures and polymorphism, one will have to accept this complexity. Complexity at the language level here leads to simplicity at the algorithmic level. The right tool for the job is what should be chosen. We don't communicate with grunts and gestures, even though they would be totally unambiguous, with absolutely no side-effects, than the higher-level languages that we all speak.

Yes, I do believe that will work. This is what humanity has been spiraling towards ever since the concept of 'specialization' has been discovered. To understand the complexities of nature one has used abstraction and specialization. I see nothing wrong with it, and if today's generation of programmers can't handle it (but they can ;)), then the next generation will replace them. Designing to the least-common-denominator is a sure-fire way to encourage mediocrity rather than excellence.

However you may define 'cleaner', it has already been shown (and gone uncontested) that C++ is cleaner than C in some cases. It would be more correct to say, "I'm using a simpler language that is cleaner than C++ in some cases". Remember that absolutes are absolutely horrid things; their scope is so grand that they are nearly impossible to prove, but they are ridiculously simple to disprove.

angelbob 03-26-2003 08:29 PM

Yui:
Sure, but what about features that are just hard to read, even when they're easy to write? I mention Perl specifically because it gets such a reputation as a write-only language. It gets this reputation because of things like its regular expression syntax (very difficult to read, and very small subtleties can change the meaning a *lot*) and the fact that a tremendously wide variety of inputs can parse to *something*.

One reason I'll call a language "clean" is if no two valid inputs in the language look very similar to each other. That is to say, if any two valid inputs in the language are reasonably easy to disambiguate from each other, especially two inputs which are basically dissimilar.
And by "disambiguate", I mean only if you're reading it. A parser, of course, won't have much trouble either way.

If you're *writing*, as opposed to reading or modifying, I agree with this statement.

Actually, Perl's remarkably fast. It's not quite up with static compiled languages like C or Pascal, and certainly not Fortran. On the other hand, it compares very favorably to anything interpreted and most things that are compiled.
That's mainly because they have a really good optimizer, though, and the fact that the whole language is designed with that in mind.
Anyway. Sorry. Off-topic.

Because good people are extremely rare. Software houses that employ a very small number of very good people will essentially never go out of business. They will also very, very rarely get really big. Most markets require a lot of customer service, and a lot of very large software to be built. Therefore, any approach that requires a very high average level of brilliance, or that allows brilliant people to be easily sabotaged by idiots they're working with, won't grow to fill the niche. It will instead be overtaken by a small army of strongly competent fellows who are, collectively, more brilliant than the five incredibly savvy guys at the other company.

That's just one of the many reasons that languages that allow good modularity are so popular.

And you're successfully making coders do that, even though no two can agree on a good coding standard, how? The only correct answer is "enforcement". The only common answer is "optimism". Where have you worked, that you haven't had problems with this? My experience with free projects is that carefully-written, carefully-posted and carefully-followed coding standards are all well and good, but free contributors simply will not follow them unless you enforce rigidly.

The same is essentially true at a professional software house, and nobody wants their job to be enforcing coding standards. Well, okay, John did, but we laid him off and he left for Norway. It's a shame, he was good at it.


Very much like that, yes. Ever notice how on modern Linux systems, root logins come configured by default to alias "rm" to "rm -i"? So instead of deleting files automatically, it'll ask to make sure you typed what you meant.

One could imagine a similar scenario where "dd" was aliased to always prompt when you used it on a hardware device (rather than just a file), so it would make you specifically say "yes" before doing something potentially stupid. The DOS "Format" command already does/did that.

I consider all of those to be basically good things. Should language designers avoid easily-abusable features in favor of features that tend to produce better code on average? Absolutely. Unquestionably. Should they remove features (like pointers) that can sabotage other people's work silently and without them specifically opting into it? Where possible, yes. Pointers specifically are a great example of a feature which can't be removed without a speed hit. I still try to use languages without them, where possible and appropriate.

Would any given lanuage be better if we added a bunch of new features? Maybe. CommonLISP plus pointers, for instance, or Java plus pointers, would be a step back. SML plus pointers would be an abomination -- like C++, it would have sabotaged its greatest asset, though for different reasons.

"Sabotaged its greatest asset?" Yeah. Being object-oriented is C++'s greatest asset. That means a real type system. The basis of data protection in a type system (private, protected, static, etc) is enforcement. Private fields aren't private as long as C++ has pointers.

Anyway. Sorry. That's a different anti-C++ tirade, and it's not like C has a real type system either -- it just doesn't pretend to.

Yui:
Thank you. This is a very concise restatement of what I said earlier about "hard to debug" and "other people's code".
Incidentally, there *are* new languages that focus on having fewer features rather than more, and some of them are very much improved by it. SCHEME is easily embeddable because of it. SML/NJ is possible because of it -- full static type analysis is essentially impossible on most imperative programming languages, and you wouldn't want it anyway. Java is cleaner because of it, having removed some nastiness that C++ added.

Sort of. You're saying here "to use closure and polymorphism, you must use a language with enough subtleties that nobody will properly understand the language". My counterexamples are Scheme, CommonLISP, Dylan and SML (for closures) and CommonLISP, Dylan, SML, LPC, SmallTalk (for polymorphism). Note that there are a decent number of languages even in the intersection of the two.

Beyond a certain number of simultaneous features, you're right, you have to have a language that's too complicated to understand. Speaking of which, if C++ has closures then we mean two very different things by "closures" or C++ has added a feature I'm not familiar with. I'm used to closures requiring lambda functions or something like them.

Actually, grunts have no established meaning and are entirely ambiguous. And complexity at the language level adds to simplicity at the algorithmic level only if you can match a language primitive with the task at hand. Near-misses on language primitives are usually as bad as not having anything at all (such as using code inheritance for physical MUD objects, as we discussed earlier, or using C++ inheritance for a system with dynamic inheritance).

For common structures (such as lists and hash tables), though, I agree -- complexity at the language level leads to simplicity at the algorithmic level. Though the stuff we were discussing earlier was all simplicity at the syntactic level, which I consider to be a separate issue.

More specifically, complexity at the standard library level tends to lead to simplicity at the algorithmic level. Complexity at the language level tends to lead to simplicity at the syntactic level.

So you feel that the potter's wheel was designed to allow more variation than shaping clay with your hands? Nope. *Less*. There are *fewer* shapes that can be manufactured with a potter's wheel, and those shapes can be created with less effort for each one. By *restricting* the expressiveness of the medium, the total labor can be reduced.
Specialization *restricts* the vocabulary of an individual, and even of a socity -- you see practically nobody that works in clay/glass hybrid objects because those are considered separate specializations so there's little overlap. That wasn't always true.

But by restricting the expressiveness of the media involved, we get everything with less labor. Old fabrics, done by hand on a loom made of strings and a rock were more complex than the most impressive stuff we can do on our big modern computer-controlled looms -- and yet our modern stuff produces it at a tiny fraction of the cost, so we're wearing simpler fabrics and not worrying about it.

By *restricting* expressiveness, we've reduced total labor.

And in the same way, the fact that I use C means I'll never have to debug a code submission that requires me to understand all the stuff that can go wrong with C++ code templates. I've saved myself a couple of months of my life that way, and I'm happy about it.

Yup. Garbage collection is argued against for the same reason -- it doesn't require you to track everything, and so it'll be overrun by higher-performance languages where you have to track all the allocations by your lonesome. The results are better, even if they're more error-prone and require more intelligent programmers.

And Perl, Python and Java overtake C and C++ while we stand in denial, because there are fifty times more people who can be perfectly adequate programmers than can be brilliant programmers, and fifty adequate guys is worth at least two brilliant guys. More on some problems. Only two? Sure. But that's still twice what the brilliant guy can do.

Of course, you could also make sure that the language the only-adequate people use is sufficiently "expressive", and then none of them can debug it. Lamentably, that's why something as awful as Visual Basic is also overtaking C and C++.

Well, except absolutes like "A and B implies A", or "not not not A implies not A", and absolutes like "this car is painted red". Which would prove your point nicely if it didn't also disprove your point.

But yes, C++ is cleaner for some specific things. The things you proved it was cleaner for were specific C++ language features (C sucks for operator overloading, I'll grant you), and ones that I feel still shouldn't be used. But in the same way that APL or Fortran absolutely rocks if you need to take the inverse transpose of the product of a 9x7 with a 7x15 matrix, C++ rocks for operator overloading.

Incidentally, APL is another long-forgotten example of a write-only language in a very specific domain. It does array processing (thus the name). It has operators for, like, everything you can do to an array. But since nobody remembers what the operators do when they read them, it doesn't matter -- the code's simply not maintainable. Rather like the way some parts of the Perl regexp system work, or some of the finer points of C++ RTTI and typecasting stuff.

karlan 03-26-2003 08:33 PM

A lot of the arguments being used seem to me to be more about how people use it. If a company has standards that people should be using they should use it. Ihave worked for a couple of companies with different coding standards, and when people have followed the standard it is often simple to maintain/modify other peoples code, the exceptions to this were the "prima donna" programmers who felt they were indispensible and so didn't have to follow the standards, and they produced hard to understand, and difficult to follow code. This is not a problem with the language but with the programmer.

If nothing else a little bit of concise commenting can simplify maintenace a whole lot.

just my 2c

angelbob 03-27-2003 05:01 PM

Karlan:
Well, yes. Assembly language can be used quite well, commented well, macros added, et cetera. Nonetheless, if somebody was to ask me "should people use C or assembly?" I would immediately answer "C, if possible".

Even though assembly is capable of things that C is not. Even though using C instead of assembly is compensating for programmers being less brilliant rather than making them work for their good code. Even though the maximum quality of the code is less than for assembly. Even though the arguments for using C are all about how people use assembly, not whether it can be done well.

Despite all of those things, I'd still recommend C over assembly. Ditto for C++. And the Future Crew, who did wonderful demos in assembly language, can laugh at me all they like.

karlan 03-27-2003 08:16 PM

Are you saying you feel C++ is a step forwards or backwards from C?

Yui Unifex 03-27-2003 08:30 PM

Yes, even those features.

What? Given that almost all projects spend most of their lifetime in the maintenance stage, I obviously wouldn't know how to take advantage of Perl's features if I couldn't read or modify it. I was able to extend the Cobalt RaQ's Perl administration application with little difficulty, and I've barely written 200 lines of Perl. Either I'm a genius or the program was easy to modify, and I don't think it's the former.

To go against the style of the project is both unprofessional and sloppy, no matter how poor the style of the original project is. If you think your style is better than the one being used, hash it out with the project manager. I should not have to mentally switch between X number of styles when I go to maintain the code in the project. If your coleagues have problems with this, I do suggest "enforcement". But honestly, most people I've worked with don't need to be told about something so basic. It's only the interns and prima donnas (as karlan mentioned) that seem to have problems with it.

First of all, C++ is a multi-paradigm language, and this is its greatest asset, IMO. Its type system is "real"; it's called "strong typing". If you have to cast something, you'll very often get undefined behavior. And no, pointers do not have anything to do with the privacy of a field, because only the class can decide whether to allow a pointer to a private field to exist. This is the exact same with Java and references. This sabotage is completely non-existant.

*grunt* now means "pizza". Now grunts have established meaning and we can continue with our regularly scheduled programming. Honestly, no language has an established meaning other than what the users of that language assign to it. To get back to the point, if one were to have complete simplicity with absolutely no abstraction nor any "subtleties", that is the linguistic equivalent of assembly. But to everyone's chagrin, we now use languages that can express higher levels of abstraction: C has more than asm, C++ has more than C, Python more than C++, Common LISP more than Python.

No. A language primitive need only match a neighboring part of the construction of the task to increase simplicity at the algorithmic level.

By using a wheel a potter is not restricting what he can create! Using a wheel does not preclude the potter from shaping with his hands once the general shape has been achieved. It is just a tool; the equivalent of a subset of a language, not the language itself.

Not even close. Name one speciality that *restricts* your vocabulary rather than merely drilling down into the complexity of a subject.

The most ironic thing is that these are all arguments for why C++ should be encouraged:
The modern textile factory is vastly more complex than the looms of old. It has higher-level constructs (machines, assembly-line) as a whole, even if the role of the individual is lessened in the Big Picture. So I agree with your argument here. C++ in some cases will allow you to produce stuff at a tiny fraction of the cost, because there are more higher-level constructs that one can make use of.

You've completely missed the point. If garbage collection were an *optional* feature, it could be used in cases where it was beneficial and avoided where it was not. Designing to the least-common-denominator is only an argument against garbage collection when that feature is forced upon the users. You should understand by now that I am arguing the exact opposite of this.

*cheers*

To enumerate the covered advantages of C++ (vs. C) in our debate:
1) When you want generic code such that a user of your library can call functions with both user-defined and built-in types.
2) When you want to change the return value of a function used in I/O without having to go back and change all users of that return value.
3) When you want an error-handling system that is not coupled to the return type of functions.
4) When you want natural math operations with user-defined types.
5) When you don't want to write Yet Another Linked List, or Yet Another String Handling System.
6) When you want to use strings with pass-by-value semantics.

And for C:
1) When you don't want to deal with other people doing something you don't understand or don't like.

(Edit: Added 'or don't like' to C's advantage.)

Lindahl 03-28-2003 12:12 AM


angelbob 03-28-2003 03:05 PM

Karlan:
I'm arguing it's backwards. Yui is arguing that it's forwards. That's our basic disagreement.

His argument is: C plus more features must be better than C. My argument: C plus features that are frequently misused is generally worse than C.

Beyond that, we're just hashing through whether C++'s features are generally a good or bad thing. His argument: the potential upside is greater since you don't have to use bad stuff, or use stuff badly. My argument: this stuff is generally used badly.

There's a lot more detail, but you can read through at your leisure, this stuff's probably on the 'net forever.

angelbob 03-28-2003 04:18 PM


Yui Unifex 03-28-2003 06:38 PM

I am in favor of choice in all features. If one is doing rapid development or prototyping, those features can be immensely useful. So long as these features are not mandatory I am in favor of them. Since I have said this many times and you still can't seem to grasp it: I am in favor of optional features.

Sounds like either you did something wrong here or you ran into a compiler bug. If assigning the memory address of a child to a parent is legal, and downcasting changes the value of the memory address of the child, you would wreak havoc on your data. Way to go, blaming somebody else's irresponsibility on language designers.

You obviously didn't know that the above wasn't the language's fault, you didn't know that you could catch exceptions at runtime inside of operators, you didn't know that operators could be debugged just like normal functions... I'd say you have a pretty poor understanding of these features of C++ that you've used -- supposing that you've used the features that you're arguing about.

Exactly. Because the project manager understands that changing the style of the entire codebase is a large undertaking (without a beautifier, of course), and he knows that individual coders should not go gung-ho on styles because that leads to inconsistency.

And the language designers are not responsible for your organization's negligance.

Yes, I just knew that the C++ language designers should have guarunteed the privacy of data once undefined operations have occurred. Anybody that has access to the memory behind your class can change it; a language can never guaruntee such a thing without total control of the OS. If you expect the integrity of your class (which private members are supposed to help protect, but cannot protect absolutely) to be maintained when you've done something as brain damaged as the above code fragment, you're living in a dream world.

More like destroyed by idiocy... Give me any language with "strong typing" and I'll destroy its integrity by modifying its memory. You've set unreasonable standards for strong typing that no language can live up to.

"nobody works in both ceramic and glass" is not the same thing as "working in ceramics restricts your working with glass". Take a course or two in logic and call me in the morning.

There are millions of people that speak more than one language fluently. Just because angelbob came in and said that this was too difficult to comprehend doesn't stop them from using whichever subsets of that language they feel would best express their thoughts. The real shocker is that these people can still communicate pretty effectively with people that only speak one of the languages they know; obviously they wouldn't be able to communicate if they expressed their thoughts in the language that their target did not know. It is up to the speaker and the speakee to negotiate this -- not you.

So we should all use VB. C sucks because it's got language features that are hard to understand (pointers! strings as arrays!). Glad that's settled now.

Yui Unifex 03-28-2003 11:02 PM

Almost forgot this gem:
Um, ocaml has Obj.magic that allows you to do similar things to the C++ pointer casting. GNU Smalltalk allows one to directly access the memory behind classes, look at the typeAt accessors. So yes, languages with 'serious type systems' also cannot live up to the silly standards you've created.

Lindahl 03-30-2003 07:06 PM

In fact, I'd argue that pointers cause more problems in C/C++ than the combination of all features in C++. Should we remove them from the language? Does that make pointers a bad idea? Not at all, it allows the programmer to operate the code at a lower level.

angelbob 03-31-2003 04:54 PM

You could argue that the former is true. The latter is not. That's actually expected behavior. Try it yourself. Create a class A and a class B (I used both virtual, but you don't have to). Make a class C that inherits from both. Typecast a C-pointer to an A-pointer and a B-pointer. Print out the numerical values of all pointers concerned. One, but not both, of the A-pointer and the B-pointer will be the same as the C-pointer. The other will not. There's no decent way around this. If you typecast to a void pointer in between, there's no way for the language to know what the fudged fixup modifier is, so it just leaves the pointer numerically the same, which breaks either the A-pointer or the B-pointer. Usually the first parent class is fine and all later parent classes break -- that's how VC++ does it, and I think GCC as well.

Whose responsibility is that, if not the language designers? The compiler writers, I guess. I'm not sure. Who are you blaming here, besides me? The language doesn't specify the bitwise layout that causes this problem, it just specifies a situation where you pretty much have to do it this way, so everyone does.

Actually, I was well aware that you can use exceptions. I've just used compilers that support them poorly, so I don't use them. I've also worked with programmers that understood them poorly so (thank God) we didn't use them. And I'm aware that you can debug an operator like any other function, and that debuggers tend to support it poorly, and you can't return an error code, and using it in questionably-matched problem domains is (still) a bad idea.

And yet they do so much to enable it in C++, and so little in a number of other languages.

Well, if not then having a "strong type system" deserves to be in quotes, as I continue to express it.

You're assuming that anything that isn't directly ruled out isn't affected. You're also assuming that anything optional will have no bad effects on behavior. You know how silly that sounds, right?

"We made sure that murder was optional, so we figure it won't cause any problems. Our laws aren't responsible for your neighbor's maliciousness. Move to a better neighborhood."

Even in Switzerland (and similar places) where they have more than one official language and more than one language commonly spoken, they tend to speak only one. If adding features is always good, why don't the Swiss constantly speak a French/German/English pidgin to everyone they meet? They know all the component parts, and so does almost everybody they speak to. Is it just angelbob-style contrariness on their part?

And yet if they were writing for a mass audience, or even more than one person, they'd still be better off choosing one or the other and sticking to it. And the fact that the two languages are independently defined (are the subsets of C++? Where?) means that they can easily and quickly determine what subset to use, and they don't have to remember individually whether, for instance, Swahili animal names are being used with English grammars in this specific setting.

Shall I throw your comment about a class in logic back at you now, or wait until later?

To make this explicit: you've taken my position, extended it to its most ridiculous extreme, and thrown it back at me as though I'd said it. "All those liberals should just move to Iraq".

angelbob 03-31-2003 05:02 PM


angelbob 03-31-2003 07:17 PM

Here's maybe a better example. There are many languages where it's common to know multiple at once. English and Spanish is a common combination, as is French with German (again, as in Switzerland).

These combinations obviously give a combined language with more expressivity than either one individually. French and English are both legendary for their ability to express uncommon and subtle shades of meaning, when used by an excellent speaker. So English-plus-Spanish must beat the #### out of Spanish, and French-plus-German must beat the #### out of German.

There are academic treatises that occasionally intersperse specific phrases in other languages ("Gestalt" being used as a psychiatric term, for instance). They almost universally go to the trouble of defining those terms, or make them entirely optional to understanding the text rather than using them fully (as with books containing random quotes in Latin at the start of chapters). That seems odd given your contention that more features always makes a language better, and given the obviously greater expressivity of those combined languages. Where are all the books written in French-plus-German?

angelbob 03-31-2003 07:28 PM

Ah, here we go. You're representing me as though I were saying "C++ shouldn't exist." Do you remember, way back when, what this thread was about? Somebody asked for a language recommendation.

If I thought English was the right language to use, I wouldn't recommend English-plus-Swahili, even if everybody involved spoke both English and Swahili. Why not? Because some day, God forbid, somebody new might show up on the project, and making sure they're fluent in English-plus-Swahili is a lot harder than making sure they're fluent in English. As a culture Imperialist (yup, guilty as charged) I believe that English &copy; is better than Swahili (single-dispatch OO done on top of pointers) so I feel that an unholy hybrid of the languages gains very little on top of English, and causes more problems than it solves.

I'm not saying people shouldn't speak whatever unholy hybrid they like in the privacy of their own homes. But if somebody asks me "C/English or a hybrid?" I'll immediately answer "C/English" without a qualm and without batting an eyebrow.

I *do* like OO for some things. It's just that what I think of as OO is very poorly represented by C++. LPC isn't all that much better but it cleans up most of the worst nastiness. Java does too, though less so.

Dylan's awfully nice. I'll never write a MUD in it, though, since there'd never be a second developer on the project.

C++? Nope. Too many of its "benefits" over C are things that I would never use personally, and that I've usually seen used badly by other people. Since I would never want to debug another developer's C++ code submissions, I say "C" not "C++".

Is the context clearer now?

Yui Unifex 03-31-2003 07:33 PM

I see you're using multiple inheritence -- I'm sorry, I must have misunderstood your earlier post and thought that it was a single hierarchy.

It is plainly obvious why this is not a bug, however: Class A and class B simply can not share the same memory address. When assigning a pointer to one of the parents here, you have to grab the part of C where B starts. So you should get an address like sizeof(overlapping parent)+sizeof(object overhead)+address. So what exactly is the problem here? The only way to fix this would be to make A and B both share the same address, and that's impossible.

You can return an error code from "in place" operators where the "real" return value is not something essential to the operation. This tends to break other idioms and is certain to confuse readers of your code, but it's definately possible.

Few non-functional, non-dynamic languages have achieved the flexibility and genericity that C++ has. Every one of the features you consider 'bad' has a use that would cause severe detriment were it removed.

That is incorrect. I said that they were not the same as each other. I don't know where you came up with this.
That is also incorrect. Where did this come from?

I don't think you understood me here. Restricting people from working in both ceramics and glass is radically different than allowing people to choose a specialty of their own accord. In one case, people are forced into what they do. In the other, they still have the choice to make some sort of ceramic-glass hybrid (It'll take the world by storm!) if they felt like it. As you can see, they are plainly not the same thing.

Here we move into the realm of principle. More on this in another post.

I'm not Swiss, nor am I a Sociologist, nor am I in a position to understand their situation. But anyone with a little savoir-faire knows that parts of languages tend to seep into others, neh?

Just as all people do not always write for a mass audience, all programmers do not always write for a mass audience.

This is a common tactic amongst logicians, to see how a particular argument stands up to scrutiny. If an argument or position, through extrapolation, condones something that is unacceptable, the argument or position must be revised to correct it. By doing this, I hope that you will either clarify your argument so that the unacceptable situation is avoided, or modify your argument for the same effect. In essence: What makes C and C++ so special that your logic only applies to it and not C and VB? Specifically, the part about certain features being confusing (on average) and thus should be removed from the language.

Even if a language design document states "Private members are never accessible under any circumstances not controlled by the class", these extensions (btw, Obj.magic is part of ocaml's standard library) prove that they were useful enough to include. Even still, one that relies on private members as anything more than a way to keep oneself from making stupid mistakes with regards to encapsulation of data is placing far too much trust in their environment.

Furthermore, unfettered access to a class' memory is very useful for those languages which lack functional properties like closures. It is useful for serialization and optimizations that scrunch classes together to avoid overhead, like a memory pool. There are thousands of C libraries which C++ was designed to interoperate with, that require a void or char pointer and a size, and then provide an operation on that memory. C++ wouldn't be operating as designed if it did not provide this functionality, and provide it easily.

They're pretty obvious: Every time you see the dereference operator (&), look for an address to be used. References and pointers are too different things.

References come with their own problems. They aren't re-assignable, so you are forced to encapsulate changes to them which causes problems with iteration constructs. They're always "valid", so you can't have a find operation return NULL. And for languages that pass them by value (like Java and Ruby), you have to implement silly workarounds (like encapsulating them in another object) to assign to the base value.

Yui Unifex 03-31-2003 07:42 PM

Books are obviously not the only measure of language. Go to Beijing and watch Channel V sometime, you'll hear tons of music with both Chinese and English lyrics. Same thing over here with Spanish and English, although I don't keep up with that much =). Music is particularly influenced because certain words flow in one language with certain beats better than it does in other languages. It's also quite popular in Japan to plaster English words everywhere, just as it's pretty popular over here to put Japanese symbols on cars. My wife speaks both Mandarin and English, and she converses with the American Chinese community while switching between the two constantly (English for more technical things, Mandarin for the rest). There are plenty more examples of language exchange, but I think I've proven my point -- that the various combinations have a purpose that simply can't be captured using only a pure form.

Yui Unifex 03-31-2003 08:03 PM

Yup, and if you'll look back at my post over there, I also recommended C =).

Our principles are fundamentally different. I believe in free choice of language features, even if it's possible that someone may not choose wisely. I say this because ultimately your language is more powerful. I approach this from the standpoint of an individual: I don't want anybody restricting what I can do with a language, and if I want write a large project in it, the responsibility for enforcement of my practices falls on my own shoulders.

You believe that we should specifically tailor languages so that the general quality of code that the lowest-common-denominator (I think?) writes will be as high as possible. This means either restricting common pitfalls or making it impossible to be caught in them. I agree that C++ does a rather poor job as the latter, but I think this is mainly because it was designed to be backwards-compatible with C,

As you can see, excepting where certain pitfalls be made harder to fall into, these principles do not overlap. In fact, they are mutually exclusive if there are any features that the second school wishes to restrict.

angelbob 03-31-2003 09:39 PM

Thought of in precisely this way, yes. It came as rather a surprise to me at the time, and I had to do a great deal of explaining to the other (professional, highly-educated) C++ programmers I was working with. They hadn't bothered to learn how C++ does its magic at a bitwise level, so ugly little artifacts like this were entirely unintuitive to them. I have yet to see a book on C++ that provides the required background to make any sense of this, in fact. Given that multiple inheritance and typecasting are both quite standard features and are in essentially every C++ book, I consider that an interesting commentary on whether adding features is basically benign.

Well, yes. If it had any more flexibility or genericity in those areas (colloquially: "did it right"), you'd have to call it a dynamic or functional language.

My coming up with that has a lot to do with your arguments about adding features always being a good thing (unless they prevent adding other features) and your claiming that adding features only adds to the expressiveness of a language so I'm obviously being fascist by disagreeing with the use of any feature.

So yes, you *do* know where I came up with that. We've been having this same argument in minor variations for awhile now. But you told me what I needed to know to lose interest. More on that in a second.

Here we go! You're not interested in how badly other people abuse C++ because you don't work with other people regularly and you don't particularly want to. Okay, I'm jiggy with it. Since I have *very* few projects where I don't work with others or plan to in the future, this explains about all I need to know. As I say, "enough to lose interest" :-)

I'm familiar with what you're talking about, and what you did isn't that. For instance: I claimed that C was different from C++ in that a single person will much more commonly know all of C to an extreme degree (John did, I do, I've met others that do), thus enabling somebody to reasonably debug a random sample of code using all language features. Speaking as a former Teaching Assistant who debugged code in a Computer Graphics class, I'm glad we used little or no C++ since I had to read arbitrary code from questionable coders to do that job.

But yes, if you'd stated some assumptions and the principle you were extending, it would be similar. Done crudely, as you did there, it's just mockery. You're welcome to do it, but calling it logic is pretty silly.

Sure, but that's pretty irrelevant to whether it breaks the type system.

I'm not entirely sure what you mean by the whole "not reassignable" thing here. You can reassign a variable which holds a reference to instead hold another reference in Java, LPC, Dylan, Perl and CommonLISP. Which language were you thinking of?

And references aren't always valid, at least in LPC, CommonLISP, Dylan, Perl and (I think) Java, all of which have a NULL value or the equivalent.

You've got me on the Chinese/English thing. Those do tend to be alternated rapidly and constantly by native speakers. Languages borrowing individual phrases from each other and having minor spillover actually *supports* my point -- instead of taking the fully-expressive union of the two languages, they take one of the less-expressive components and timidly add little extra bits of expressiveness to it. Pretty silly if more expressive was always better.

This is the other reason I've lost interest. I'd thought you were suggesting it for him, not for you. What you do by yourself is your business, in pretty much every sense :-P

Roughly. I believe that a programmer of average competence should be able to write very usable, pretty debuggable code, and a programmer of high competence (but not utterly brilliant) should be able to write good, usable, debuggable code. This should be true even if using a fair subset of the language features since the overlap of any five programmers is likely to use the vast majority of the features of a given language -- even Perl :-)

True. I agree entirely. I just don't care about that as an excuse since I already have a perfectly good language that is 100% compatible with C :-)

Okay. Unless we raise a new topic (or you'd like some very specific question addressed), I think I'm done with this thread.

Yui Unifex 03-31-2003 11:10 PM

Debugging and examining memory is mostly a function of the system you're using, not the language. It's so intertwined in C because C is so intertwined in Unix. But one needs to do away with these C assumptions when working with C++. I think this is a case of beginner's wisdom, where you have just enough knowledge to get yourself in trouble.

Even if I thought that adding features was always a good thing, I still never made the silly assumption that they don't affect things that they're not directly related to. If they didn't affect these things, we wouldn't be having this argument. So no, I have no clue how you attributed this assumption to me.

Hahahaha. 50% of what I do professionaly is interface with other people's code. Bad MFC-influenced C++ code. Bad traditional C code written when I was in kindergarten. Bad C++ written by VB programmers. Bad VB written by doctors and financial guys. Large projects and small, you don't call in the consultants until you're sure your code is thoroughly screwed. So yes, I work with a lot of other people and yes, I understand the abuse very, very well. Yet still I hold the position that I do. I've come to realize that there's a lot of screwed up code out there, even in "safe" languages like VB. I simply make language recommendations based on the level of ability I perceive of my clients, nothing more. Note how the original poster had a specific goal, and I made a recommendation that would seem counter to what I've been arguing for this entire time. When there is no stated goal, however, everything is on the table and every last possibility must be accounted for.

So this is your answer: People should only avoid features that are "misused, or commonly misused" within languages that people can not understand to an extreme degree. You base this on the fact more people know C to an extreme than C++. Shouldn't this be obvious though? If one is going to master C++, one will naturally master C in the process. Most of the 'serious' programmers I've met know C++, or are not daunted by a simple debugging session with some random C++ code. With any of the competent programmers I've met, syntax means nothing once the basic idioms are mastered, and google is the instant reference for anything =). So from the start we see that this condition will never be met due to C++ being a superset of C. Many people write books using only a subset of a language. It's not impossible to restrict one's vocabulary, and I've worked on several projects with strict rules (mostly for portability, though, I wouldn't trust a manager that hired a guy that couldn't debug a random subset of valid code). So I disagree with that premise as well. Debugging standard code is a simple matter for most programmers I've met -- it's the library stuff that gets ya =). Thus, it is indeed logic, I simply disagree with the premises that excludes VB.

Then the references to which you refer are basically the same as pointers that memory arithmetic operations cannot be applied to. Your beef isn't with pointers, it's with memory address manipulation.

When did I do that? I don't remember doing so... all I remember is responding to your points about C++ and C cleanliness =).

LPC and C++ are two vastly different things. And before you ask -- LPC doesn't have nearly as many features for writing extendable, generic and safe code that C++ does =). Of course I usually forgive this because one can extend LPC from within C (and thus C++).

angelbob 04-01-2003 01:26 PM

Well, sure, but (other than people like me that rederive the bit layout based on how we'd write the compiler) how is a beginner supposed to turn into somebody that expects the behavior that C++ has there?

I was only able to do it because I've played with ugly bitwise manipulation of several other C++ constructs. Knowing the behavior is required to debug the problem, and it's not behavior that I've ever seen documented (with the exception of email/posts written by me).

Actually, if you agree that adding features affects how people use the rest of the language, I'd say that brings us closer to agreement rather than furthering our disagreement. You're in favor of optional features, even optional features that are badly used in almost every case (at least, so you said), because they increase the expressivity of the language, presumably in all the cases that aren't part of the "almost every case" I just mentioned.

Well, yes, but there are degrees of "screwed up". There are, in fact, languages that make pretty good guarantees of modularity.

Well, no. They should avoid those features whever possible. However, they get an extra safety net in languages where people can't use features they're not basically familiar with, such as one where they know all the features because there aren't all that many. I'd say C is near the largest set of features a language can have and still be that comprehensible. It may even be slightly larger than that, given how few people I've met that really know it. C++ is unquestionably over the limit.

Wait, wait. It's obvious that more people will fully know C than C++ (I've still never met one that fully knows C++). And therefore it's obvious, so it's irrelevant?
But yes, I feel that a language that is fully known is easier to debug than a language that you only partially know. You're welcome to say Google is a full reference to everything, and I'll reply that some things are very hard to find. Again, take my typecasting and multiple inheritance problem above. What would you do a search for to figure out what's wrong with that? Would you know to search for that without already knowing what the problem is?

Sure. Syntax isn't the problem. How the language handles things can be pretty unintuitive, though. You're welcome to call it semantics, which is more accurate. I consider the basic point correct, though.

But it's unusual to get that luxury during debugging, unless you write everything you work on.

Actually, I was disagreeing with the idea that the bald statement, the one starting with "so we should all use VB", was using the logical principle in question. You never stated how you got there, it certainly wasn't obvious, and you never gave most of your other assumptions.

Presumably the logic you used goes, "bad features are bad, C++ contains bad features, C contains bad features, VB contains fewer bad features, so VB must be where his argument goes". But then, that sounds pretty illogical, at the very least the part that says "VB contains fewer bad features" given that we haven't talked about VB.

So you apparently got there some other way. If you'd stated how, or even given a serious hint, I could have taken that as a logical utterance. You didn't, so you were simply using a challenging tone and using a statement you were pretty sure I'd disagree with, but attributing it to me. Again, that's fine, but calling it "logic" is still a stretch.

I have, incidentally, taken classes in logic. That's one reason I'm calling you on this. If I hadn't, I wouldn't bother calling you on it. Nor would I bother taking classes in logic if I hadn't already since your examples make 'em look pretty useless :-)

Yes, that's pretty much what references are in the languages I mentioned. The fact that you can't typecast them helps as well. Between those restrictions and array bounds-checking, those references are guaranteed not to allow you to write to memory without knowing what type it is, unless you have a "cheat" function to let you supply a numerical pointer somehow.

So yes, they look a lot like pointers, and yet they're much safer to use.

Huh? No, I didn't mean LPC. LPC isn't 100% compatible with C. Not even close. C is 100% compatible with C.

And I actually make a point of using a dialect of LPC that can't do C callout. The fact that it doesn't means that it can make several other guarantees in the language, which lets it do cute tricks like atomic functions and the rlimits() construct safely. Unfortunately, neither of those things is compatible with C, nor is there any easy way to do the equivalent.

Yui Unifex 04-01-2003 02:40 PM

By writing tests to clarify uncertainties, by reading books, talking to people more knowledgable in this particular field than they are, and by learning the underlying system architecture (something that debugging often requires). It's pretty much like learning anything else, except for the fact that it's not covered in most books presumably because it isn't that important. The perceived importance of the numerical value of a pointer changing is the part about beginner's wisdom that I was referring to.

Correct. The DoD is quite fond of Ada for this purpose. Sometimes, restrictions that require very explicit permissions are impossible to implement due to the black-box nature of some code modules that one works with. So this absolute guaruntee of protection actually excludes some certain interoptability requirements.

It's not irrelevant at all -- I was confirming your point. But then I took it a step further and showed that even if C++ were within the bounds of comprehensibility, it's still a superset of C and therefore there would still likely be more people that fully understand C. You address this by stating that you've never met someone that fully knows C++, and I counter that I've met many =).

That wasn't actually a problem though; there was nothing wrong with it. I would first probably search for multiple inheritance, assigning pointers, etc. But one needs a bit of architectural knowledge to understand why it does this. This isn't necessarily a bad thing, there are architectural issues behind the 'why' of every language that can't be easily explained to a new programmer. However a few simple test programs are enough to show that this behavior wasn't likely to cause problems, and could thus be ignored. I don't usually google issues that can be resolved so easily.

Debugging code not written to you is akin to reading books not written by you. If your team can't agree on a vocabulary, I'm sorry but there's nothing I can do.

That is indeed how the logic goes, especially after I and Lindahl pointed out features that are commonly misused (pointers, strings as arrays) in nearly the same breath. While it's true that we haven't talked about VB, I would like to see why you feel that C is more justified than VB due to this confusion. Are bad features alright because you've met people that fully understand a language that makes use of them? Do you decide with a contest of bad features, with the language that has the lesser amount winning out? Is it because the reasonably good programmers (a subjective term, of course ;)) can produce reasonable code in both VB and C, so there is no preference either way? You've used several arguments between here and the beginning, and many that I have addressed as being mostly subjective and thus unarguable. I want to find the common ground that we can both address. You fight my attempts, claiming that they aren't logical when you simply do not understand what I'm trying to do. Remember back to your classes, then: Any argument in which the premises force you to a conclusion is logical, even if you disagree with those premises.

What I like most about 'object references' as opposed to 'memory pointers' is that they decouple memory operations from object operations. The primary abstraction behind a reference is the object, whereas the primary abstraction behind a pointer is a chunk of memory that usually has a type that goes along with it. I believe that languages should still offer the ability to access lower-level memory, but I also agree that they should use a different construct for this than the pointer.

angelbob 04-01-2003 03:57 PM

True, I didn't give the full context.

The way this came up was that I had a function taking a pointer, and I was passing in the pointer in question. I was using void pointers for intermediate storage, mainly because this was autogenerated code and looking up the type name for the pointer being passed was a massive pain and involved parsing an entire extra file.

But typecasting to (void*) and then to what was needed turned out to give garbage results, and cause crashes. I had no clue why. Eventually, on one of those "Oh God, that would be so evil" hunches you get in debugging, I did a straight-up assertion -- assert((B*)var == (B*)(void*)var) -- and discovered that C++ was changing the value on me, but only sometimes.

There was no obvious way to find the problem, though I did manage to figure the rest out once I figured out that the typecast was changing the pointer's value. But as you say, there's nothing obvious to google for there. Inheritance? Typecasting?

Actually, I was disagreeing with the idea that the bald statement, the one starting with "so we should all use VB", was using the logical principle in question. You never stated how you got there, it certainly wasn't obvious, and you never gave most of your other assumptions.

Well, yes. You never state most of it. And if "state your premises if you want your argument to be taken seriously" is too onerous, that's tough. I could take your position, that every feature added (that doesn't conflict with other features) is good because it adds to the expressiveness of the language and put some pretty ridiculous points in your mouth as well, but (as when you do it to me) it would just be mockery, even though it obeys your stated reasoning.

I remember back to my classes: using unstated premises and unstated rules to get conclusions based on what you think I think you think is outside the domain of logic, so I can pretty much ignore it.

Now, back to the point you want to debate, the C vs VB thing and what the actual difference is.

While I think the understanding thing is important -- I've never worked with somebody who even claimed to fully understand C++, let alone somebody who actually does -- it's not the main point. Let me introduce a pretty exact concept and then a very small number of very inexact data points.

One could imagine rating every construct one sees in code for cleanliness, effectiveness and brevity. One could then look at various language features and based on the constructs that they had contributed to, decide whether they contributed to good or bad code, on average.

One could then look at multiple possible language subsets (or designs or whatever) and decide on that basis whether the features included were good, and whether in concert they tended to produce good or bad code. By beginning with a language that is very clean but very simple (something like SCHEME, for instance, but even simpler), you could guarantee that the language had a baseline minimum of expressiveness and then add features from there, bearing in mind one's tolerance for ugliness in code. Adding "goto" would bring the total up a lot, so you'd much rather add loop constructs, perhaps with labelled loops (Perl's usual answer to goto). You could add exceptions, but only if, as in Java, it's easy to be sure of the full range of exceptions a given function can throw. You could add something to do template-like work, but instead you might choose procedural macros to make the results less syntactic and more semantic in the way they work. Or you might just skip them entirely if you have runtime compilation already, since then you could construct whatever you like in the language itself, very much like how LISP handles its procedural macros.

If one had a very low tolerance for syntactic ugliness (or were trying to irritate Yui specifically) one could wind up with a very simple language with very few features, a lot like SCHEME. If one had a very high tolerance for syntactic ugliness, one could bolt on features 'til the cows come home, and wind up with something a lot like Perl. With a sufficiently high tolerance for semantic ugliness, you could come up with something like TCL.

And each of these languages has an associated power in various domains. C has massive ability at systems programming, Perl can manipulate strings astoundingly well, TCL can be compiled very quickly, and Scheme does none of these things (being simple) but it embeds like the dickens (being simple) and compiles lightning-fast (being simple).

So that's a fine abstraction, but it tells us very little about C versus VB. What's the difference?

C has a higher tolerance than VB for syntactic ugliness, though not nearly as much so as C++ or Perl. Yes, this is subjective, but it's accepted in the vast majority of programming forums that more kinds of punctuation in more random places in the code is generally a bad thing -- Perl's regular expression syntax, much as I love it, is just not a pretty thing. It's also hard to read because density of expression leads to poor reading comprehension, especially if you don't know if there are bugs. Similarly, code that has bits that don't label their functions well is hard to comprehend, and usually ugly. Dylan's structure-definition stuff is a joy to behold, especially if you don't know the language very well. Since it's been awhile for me, don't take this syntax as gospel, but it's reasonbly close:

class <MyClass>
inherit <MyOtherClass>;
field data-one, type: <integer>, setter: data-setter;
end class <MyClass>;

In C++, you have:

class MyClass : public MyOtherClass {
int data_one;
public:
void data_setter(int new_val) { data_one = new_val; }
}

Note how in this class it's less obvious what the individual bits do? You can get away with less keystrokes, at the cost of reading comprehension. And yes, yes, you're welcome to say that somebody that knows the language well will understand what the class declaration does, and you'd be right. But there's a difference between the possible and the pleasant, and if you make it more pleasant, it's usually more maintainable.

So what about C versus VB? Neither looks like Dylan. VB doesn't even usually use classes, at least the way I've seen it done.

C is substantially more powerful than VB for most uses (note: "most uses" here means "stuff I do" -- VB is actually more common than C in the real world, and probably rightly so). Far more powerful. Hands down. It's also uglier, at least the parts I've used. And faster, though that's effectively part of "more powerful".

Thus, VB is to C as C is to C++ -- one is more powerful, and uglier. So rather than saying "why don't we all use VB?", you might have extended the point to "why don't we all use 'Hello World' in Scheme?". It does nothing and is very pretty, so it's the logical conclusion of going for a less-powerful, prettier choice of language.

Of course, if I was saying, "y'know, the Honda Insight is a lot less economical than an Accord considering what the two do", you could equally validly say "well then just walk, cheapskate." This would be why I don't consider it logical. I'm considering a tradeoff, so you assume that if I prefer a trade toward cheapness and lower performance that obviously something that costs nothing and does nothing is perfect.

No. It's a tradeoff. In the same way that I assume you wouldn't want a language with every possible feature, I prefer you not assume that I want a language with no features. I'm considering the cost and the value of using one thing versus another, which is different from taking a single principle and applying it to the absolute utmost.

Maybe I'm wrong. Maybe if there were something with more features than C++, you'd just automatically use that, no matter how ugly and no matter how hard to debug. I don't think so, though.

Kastagaar 04-02-2003 03:53 AM

In all the world, I think there are possibly 7 people who fully know C++, and they're all on the C++ standards committee. There are, however, many programmers who know enough C++ to a) be able to use it effectively and b) know where to look when they come across some esoteric aspect of the language. I think it all follows the 90% rule.

I came across an aspect involving the width of an enum when having an int constructed from it just last week. Oh wait, that exists in C, too. And then there's the returning static thing from that poster on TMC. Except that's also the rule in C. Let's ban C, it's too easy to make silly mistakes.

Kas.

Yui Unifex 04-02-2003 05:44 PM

It's important to note that if we all stated *all* of our premises before every conclusion, we wouldn't be able to argue effectively with our hands so crippled from overtyping =). No, instead, we use a set base of assumptions -- or a ridiculous assumption like my own statement -- and see which parts of it the other party takes issue with. Then we clarify and re-clarify until we get to immutable core principles (and a set of extrapolations based on them) or uncover fallacies. It would be ridiculous for us to specify *every* assumption simply because different sets of people take issue with different assumptions for different reasons.

By all means! Be my guest -- and I'll either clarify why such ridiculous points don't fit the premises, or alter my premises, or point out fallacies, etc. I don't see it as mockery at all, unless it is done continually with no eye towards giving it some intelligent thought.

I agree, and I think this is a good system for rating programming languages in general. Note the underlined portion of this quote: Some languages by necessity must consider more than this (unfortunately) idealistic view. C++, for example, wished to draw from the large body of C users out there. These users absolutely had to have a compiled system because of the large amount of systems programming and performance considerations attributed to the previous language, which makes it very difficult for dynamics. Java is facing the same problems that C++ faced many years ago: Do you keep the cruft and make new versions of the language backwards compatible, or do you do away with it and risk alienating former users of the language? The C++ Standards committee has been bending over backwards to maintain backwards compatibility. What I'm trying to say is that every language has a set of unique considerations over and above the goal of producing good or bad code; that producing good or bad code, while an important consideration, is something that must be balanced against other important considerations.

These other considerations particularly shine in the mud community. Because of the backwards compatibility with C, a coder can port their source over to take advantage of certain features (like strings, linked list objects that are decoupled from the object they store, and constructors/destructors to initialize memory and subsequently free it) while still maintaining the large body of code that they have already written.

I wouldn't say that a language with few features is irritating =). I've been enjoying greatly my time with a ridiculously simple (but still quite powerful) language called =).

Great! I'm glad we agree =). My only goal is recognizance that one language is not best suited for all purposes. Even languages like Brain**** are useful for modeling how one needs to do things on a pure Turing machine.

Right, that's what I usually go by. I don't expect someone to literally fully know a language -- that would be pretty silly =). But it's easy to tell people that have achieved a certain mastery over a language. They can generally sense if something's not right in the code, and lookup the answer to solve most problems they have.

angelbob 04-03-2003 02:43 PM

My experience has been that a problem involving a feature I have trouble understanding, or with serious subtleties, will take many times as long to debug. You can produce those in C as well (or any language), granted, though I've found that every situation in C where I have that problem involves a lot of indirection (pointers). Then again, I'm very comfortable with a lot of the parts of C that tend to give many people problems like unions, signedness, widths and bit-layout, and bitwise operators, so it's entirely possible that there are other features of C where other people would have problems like you describe.

If 10% of your problems take 10 times as long to debug as the other 90% (which is about right for me and C++ in my experience), you wind up spending half of your time on that 10%. That's fine if that's where the meat of your problem is, and in that case it's fully justified. But I've found that in C++ I wind up spending way too much time on trivial problems caused by nasty syntax or questionably-designed language features.

In C, I still spend half my time on 10% of my problems. But they're the 10% that occur in places with genuinely weird logic where the hard part is figuring out the algorithm. That'd be the right 10% to my mind.

There are certainly language features in C that could be clarified, changed or banned. Like I say, I'd love to have references in C, especially if pointers could be easily identified by the very distinctive syntax they required. Star and ampersand are okay except that star is used for multiplication as well, and pointers are currently used too readily.

And as far as figuring out what size an enum is, granted, that should be standardized. But it has the same problem C has always had -- too many platforms. C is old enough that it can't even be sure that its integer types are multiples of eight bits. Scary but true.

I haven't seen the returning static thing. I'll take your word for it.

And yes, it *is* too easy to make silly mistakes in C. I'll run the risk of irritating Yui by blaming some of that on the language designers :-)

angelbob 04-03-2003 02:56 PM

Yup. Poor schmucks, they fell for it :-) You're welcome to justify this way ("C++ may be ugly, but it had to be in order to get popular"), but I'm not sure it's helping your case.

Yup. C++ takes a lot of flak for every instance where the same code (in C, like) compiles to something slower. It doesn't seem to take the same flak for all the places where the C code gets bigger, but that's neither here nor there. Unless you work for someplace like Palm, and then you just don't use C++ :-)

And, oddly enough, doing quite well by it. But then Java has a marketing budget like no language before it. I *do* think it's a step in the right direction from C++. Or the wrong direction from most dynamic languages, so it depends how you look at it :-)

The performance thing that you mention is a good point. Languages certainly must be designed with efficiency in mind. Whether that's programmer-time efficiency, cpu-time efficiency, memory-efficiency or something else determines a lot about the language.

I consider popularity concerns ("if it doesn't look like C, nobody will use it") and time-to-market concerns ("but we don't have time to make a real VM language for Java! Use the language directly") pretty irrelevant to whether I should use the language, and what I should use it for. Instead I'll judge it based on its actual merits ("gee, that's a lot uglier than C" and "gee, that's really slow", respectively, in the two examples above).

Yup. Speaking of ugly code. It gives you all the syntactic ugliness of C++ and the reduced range of debugging tools, but without the object-oriented design.
You can say "but you can refactor". The codebase has to be *very* clean and *very* OO already for that to work well, though, especially at the talent level of most current MUD coders.

Yui Unifex 04-03-2003 03:01 PM

You know, irritating me is really not as easy as you think it is ;). Even though I may argue for one side or another, I don't particularly associate any emotional state with their successes or failures. You've made this same mistake twice now, and I don't expect you to make it again! =)


All times are GMT -4. The time now is 01:03 PM.

Powered by vBulletin® Version 3.6.7
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Copyright Top Mud Sites.com 2022