Bob.Stout@p6.f506.n106.z1.fidonet.org (Bob Stout) (02/01/90)
In an article of <31 Jan 90 07:52:10 GMT>, (Steve Watt) writes: > The exact potential problem with overloading is that each operator does >not NECESSARILY give some clue as to what it does. For example: I'd love >to do something cruel and inhuman to the person who came up with > "This is a test" >> cout > > Because to me, >> means shift right! Clearly, someone else (I think his >initials are actually B.S.*! :) thinks of >> as 'put something to there'. > But why not use -> for output and <- for input? a * b (where a and b are >some appropriate class) could mean add a and b, a repetitions of b, or some >other thoroughly bizarre operation (such as removing string b from string >a). When this topic came up in the FidoNet C++ conference, *this* particular B.S. noted that it will take an extraordinary amount of discipline on the part of programmers using operator overloading to keep C++ from becoming "the Forth of the '90's"
ruede@boulder.Colorado.EDU (Ulrich Ruede) (02/02/90)
In article <4156@helios.TAMU.EDU> john@stat.tamu.edu (John S. Price) writes: > >#define FORNEXT(x,y,x) for (x=y;x<z;++x) > >... >FORNEXT(x,0,10); > >That is not standard C, and I feel that using this type of macro is >bad coding style. > Well, knowing that the following program has to do with a graph (with attributed nodes and edges) would you prefer to see an initialization like FOR_ALL_NODES_OF(a_mesh, this_node) FOR_ALL_EDGES_OF(this_node, this_edge) this_edge->component= 0; END_ALL_EDGES END_ALL_NODES or rather { Node_Ptr this_node; for(this_node= (a_mesh)->grd; (this_node) != NULL; (this_node)= (this_node)->next){ { register Edge_Ptr this_edge= (this_node)->c, _end= (this_edge)+((this_node)->num_edges); for(; (this_edge)<_end; (this_edge)++){ this_edge->component= 0; } } } } This has been produced by cb on the expanded result. The macros enable me to define the data structures and the access to these structures together, as one module. If I don't use macros, the information how to access all nodes of the graph is dispersed throughout the program. Changing the basic structure then means to rewrite everything. If I have the macros, I need to change just the macro definition. I am using m4, so everyone who prefers the expanded result, can easily get it with all symbolic constants still in symbolic form. I also think that changing the syntax of a language is not a bad thing by itself. If you write a function, you have also changed the syntax of the language by introducing a new terminal symbol at the expression level. In some sense all programming consists in changing the syntax of a given base language, until you have a *specialized language* in which you solve your problem with a single statement like work(); This view of programming may be more obvious users of languages like Prolog or Forth. I agree, that only because you dislike C syntax you shouldn't do things like #define BEGIN { (if you can't see the braces, get a better terminal (:-) or #define OR || just as you wouldn't introduce new names for printf and other standard library functions. Writing your own subroutines, however, makes perfect sense, just as I believe it makes sense to use macros as mine above. It would still be better if these capabiltities were built into some language (without sacrificing performance). Ulrich Ruede ruede@boulder.colorado.edu (until Friday) ruede@infovax.informatik.tu-muenchen.dbp.de (next week)
jwl@ernie.Berkeley.EDU (James Wilbur Lewis) (02/04/90)
Ulrich Ruede writes: -Well, knowing that the following program has to do with a graph (with -attributed nodes and edges) would you prefer to see an initialization -like - - FOR_ALL_NODES_OF(a_mesh, this_node) - FOR_ALL_EDGES_OF(this_node, this_edge) - this_edge->component= 0; - END_ALL_EDGES - END_ALL_NODES - -or rather - - { - Node_Ptr this_node; - for(this_node= (a_mesh)->grd; (this_node) != NULL; (this_node)= (this_node)->next){ - { register Edge_Ptr this_edge= (this_node)->c, - _end= (this_edge)+((this_node)->num_edges); - for(; (this_edge)<_end; (this_edge)++){ - this_edge->component= 0; - - } - } - } - } - -This has been produced by cb on the expanded result. You've stacked the deck in favor of your macros by showing a fragment of gross, badly-formatted machine-generated code. I'd much prefer to see something like this: zero_components(a_mesh) A_MESH_TYPE a_mesh; { Node_Ptr this_node; register Edge_Ptr this_edge, end; for( this_node = a_mesh->grd; this_node != NULL; this_node = this_node->next) { end = this_edge + this_node->num_edges; for(this_edge = this_node->c; this_edge < end; this_edge++) { this_edge->component = 0; } } } I notice that to "macroize" your operation, you had to introduce an extra parameter into each macro (this_node and this_edge, respectively) to get the temp variables defined correctly. And you rely on using an underscore to hide another temp variable from the macro user. There is also the problem of "this_node" being evaluated multiply within the inner macro -- I pity the fool who writes FOR_ALL_EDGES_OF(this_node++,this_edge) ! -The macros enable me to define the data structures and the access to -these structures together, as one module. If I don't use macros, the -information how to access all nodes of the graph is dispersed throughout -the program. There is almost always a better way to do this without resorting to the preprocessor. The operation above, "do something" to each edge of a graph, probably *is* a common operation for you. It shouldn't be too hard to write that as a function instead of a set of macros -- perhaps you could pass a function pointer to your routine which would specify the operation to perform on each edge or node. Or if the function call overhead in the inner loop bothers you, you could pass some sort of function code to the routine and have a switch statement inside the loop to select from a (hopefully small) set of operations. Once you get the operation in the form of a function call, feel free to define any macros you like to invoke it. I won't care because syntactically, it still looks like a function call, and my tools that know C's syntax won't get confused by it. And the specialized control structure is still localized in one place, so you can modify it easily without rewriting the rest of your code. -I am using m4, so everyone who prefers the expanded result, can easily -get it with all symbolic constants still in symbolic form. Everyone who has access to m4, that is....tough darts if you're porting it to VMESS or Mess-DOS! :-) There are two related attributes of "well-writtten" programs that I'm trying to get across in this thread. Programs should be written in such a way that future maintainers can easily use whatever tools they might have at their disposal. (Specifically, since many interesting tools need to parse your code, you should avoid macros that would choke a C parser.) Your coding style shouldn't force future maintainers to use any particular tool to make sense of it. Don't assume that every programmer who will encounter your code has access to m4, or even the preprocessor! All the world isn't a UNIX box! -I also think that changing the syntax of a language is not a bad thing by -itself. If you write a function, you have also changed the syntax -of the language by introducing a new terminal symbol at the expression -level. Not in any C grammar I've ever seen. Now if you want to talk about typedefs, that's another story! -It would still be better if these capabiltities [abstracting control -structures, etc. -jwl] were built into some language -(without sacrificing performance). I think inline functions would be good for that. Too bad they're not standard C! -- Jim Lewis U.C. Berkeley
anw@maths.nott.ac.uk (Dr A. N. Walker) (02/07/90)
In article <4156@helios.TAMU.EDU> john@stat.tamu.edu (John S. Price) writes: > [...] It was pointed out to me the other day that >Bourne used alot of macros to make C look like Algol (I can post >some of the code if you like.) I would HATE to have to >maintain that code. [I don't want to pick on John, he's only one of several posters who have commented adversely on Bournegol.] Steve Bourne can defend himself; however, I think some of you are missing the point. In the late 70s, Algol (specifically, Algol 68) was the language of choice for many of us old lags, certainly for me, and I strongly suspect for SDB. C was definitely second best. What to do, faced with a programming task? Why, you write it in Algol, of course. Later you try to port that program to a computer that has no [adequate] Algol compiler, but has C. So, you copy the source across, write a few macros, try to compile and lint the result, and iterate into a working Bournegol program. It's not perverted C, it's perverted Algol. I've done the same with a lot of "dusty decks". Those who are complaining loudest about Bournegol might like to think about what they will do if they ever find themselves with lots of C source on a computer with no C compiler, but with, say, Fortran available. Once you are used to Bournegol, it becomes a perfectly viable language in which it is possible to write useful programs, like "sh" [:-)]. Over a decade later, most of *my* programs are now written in C from the start. (Actually, that's a half truth: most by line count. Most by number are in [Bourne] shell.) Even so, when faced with a tricky problem involving linked lists, or digraphs, or similar, I still write the algorithm first in Algol, where it's *much* easier to write, to prove, to maintain, to understand, and translate into C. (At least Algol to C is fairly easy; Algol to Pascal is an absolute pig for these activities.) >If someone says that they have a program in C that they want >me to look at, I EXPECT it to be C, not some weird, perverted >Algol-looking beast. But C *is* a weird, perverted Algol-like beast! [:-)] -- Andy Walker, Maths Dept., Nott'm Univ., UK. anw@maths.nott.ac.uk
peter@ficc.uu.net (peter da silva) (02/08/90)
In article <1990Feb6.174139.21140@maths.nott.ac.uk>, anw@maths.nott.ac.uk (Dr A. N. Walker) writes: > Those who are complaining loudest about Bournegol might like > to think about what they will do if they ever find themselves with lots > of C source on a computer with no C compiler, but with, say, Fortran > available. Buy a copy of "Software Tools", and try to get a few programs running under Ratfor. After a certain amount of blasphemy, settle down to rewrite the whole kit and kaboodle from scratch. As you later point out, C and Algool are pretty close. Certainly a lot closer than Fortran and C: > But C *is* a weird, perverted Algol-like beast! [:-)] -- _--_|\ Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>. / \ \_.--._/ Xenix Support -- it's not just a job, it's an adventure! v "Have you hugged your wolf today?" `-_-'
brnstnd@stealth.acf.nyu.edu (02/08/90)
In article <4152@helios.TAMU.EDU> john@stat.tamu.edu (John S. Price) writes: > No, no, no. Operator overloading in C++ is used to abstract what > the '+' operator does to a user-defined class. This Ada (and, by imitation, Fortran 90 and C++) misfeature makes program maintenance a nightmare. The problem isn't just that it's a pain to locate the routine that adds a GLORP to a FOOBIEBLETCH. The problem is that you won't even notice the nonstandard usage until it's too late. Overloading saves typing time. It has no other advantages. (Is it an advantage to be able to code without thinking and make undetectable syntax errors?) ---Dan
henry@utzoo.uucp (Henry Spencer) (02/10/90)
In article <926.18:17:58@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: >Overloading saves typing time. It has no other advantages... Sorry, I can't go along with that. Saving typing time by itself is not of massive importance, but shorter programs are. Other things being equal, a shorter program is easier to understand, easier to work with, easier to modify. The gotcha is in that phrase "other things being equal". In the case of operator overloading, other things are equal only if the author has been careful to follow the Law of Least Astonishment when writing the program. Operator overloading is a power tool. One does not give power tools to children and expect safe use, but for professionals they make work quicker and easier and thus make harder jobs manageable. The problem is that there are too many incompetent amateurs -- calling themselves programmers -- who will slice off their own fingers, or their successors' fingers, if given access to power tools. Unfortunately, it's also true that some power tools are safer than others. There is room for debate about whether C++'s sharp edges are dangerously exposed. Operator overloading is desirable and useful, but placing some more constraints on it might be desirable. -- SVR4: every feature you ever | Henry Spencer at U of Toronto Zoology wanted, and plenty you didn't.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu
brnstnd@stealth.acf.nyu.edu (02/14/90)
In article <1990Feb9.181111.24546@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: > In article <926.18:17:58@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > >Overloading saves typing time. It has no other advantages... > Sorry, I can't go along with that. Saving typing time by itself is not > of massive importance, but shorter programs are. True. But do you really find that typing foo instead of library.foo (or whatever your overloading language allows) makes your programs shorter? Narrower, maybe, but that doesn't aid reading or comprehension. > Operator overloading is desirable and useful, but placing some > more constraints on it might be desirable. Yeah. I probably wouldn't mind overloading if it had to have a special syntax and if I could coax my editor into un-overloading (underloading?) all overloaded operations. If Ada abbreviated lib1.lib2.foo as .foo or lib2.foo rather than foo or lib2.foo, it might even be readable---the initial period would serve as an ``overload warning'' and wouldn't be too distracting. C++ doesn't have such simple syntax but the same idea would work. ---Dan
schaut@cat9.cs.wisc.edu (Rick Schaut) (02/15/90)
Regarding overloading of operators: In article <926.18:17:58@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: | This Ada (and, by imitation, Fortran 90 and C++) misfeature makes | program maintenance a nightmare. The problem isn't just that it's a pain | to locate the routine that adds a GLORP to a FOOBIEBLETCH. The problem | is that you won't even notice the nonstandard usage until it's too late. Any compiler that would allow you to apply the "+" operator to a "GLORP" and a "FOOBIEBLETCH" doesn't conform to the notion of overloading. Overloading does _not_ come at the expense of strong type checking. It _does_, however, allow the programmer to apply the abstract notion of "addition" to objects for which such an operation makes sense (e.g. sets). Of course overloading the "+" operator to mean set difference when the two operands are sets doesn't make much sense in the semantics of any language. Does passing an array of characters in a parameter that is supposed to be a pointer to a FILE object make much sense? | Overloading saves typing time. It has no other advantages. (Is it an | advantage to be able to code without thinking and make undetectable | syntax errors?) Overloading saves having to think about the mechanics of calling the correct procedure whilst allowing the programmer to think more about the semantics of the program. It's not a case of being able to code without thinking. Rather, it's a case of being able to code while thinking about that which is important. -- Rick (schaut@garfield.cs.wisc.edu) Peace and Prejudice Don't Mix! (unknown add copy)
brnstnd@stealth.acf.nyu.edu (02/16/90)
In article <4301@daffy.cs.wisc.edu> schaut@cat9.cs.wisc.edu (Rick Schaut) writes: > In article <926.18:17:58@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > | This Ada (and, by imitation, Fortran 90 and C++) misfeature makes > | program maintenance a nightmare. The problem isn't just that it's a pain > | to locate the routine that adds a GLORP to a FOOBIEBLETCH. The problem > | is that you won't even notice the nonstandard usage until it's too late. > > Any compiler that would allow you to apply the "+" operator to a "GLORP" > and a "FOOBIEBLETCH" doesn't conform to the notion of overloading. Say what? Why not? What if GLORPs and FOOBIEBLETCHen are natural candidates for addition? And since when does the compiler decide this for you? Read my comments in another article in this thread about how to make overloading readable. > | Overloading saves typing time. It has no other advantages. (Is it an > | advantage to be able to code without thinking and make undetectable > | syntax errors?) > Overloading saves having to think about the mechanics of calling the > correct procedure whilst allowing the programmer to think more about the > semantics of the program. The same would be true if overloading were distinctively marked, by an initial character, for example. This would save gratuitous syntax errors without being too distracting. Even so, are you sure that vector + vector means addition and not concatenation? Or are they character vectors, being used as strings? As many other programmers have pointed out, you should never force someone to learn a new language just to read a program. ---Dan
gsarff@meph.UUCP (Gary Sarff) (02/17/90)
In article <4301@daffy.cs.wisc.edu>, schaut@cat9.cs.wisc.edu (Rick Schaut) writes: >Regarding overloading of operators: > >In article <926.18:17:58@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: >| This Ada (and, by imitation, Fortran 90 and C++) misfeature makes >| program maintenance a nightmare. The problem isn't just that it's a pain >| to locate the routine that adds a GLORP to a FOOBIEBLETCH. The problem >| is that you won't even notice the nonstandard usage until it's too late. > >Any compiler that would allow you to apply the "+" operator to a "GLORP" >and a "FOOBIEBLETCH" doesn't conform to the notion of overloading. Why not, if that is what I want, and that is the way I declared the operator to work? I want + to add 1 operand of type GLORP to one of type FOOBIEBLETCH. They don't necessarily have to be the same type of objects to overload. >Overloading does _not_ come at the expense of strong type checking. It >_does_, however, allow the programmer to apply the abstract notion of >"addition" to objects for which such an operation makes sense (e.g. sets). Makes sense to whom? You? Me? A foreign programmer who doesn't speak your native english? > >Of course overloading the "+" operator to mean set difference when the two >operands are sets doesn't make much sense in the semantics of any language. Again, make sense to whom? >Does passing an array of characters in a parameter that is supposed to be >a pointer to a FILE object make much sense? > >| Overloading saves typing time. It has no other advantages. (Is it an >| advantage to be able to code without thinking and make undetectable >| syntax errors?) > >Overloading saves having to think about the mechanics of calling the >correct procedure whilst allowing the programmer to think more about the >semantics of the program. It's not a case of being able to code without >thinking. Rather, it's a case of being able to code while thinking about >that which is important. > I think the original poster's point, and the reason I have always distrusted overloading, (as in Ada when the whole point is supposed to be reliability and ease of maintainability) is that when you have overloading, you must have all source code, headers, module def's, whatever available to you (the way the compiler does) or the meaning of any statement you see that has operators in it cannot be deduced by you. This is ease of maintainability?? Even if you can determine the types of a,b, and c, and you see a = b + c; do you _REALLY_ know the semantics of this, what if I overloaded + to do something really strange, like b + c = 1 if b and c are mutually prime? Doesn't make sense to you, (or me either), but that isn't the point. The compiler won't stop me from doing this, the language definition allows it. The only restraint we have that something like this won't happen is the restraint of the originating programmer. Features like that in any language are at least a bit scary to contemplate.
schaut@cat19.cs.wisc.edu (Rick Schaut) (02/19/90)
There is a bit of a misunderatanding here which is probably due to my having jumped in on the middle of a discussion. If so, I apologize and will attempt to be a bit more lucid. In article <16334:04:32:49@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: | In article <4301@daffy.cs.wisc.edu> schaut@cat9.cs.wisc.edu (Rick Schaut) writes: | > In article <926.18:17:58@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: | > Any compiler that would allow you to apply the "+" operator to a "GLORP" | > and a "FOOBIEBLETCH" doesn't conform to the notion of overloading. | | Say what? Why not? What if GLORPs and FOOBIEBLETCHen are natural | candidates for addition? And since when does the compiler decide this | for you? If GLORPS and FOOBIEBLETCHen are type compatible (as the programmer has defined them), then addition should be fine. You seemed to be complaining that overloading allows you to apply some operator to objects having incompatible types which, frankly, isn't true. | Read my comments in another article in this thread about how to make | overloading readable. If that's all you were saying I wouldn't have posted a follow-up even though I don't necessarily agree. Why should we take extra steps to make overloading more readable (whatever 'readable' means) when we don't for other aspects of a language? Doing anything to notify the reader that overloading is being applied in a particular expression seems to defeat the whole purpose of overloading. If you know the objects to which an overloaded operator is being applied, why do you need some special flag to tell you there is overloading? If a compiler can understand overloading, a human ought to be able to understand it as well. In any event, you _did_ make the following statement: | > | Overloading saves typing time. It has no other advantages. (Is it an ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | > | advantage to be able to code without thinking and make undetectable | > | syntax errors?) | > Overloading saves having to think about the mechanics of calling the | > correct procedure whilst allowing the programmer to think more about the | > semantics of the program. | | The same would be true if overloading were distinctively marked, by an | initial character, for example. This would save gratuitous syntax errors | without being too distracting. Which you now seem to concede isn't correct. Overloading allows at least enough advantage that you want to allow it yet flag it in some manner. I was, primarily, taking issue with the sentence I underlined above. | Even so, are you sure that vector + vector means addition and not | concatenation? Or are they character vectors, being used as strings? I'll grant that ambiguities are a problem, and ambiguities are _usually_ solved through context. However, no language that is in prevalent use can't be described using a context free grammar, so if the compiler is smart enough to resolve those ambiguites without a context, a human shouldn't have any problem whatsoever. | As many other programmers have pointed out, you should never force | someone to learn a new language just to read a program. That's funny. We seem to have very few qualms about the fact that one can't read a C program without understanding C. Why should new languages be any different? C++ is _not_ C and isn't intended to be C. -- Rick (schaut@garfield.cs.wisc.edu) Peace and Prejudice Don't Mix! (unknown add copy)