ogden@seal.cis.ohio-state.edu (William F Ogden) (06/05/91)
In article <1991Jun3.145924.28406@mstr.hgc.edu> jcm@mstr.hgc.edu (James McKim) writes: ... >Let me try to summarize the discussion so far. The question before >the groups is "Should there exist a dichotomy between functions and procedures >within a class? In particular, should functions return information >about the state of an object _without_ changing that state (at least >as far as a user of the object can tell) while procedures are used >to change the state of the object _without_ returning a value. > >So far the two most extreme views are held by Craig Chambers and myself. > >Craig feels that procedures that return values are often extremely >useful and so should be designed into the class as a matter of course. >He cites Pop and Top in a stack class as a prime example. Top returns >the obvious item from the stack with no side effects. Pop removes the >top item _and_ returns it. His argument being, I believe, that the >vast majority of the time the user will want to use the item she just >popped. (Is that a fair summary Craig?) > >I feel that the separation of concerns that the proposed dichotomization >between functions and procedures is too important to give up lightly. >The designer of a class should expect to design procedures that don't >return values and functions without side effects, and only vary from >this heuristic when there is a _compelling_ reason to do so. Thus my >Pop would just remove the top element, not return it. There are a number of considerations that bear upon this issue, but comprehensibility and efficiency are probably the most important. Functions enjoy a prominent position in twentieth century mathematics, and thus in the educational background of most software professionals. It makes sense to exploit this shared knowledge when designing software. Now the principle feature of functions is that they can be composed into arbitrarily large expressions. If you don't anticipate clients forming expressions, then functions offer no particular advantage over procedures as class operations. The answer to the question of whether functions should have side-effects which are visible at the client level is clear when you observe that side-effects will make the value of experessions dependent upon the order of evaluation of subexpressions, and hence quite unapparent. On the other hand, side-effects which only affect the internal representationsof objects (such as changing the shape of a tree being used to realize a set)should be permitted for efficiency reasons. The pop/top discussion raises an important efficiency issue in class design. While we now give lip service to object-oriented design, we often fail to recognize some of the consequences of what we're advocating. If the object based software thesis is correct, then our software will be organized around increasingly large and sophisticated objects, yet when we design things like stacks, we persist in thinking of the objects being stored in stacks as being small objects like integers. Instead, we should recognize that the really serious uses of stacks will involve storing large objects ( sets, polygons, other stacks, etc. ), and that to achieve real reusability, our stack operations should be chosen with an eye to making them efficient for storing large objects. Probably the most significant feature of large objects, as opposed to small objects like integers, is that they are usually quite expensive (if not impossible) to replicate. Consequently operations like Top make poor choices as primary operations, since their implementation inevitably involves making a copy of a data structure entry. The proper choice of primary operation for the stack then is the procedure (not function -- see above) Pop which does return the top value, since this does not entail replicating an entry. Top can be provided as a secondary operation, but clients should be warned that it is potentially an expensive operation. -- /Bill
diamond@jit533.swstokyo.dec.com (Norman Diamond) (06/05/91)
In article <1991Jun5.072556.19870@irisa.fr> jezequel@irisa.fr (Jean-Marc Jezequel) writes: >Let me summarize even further: It seems that we all agree on: >1) Functions with side effects are dangerous, and don't follow the >road towards better software quality >2) Procedures which return values are often usefull > >So why not trying to make a syntatical difference between the two >concepts (keyword like "pure" for pure functions)? >I guess it is too late for Eiffel V3, but may be for V4, when we (hope >to) have tools to make static analysis of programs in order to prove >correctness of pieces of code (i.e. ensuring postconditions and >invariants from preconditions and code), and so on. There are degrees of purity. Idempotency does not imply an absence of side effects. Even a function which is "practically" "pure" should be able to signal an error handler on occasion, which is likely to cause side effects in both I/O and in the I/O support routines' knowledge of the external state. I think the keywords will have to be on the order of "idempotent" and other precise descriptions. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it. Permission is granted to feel this signature, but not to look at it.
jgk@osc.COM (Joe Keane) (06/08/91)
I think this is a symptom of a more general problem. People try to make their
classes `whizzy' rather than clean and easy to understand. They add features
because they `might be useful', rather than that there's a good reason that
the features should be part of the class. KISS.
Suppose i'm writing a widget class. Widgets have a property called `part'. I
want to write methods to access and modify this property. The way i would do
this in C++ is the following:
class Widget
{
...
Part get_part();
void set_part(const Part&);
}
This is so simple and easy to understand, you'd think everyone would do it this
way. But no, people will manage to screw it up in new and interesting ways.
One way is by adding unnecessary functionality. For example, they say it
`might be useful' for the set method to return the old value. I think this is
stupid. If i wanted the old value, i would have called get_part first.
Some people would name either or both of these methods just `part', perhaps to
save keystrokes. I think this indicates a confusion between a method and the
value it returns. Here is the way i see it: `widget.part' is an attribute,
`widget.get_part()' is a method call which returns the part, `widget.part()'
is a mistake since you're trying to call an object, and `widget.get_part' is a
method which would return the part if you called it.
Sometimes it may be a good idea to provide a method which combines the
functionality of two simpler methods. But there has to be a good reason, more
than just the fact that the original two methods may be called sequentially.
For example, there may be some good reason you can make the combined method
significantly more efficient than calling the original methods separately.
And i don't mean you'd save a single function call overhead, it has to be more
than that. If you followed that reasoning, you'd have to provide a method for
almost every pair of methods you had originally. For example, in a list class
you'd need to put a method called
`swap_the_last_two_elements_delete_the_first_element_and_return_it'.
--
Joe Keane, amateur mathematician
jgk@osc.com (...!uunet!stratus!osc!jgk)
jls@netcom.COM (Jim Showalter) (06/09/91)
Good points! I have a few comments: >`widget.get_part()' is a method call which returns the part, That's fine if this is a procedural method. However, if you want to get the part from the widget and assign it into something, you wind up with: the_part = widget.get_part(); which doesn't seem to me to be as clear (English-like) as: the_part = widget.part(); An alternative I can live with is to write get_part to return its value as an argument: widget.get_part(the_part); but this still doesn't seem as clear. >Sometimes it may be a good idea to provide a method which combines the >functionality of two simpler methods. But there has to be a good reason, more >than just the fact that the original two methods may be called sequentially. >For example, there may be some good reason you can make the combined method >significantly more efficient than calling the original methods separately. Agreed. Generally the criterion I tell my students to use is whether or not the method they're providing is something that depends on visibility to private data for efficiency. If so, then a client can never hope to implement the operation as efficently from outside the class as from inside it. The example I usually give is something to count the number of elements in a list. From outside the class the only way to do this (if the class has been properly abstracted and the data properly encapsulated) is to set up a local counter and then perform N swap head/tail operations until the list has been counted. That this is very inefficient, plus which it modifies the state of the list (so you need to keep a duplicate list around to get back to the starting point), etc. Clearly a Count method that can simply walk a pointer to list elements down the list (because it has visibility to the private data) is much superior and should be supplied by the class (for even higher efficiency a count field can be part of the data for the list itself and this can be incremented/decremented as elements are added to/deleted from the list). -- **************** JIM SHOWALTER, jls@netcom.com, (408) 243-0630 **************** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
paj@mrcu (Paul Johnson) (06/10/91)
>There are degrees of purity. Idempotency does not imply an absence of >side effects. Even a function which is "practically" "pure" should be >able to signal an error handler on occasion, which is likely to cause >side effects in both I/O and in the I/O support routines' knowledge of >the external state. Why not add a keyword `unchanged' to the `ensure' clause? This would be equivalent to something along the lines of `current.equal( old current )' and would assert that the function has not changed anything. Function purity then becomes a run-time checkable assertion. Of course it does not handle internal changes (such as the tree rearangement which someone suggested) but that *is* a little more complicated. For functions which simply return some aspect of the state it would do quite well. Paul. -- Paul Johnson | Isn't modern education wonderful: one size fits all! -------------^------------------v-------------------------v------------------- GEC-Marconi Research is not | Telex: 995016 GECRES G | Tel: +44 245 73331 responsible for my opinions. | Inet: paj@gec-mrc.co.uk | Fax: +44 245 75244
rick@tetrauk.UUCP (Rick Jones) (06/12/91)
In article <956@puck.mrcu> paj@uk.co.gec-mrc (Paul Johnson) writes: > >Why not add a keyword `unchanged' to the `ensure' clause? This would >be equivalent to something along the lines of `current.equal( old >current )' and would assert that the function has not changed >anything. Wait for Eiffel version 3! (not long now, I hope). It will support a construct "strip" which means "the attributes of this object, except for <the parameters given to strip>". If there are no parameters, it is all the attributes. Then the postcondition "strip = old strip" means "no change". Since strip allows you to explicitly omit specified attributes, you can write a postcondition which means "no change to any attributes except those specified". So by omitting attributes which only affect internal state, the postcondition can ensure that the important things are unchanged, even though the internal state may have been modified. -- Rick Jones, Tetra Ltd. Maidenhead, Berks, UK rick@tetrauk.uucp Chairman, NICE (Non-profit International Consortium for Eiffel) Any fool can provide a solution - the problem is to understand the problem
jimad@microsoft.UUCP (Jim ADCOCK) (06/14/91)
In article <4888@osc.COM> jgk@osc.COM (Joe Keane) writes: >Some people would name either or both of these methods just `part', perhaps to >save keystrokes. I think this indicates a confusion between a method and the >value it returns. Here is the way i see it: `widget.part' is an attribute, >`widget.get_part()' is a method call which returns the part, `widget.part()' >is a mistake since you're trying to call an object, and `widget.get_part' is a >method which would return the part if you called it. I disagree. Once upon a time there was a language called "Basic" that used a '=' for both assignment and equality testing. Fearful that some beginners might find this confusing, the language authors introduced the "let" noise word: LET part = somepart; However users of the language recognized that this was silly and redundant and chose not to use the noise word. Nowadays some "object oriented" library writers introduce the "set" and "get" noise words for fear, as in Basic, that the users of the libraries might otherwise get confused. However users of these OOP libraries recognize that this is silly and redundant and choose not to use the noise words. ---- Thus I claim: "Get" and "Set" are object oriented for "Let" ---- I recommend: Please allow C++ compiler's strict type checking and overloading by parameter type to do their jobs. It is unnecessary and redundant for *first* the programmer and *then* the compiler to encode type information in function names: object.ObjectDoSomething(); // please don't encode class names // in method names -- the compiler // already does this for you! object.DoSomethingWithInt(100); // please don't encode parameter types // in method names -- the compiler // already does this for you! somepart = object.GetPart(); // please don't encode return types object.SetPart(somepart2); // or lack thereof in method names -- // the compiler already performs // selection based on parameter type! Without redundant noise words this becomes simply: somepart = object.part(); object.part(somepart2); Note: for the above functions the compiler generates "type safe" mangled names that if re-written in plaintext might be something like the following: Object__ObjectDoSomething__void Object__DoSomethingWithInt__int Object__GetPart__void Object__SetPart__Part verses: Object__part__void Object__part__Part [ Further, the above proposed form without the Let, Set, Get noisewords allows rapid prototyping via overloaded operator(), if so desired ] [my opinion only]
dmg@ssc-vax (David M Geary) (06/15/91)
In article <72893@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: aIn article <4888@osc.COM> jgk@osc.COM (Joe Keane) writes: >>Some people would name either or both of these methods just `part', perhaps to >>save keystrokes. I think this indicates a confusion between a method and the >>value it returns. Here is the way i see it: `widget.part' is an attribute, >>`widget.get_part()' is a method call which returns the part, `widget.part()' >>is a mistake since you're trying to call an object, and `widget.get_part' is a >>method which would return the part if you called it. > >I disagree. > >Once upon a time there was a language called "Basic" that used a '=' >for both assignment and equality testing. Fearful that some beginners >might find this confusing, the language authors introduced the "let" >noise word: > > LET part = somepart; > >However users of the language recognized that this was silly and >redundant and chose not to use the noise word. > >Thus I claim: > >"Get" and "Set" are object oriented for "Let" > >---- > >Without redundant noise words this becomes simply: > > somepart = object.part(); > object.part(somepart2); > > In: LET part = somepart; The LET is obviously redundant due to the fact the the = implies it. Therefore, in: somepart = object.getpart(); The get is also redundant, because both the type of somepart, and the = imply that assignment is taking place. However, in: object.setpart(somepart2) That the set is redundant is only gleaned from the type of somepart2, and that does not (fully) imply that the object's part is being set. In the expression: object.part(somepart2), perhaps part is really a list of parts, and this operation adds somepart2 to the list of parts kept by the object. (Not the slickest design, admittedly, but not so totally irrational that nothing akin to it will/would ever be done). One might therefore advocate that an operator be defined such that we may write the expression: object() << somepart2; However, this is equally as vague to me. I agree with Jim on all other counts (which I ommitted in this article), for removing redundancy from method names, however, this set business does not seem so clear-cut. -- |~~~~~~~~~~ David Geary, Boeing Aerospace, Seattle, WA. ~~~~~~~~~~| |-----------------------------------------------------------------------------| |~~~~~~ Seattle: America's most attractive city... to the *jetstream* ~~~~~~| |-----------------------------------------------------------------------------|
marc@dumbcat.sf.ca.us (Marco S Hyman) (06/16/91)
In article <72893@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: > object.DoSomethingWithInt(100); // please don't encode parameter types > // in method names -- the compiler > // already does this for you! Hmm. Is the C (and by extension C++) corollary of this rule: int someFunc(int someInt); /* don't encode paramater types in paramater names */ Nah. Couldn't be. Jim's posting from microsoft.uucp -- just look at any MS Windows software... :-) Seriously -- I agree with Jim but wonder what his (and others) solution to this question is. Given a language that requires different names: Class someClass { public: int part(); // returns the part void part(int newValue); // sets the part private: int ???; // what do yoy call this. }; what name do you assign to ???. myPart? localPart? privatePart? // marc -- // home: marc@dumbcat.sf.ca.us pacbell!dumbcat!marc // work: marc@ascend.com uunet!aria!marc
jcm@mstr.hgc.edu (James McKim) (06/17/91)
In article <1186@tetrauk.UUCP> rick@tetrauk.UUCP (Rick Jones) writes: > >Wait for Eiffel version 3! (not long now, I hope). Second that (e)motion! And where/how can I get the latest _Eiffel: The Language_ ASAP? > It will support a construct >"strip" which means "the attributes of this object, except for <the parameters >given to strip>". If there are no parameters, it is all the attributes. Then >the postcondition "strip = old strip" means "no change". Since strip allows >you to explicitly omit specified attributes, you can write a postcondition >which means "no change to any attributes except those specified". So by >omitting attributes which only affect internal state, the postcondition can >ensure that the important things are unchanged, even though the internal state >may have been modified. > Hmmm. Is "strip" included in the public interface? Offhand, it seems it should _not_ be since, if I understand correctly, it may include parameters that are private attributes. These the client does not need/want to see and, besides, the public interface should not change if I change the name of a private attribute. Also "strip" wouldn't help with public attributes that change, since the client needs to know _how_ each such attribute changes, not just which ones may. It _does_ look like a very useful compiler directive, though.... >-- >Rick Jones, Tetra Ltd. Maidenhead, Berks, UK rick@tetrauk.uucp >Chairman, NICE (Non-profit International Consortium for Eiffel) > >Any fool can provide a solution - the problem is to understand the problem -- Jim *------------------------------------------------------------------------------* Jim McKim (203)-548-2458 _Give_ people fish and they eat for a day. Internet: jcm@mstr.hgc.edu _Teach_ people to fish and they eat for a lifetime.
jgk@osc.COM (Joe Keane) (06/19/91)
Not surprisingly, something i wrote touched off a bunch of replies. So now i'm going to write some more on method names. Actually, i agree completely with Jim Adcock's main point, that redundant information should not be included in a method name. However, i'd say that it's hardly a minor point whether a method changes the object it's run on or merely returns some value based on it. In fact, when listing methods the most important distinction i make is between accessors and modifiers, or whatever you call them in your language. My rule on method names is simple. Methods with the same name should do the same thing. Really this is just common sense, but it can't hurt to make it explicit. Exactly what `the same thing' means is left open, but i think reasonable people will generally agree on whether two operations are the same. Of course, the methods don't have to perform exactly the same operations inside, and in terms of implementation they may be radically different. But at a conceptual level they should perform the same operation on different things. Here is an example of overloading: print(char); // print a character print(int); // print an integer print(const char*); // print a string print(const Widget&); // print a widget I think most people would agree that this is a proper and desirable use of overloading. Looking at the descriptions, which are actually pretty much redundant, you can see that these methods perform the same conceptual operation, and in fact the verb is the same as the method name. Here is another example of overloading: print(char); // enable Kanji printing print(int); // delete printing database print(const char*); // set printer device name print(const Widget&); // make a printer widget I think everyone would agree that this is a terrible use of overloading, and also that this is a silly example. But when you start putting multiple operations on a single name, you're venturing into this territory. I agree that in most cases a user can figure out what is meant, but that's not the point. Why make your methods confusing when they can be clear? A good convention to follow is that method names should be predicates, in the grammatical sense. This means that the first word should be a verb which desribes the conceptual operation, and then this is possibly followed by some nouns which clarify what the operation is to be performed on. Now it turns out that in many cases the verb will be a simple one, like `get', `set', `make', `add', `remove', or `replace'. In fact, i'd say that most methods are one of the preceding operations. This doesn't mean that the verb is not needed, it just means that the conceptual operation is a simple one. If the arguments are classes, you may not need any clarifying nouns. But in many cases the arguments are `int' or `const char*', and here it may not be immediately clear just what that integer is supposed to be. Furthermore, you may want to add another operation whose argument is the same type, although it means a different thing. One poster mentioned the possibility of a single method which returns a reference. I have one piece of advice on this: don't do it. If you do this enough i guarantee that eventually you will get screwed. I'm tempted to just leave this as a comment from experience, but i guess i should elaborate. First of all, references last forever. You never know when a user is going to decide to change the thing you passed him a reference to. Second, you may decide to change the internal implementation, so that the thing which you returned a reference to no longer exists. Then what do you do? You can't create a fake one, because you don't know when to get rid of it. Third, you may decide you want to do something when the object is changed, and this form doesn't allow you to distinguish when someone is just looking or is really going to change the attribute. I'd like to point out that all of the preceding comments apply to writing classes that other people are actually going to use. On the other hand, if you're writing a class for internal use, i suppose you can pretty much do what you want, as long as you can figure it out. However, i would like to remind people that even something you wrote may look a little unfamiliar after a couple years. -- Joe Keane, professional C programmer jgk@osc.com (...!uunet!stratus!osc!jgk)
rick@tetrauk.UUCP (Rick Jones) (06/19/91)
In article <1991Jun17.141842.25702@mstr.hgc.edu> jcm@mstr.hgc.edu (James McKim) writes: |In article <1186@tetrauk.UUCP> rick@tetrauk.UUCP (Rick Jones) writes: |> |>Wait for Eiffel version 3! (not long now, I hope). | |Second that (e)motion! And where/how can I get the latest |_Eiffel: The Language_ ASAP? It's due for publication in July - I have a final draft copy (one of the priveleges of being a member of NICE :-). |> It will support a construct |>"strip" which means "the attributes of this object, except for <the parameters |>given to strip>". If there are no parameters, it is all the attributes. Then |>the postcondition "strip = old strip" means "no change". Since strip allows |>you to explicitly omit specified attributes, you can write a postcondition |>which means "no change to any attributes except those specified". So by |>omitting attributes which only affect internal state, the postcondition can |>ensure that the important things are unchanged, even though the internal state |>may have been modified. |> |Hmmm. Is "strip" included in the public interface? Offhand, it seems it |should _not_ be since, if I understand correctly, it may include parameters |that are private attributes. "strip" is not a feature that can be part of a class interface - it is a language keyword, and its use will yield the attributes of the current object, as seen by the class in which the strip construct is used. This means that even if the object is an instance of a descendant class which introduces new attributes, these attributes will not be included in the result of "strip". It is only really intended for use in postconditions; if you wanted to export the result of a strip expression (which syntactically is an ARRAY[ANY] object), you would have to write a function to do so. (to be precise, you would not actually write "strip = old strip" as I wrote before, the correct expression is "equal (strip, old strip)" - I thought I'd better put that in before someone picks me up on it!) -- Rick Jones, Tetra Ltd. Maidenhead, Berks, UK rick@tetrauk.uucp Chairman, NICE (Non-profit International Consortium for Eiffel) Any fool can provide a solution - the problem is to understand the problem
jls@netcom.COM (Jim Showalter) (06/20/91)
>If the arguments are classes, you may not need any clarifying nouns. But in >many cases the arguments are `int' or `const char*', and here it may not be >immediately clear just what that integer is supposed to be. In languages that have formal names for parameters, not just types, you can use the formal names to self-document what all the mystery-int's are. For example, in Ada (I'm using Ada here because it's the language I'm most fluent in--yes, I realize other languages have this capability), you could write things like: procedure Print (This_Many_Lines : in Integer); The formal name "This_Many_Lines" eliminates any confusion about what the Integer argument might specify. For languages that have this capability, there is a nice additional feature that makes a natural companion to formal parameter names--named parameter association. In Ada, you could call the above procedure like this: Print (This_Many_Lines => 8); Note how this makes the code inherently self-documenting, always a noble goal. Contrast this with: Print (8); Which is the only argument binding syntax available in less readable languages--from the above the reader cannot deduce whether the Print is going to print the numeral 8, or eight of something, or what. And off the the comments and/or documentation the maintainer runs where, if he/she is lucky, the necessary information MIGHT be available. I much prefer to put the requisite information into the code itself, since that's the only way I can guarantee that the documentation for the code and the code itself will stay in sync with one another. Now, I get complaints occasionally that the version using named parameter association is too verbose. I've noticed that such complaints typically come from hunt-and-peck typists with little or no background in maintenance, which pretty much says it all... -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
kers@hplb.hpl.hp.com (Chris Dollin) (06/20/91)
Jim Showalter [indented below] extolls the virtues of keyword parameters. in--yes, I realize other languages have this capability), you could write things like: procedure Print (This_Many_Lines : in Integer); The formal name "This_Many_Lines" eliminates any confusion about what the Integer argument might specify. For languages that have this capability, there is a nice additional feature that makes a natural companion to formal parameter names--named parameter association. In Ada, you could call the above procedure like this: Print (This_Many_Lines => 8); I think it's a mistake to tie in the name of the formal parameter to the interface of the procedure; the calling keyword has a right to be verbose, but the *parameter* name may be used repeatedly in the procedure, and has the right to be short. ("You have the right to remain ....") Note how this makes the code inherently self-documenting, always a noble goal. Contrast this with: Print (8); Which is the only argument binding syntax available in less readable languages--from the above the reader cannot deduce whether the Print is going to print the numeral 8, or eight of something, or what. I'd choose a different name for the procedure: this ensures that the keyword-syntax cannot be accidently left out (not being there). Of course this gets harder as the number of arguments increases. Now, I get complaints occasionally that the version using named parameter association is too verbose. I've noticed that such complaints typically come from hunt-and-peck typists with little or no background in maintenance, which pretty much says it all... It can be too verbose to *read* as well. If it makes code unnecessarily large, that is in and of itself a maintenance problem. (Doesn't a respectable maintenance environment allow you to see the call annotated with the meanings of the parameters anyway?) Keyword-calling is less useful in languages making free use of procedure-valued variables (ie higher-order functions). If you have keyword-constructors for record aggregates (eg, rectype( fieldX as exprX, fieldY as exprY )) then some uses of keyword arguments can be replaced by calls with suitably constructed aggregates. -- Regards, Chris ``GC's should take less than 0.1 second'' Dollin.
jls@netcom.COM (Jim Showalter) (06/21/91)
kers@hplb.hpl.hp.com (Chris Dollin) writes: >I think it's a mistake to tie in the name of the formal parameter to the >interface of the procedure; the calling keyword has a right to be verbose, but >the *parameter* name may be used repeatedly in the procedure, and has the right >to be short. ("You have the right to remain ....") That's why--in Ada at least--you can RENAME the parameter inside the body of the procedure. This gives you the best of both worlds--a formal name that is ideal from the client's standpoint specified in the interface, and a second formal name that is ideal from the implementor's standpoint specified in the hidden part of the unit. >I'd choose a different name for the procedure: this ensures that the >keyword-syntax cannot be accidently left out (not being there). Of course this >gets harder as the number of arguments increases. It gets unacceptably ugly as the number of arguments increases above 1, which means that in the typical case, you want named parameters: Print (This_Comment => "I love named parameter names", With_This_Spacing => 5, On_This_Device => Devices.Laserprinter, In_This_Font => Fonts.Helvetica); and so forth. I find this considerably better than a name like Print_Comment_With_Spacing_Device_and_Font_Toggles or some such. >It can be too verbose to *read* as well. If it makes code unecessarily large, >that is in and of itself a maintenance problem. Here we go again. The C equivalent of the above would typically look something like: prnt("I love named parameter names",5,lsptr,hlvtca); This DOES take up less space. Is it more readable? >If you have keyword-constructors for record aggregates (eg, > > rectype( fieldX as exprX, fieldY as exprY )) >then some uses of keyword arguments can be replaced by calls with suitably >constructed aggregates. Indeed. This is why--in Ada at least--one can OPTIONALLY use named parameter association, or not, depending on what is most readable in each particular case. If you refer back to the post that originated this arm of this thread, the poster was asking how best to approach a naming problem. In that particular case, I argue that the best approach is to use named parameter association. In other cases, I might well say it is overkill. But at least one should have the OPTION. -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
dmg@ssc-vax (David M Geary) (06/22/91)
In article <1991Jun21.013944.23970@netcom.COM> jls@netcom.COM (Jim Showalter) writes: akers@hplb.hpl.hp.com (Chris Dollin) writes: ] ]>I'd choose a different name for the procedure: this ensures that the ]>keyword-syntax cannot be accidently left out (not being there). Of course this ]>gets harder as the number of arguments increases. ] ]It gets unacceptably ugly as the number of arguments increases above 1, which ]means that in the typical case, you want named parameters: ] ] Print (This_Comment => "I love named parameter names", ] With_This_Spacing => 5, ] On_This_Device => Devices.Laserprinter, ] In_This_Font => Fonts.Helvetica); ] ]and so forth. I find this considerably better than a name like ]Print_Comment_With_Spacing_Device_and_Font_Toggles or some such. ] ]>It can be too verbose to *read* as well. If it makes code unecessarily large, ]>that is in and of itself a maintenance problem. ] ]Here we go again. The C equivalent of the above would typically look ]something like: ] ] prnt("I love named parameter names",5,lsptr,hlvtca); ] ]This DOES take up less space. Is it more readable? ] Jim, Jim, Jim. Come on now, play fair. How about: prnt(/* This Comment */ "I love *commented* parameter names", /* With This Spacing */ 5, /* On This Device */ lsptr, /* In This Font */ hlvtca); BTW, why such wonderously readable *variable* names for the Ada example: ] Print (This_Comment => "I love named parameter names", ] With_This_Spacing => 5, ] On_This_Device => Devices.Laserprinter, ^^^^^^^^^^^^^^^^^^^ ] In_This_Font => Fonts.Helvetica); ^^^^^^^^^^^^^^^ and such terse variable names for the C example: ] prnt("I love named parameter names",5,lsptr,hlvtca); ^^^^^^^^^^^^ Oh, yeah, I forgot; C is only used by a bunch of lowlife hackers who revel in unreadable code... -- |~~~~~~~~~~ David Geary, Boeing Aerospace, Seattle, WA. ~~~~~~~~~~| |-----------------------------------------------------------------------------| |~~~~~~ Seattle: America's most attractive city... to the *jetstream* ~~~~~~| |-----------------------------------------------------------------------------|
gaynor@brushfire.rutgers.edu (Silver) (06/23/91)
Excerpt from jls@netcom.com: > Print (This_Comment => "I love named parameter names", > With_This_Spacing => 5, > On_This_Device => Devices.Laserprinter, > In_This_Font => Fonts.Helvetica); > > [vs] > > prnt("I love named parameter names",5,lsptr,hlvtca); Or print("I love named parameter names", 5, laserprinter, helvetica) > > [One should have the option to have named parameters, to clean up the > understandability of complex calling sequences. It is best used with > discretion to avoid unnecessary verbosity.] Often one hears claims that whitespace is `cheap' or `free'. This is NOT true. Strunk & White's Little Book stresses brevity's importance to clarity, a lesson we should not forget. Too much whitespace can be as detrimental to readability as too little. For instance, let's add some context to the calls above. It is not far-fetched to suppose that they might be part of a string of similar statements, perhaps a report generator. NOW which one is more readable, when written with a little flair? Print (This_Comment => "I love named parameter names", With_This_Spacing => 5, On_This_Device => Devices.Laserprinter, In_This_Font => Fonts.Helvetica); Print (This_Comment => "My kingdom for a comment", With_This_Spacing => 5, On_This_Device => Devices.Laserprinter, In_This_Font => Fonts.Helvetica); Print (This_Comment => "Self-documenting code? Hah!", With_This_Spacing => 5, On_This_Device => Devices.Laserprinter, In_This_Font => Fonts.Helvetica); Print (This_Comment => "Pork bellies are looking good", With_This_Spacing => 5, On_This_Device => Devices.Laserprinter, In_This_Font => Fonts.Helvetica); vs # Comment Spacing Device Font print("I love named parameter names", 5, laserprinter, helvetica); print("My kingdom for a comment", 5, laserprinter, helvetica); print("Self-documenting code? Hah!", 5, laserprinter, helvetica); print("Pork bellies are looking good", 5, laserprinter, helvetica); The latter is 25% shorter in vertical space, 25% longer horizontally, 50% the number of characters, and a hundredfold more readable because the statements are short enough to be written in a tabular fashion. The only expense, as far as I can tell, is that the latter version is less tolerant to changes in the function. This might be alleviated by spelling out the formal parameters in the first call as a check, and leave the remaining calls tabular. There's a better example I'd love to harp on, the common practice of devoting an entire line to compound statement delimiters. What a silly waste of space. But this discussion isn't really on comp.object's beaten tracks, so I'll cut it off here. Regards, [Ag] gaynor@paul.rutgers.edu
jls@netcom.COM (Jim Showalter) (06/23/91)
> Jim, Jim, Jim. Come on now, play fair. How about: > prnt(/* This Comment */ "I love *commented* parameter names", > /* With This Spacing */ 5, > /* On This Device */ lsptr, > /* In This Font */ hlvtca); Ah, but in THIS case, you have a MULTIPLE point of maintenance: the client of a class/method/function has to redocument via comments the meaning of each argument at every point of call. Sure, you can remember to do this if you are diligent and a practitioner of good community hygiene, but who has the time for THAT?--certainly not the average C hacker. If you have function prototypes with formal parameter names and named parameter association, the names only have to be designed in one and only one place, by the DESIGNER of the class/method/function, and used for free by all clients from then on (and, if you are fortunate enough to be using real tools, they can automatically add all of the names and prompt for the values at the point of call, so you don't have to type anything except the name "print" itself). Again--nothing is impossible if enough manual effort is expended, but if you believe that the majority of C hackers bother to expend such effort, I've got some great swampland to sell you in Florida. Incidentally, it was never my intention to PROVE that formal parameter names and named parameter association is a good thing--I think the fact that Stroustrup added at least the former to C++, that ANSI C adds the former to C, that both are present in Modula-3, and that (I believe) both are present in Eiffel says something about their usefulness. > BTW, why such wonderously readable *variable* names for the Ada > example: >] Print (This_Comment => "I love named parameter names", >] With_This_Spacing => 5, >] On_This_Device => Devices.Laserprinter, > ^^^^^^^^^^^^^^^^^^^ >] In_This_Font => Fonts.Helvetica); > ^^^^^^^^^^^^^^^ > and such terse variable names for the C example: >] prnt("I love named parameter names",5,lsptr,hlvtca); Well, in the case of Ada such names tend to be the default, since the first segment of the name is the name of the package, and the second segment is the name of the entity exported from the package. This is almost directly analogous to <class>.<entity> in C++ and several other languages. If you're complaining that the words themselves are too long and readable in the Ada example and deliberately short and cryptic in the C example, I offer the following challenge: take 50 KSLOC of Ada from an arbitrary source and count up the number of times you encounter a name that ISN'T very readable, is lengthy as opposed to scrunched up like a vanity plate with all the vowels missing, etc, and post to the net the relative proportion of such things relative to those that are readable. I've been working with Ada programs of various sizes at companies ranging from just shy of totally incompetent to quite good for the past four years, and I'd say that 99.9% of the time all names are chosen with care. Call it a culturally-shared value. Really--go look at some Ada code and report back. As for the C example, be real. Yes, people CAN write readable code in C, and some even pride themselves on it. On the other hand, it has been my experience working with C hackers and UNIX weenies for over a decade that many shared cultural values that should have had a stake driven through their heart in 1964 survive to this day. You may, like a fish asked to describe water, be unware of these values, but they're real and they stink, and as something of a fish in a different pond, I can rather accurately observe and describe the water in which YOU swim. Consider, for example, the lovely naming used in UNIX itself: the semantic content of such commands as "awk", "sed", "grep", "elm", "nn" blah blah blah is effectively nil. This is WHY, if you've ever stopped to wonder about it, neophytes complain that UNIX is cryptic and hard to learn--because it IS. It is a hacker's dream operating system, written by hackers, used by hackers, and extended by hackers. Non-hackers--ordinary every day people who are just trying to get WORK done atop UNIX--don't find UNIX charming or sophisticated or productive or all those other words hackers used to describe it so glowingly...quite the contrary, they HATE the damned thing, and that explains why they embrace graphical, menuing interfaces that isolate them from the grunge of the underlying UNIX command syntax. This misplaced love of cryptic, vowel-less, hard to understand, encoded names filtered into and infiltrated the C culture at large (not surprising, given the incestuous relationship between C and UNIX), and became a culturally shared value. It survives to this day. I can go on to lambast UNIX's cryptic command line arguments, but I think I've made as much of my point as I'm ever going to make in a forum that is essentially hosted on UNIX and read by zillions of C hackers. >|~~~~~~ Seattle: America's most attractive city... to the *jetstream* ~~~~~~| Nice .sig! -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
jls@netcom.COM (Jim Showalter) (06/23/91)
>Often one hears claims that whitespace is `cheap' or `free'. This is NOT true. >Strunk & White's Little Book stresses brevity's importance to clarity, a lesson >we should not forget. Strunk & White's little book explains how to write readable ENGLISH. It does indeed stress brevity's importance to clarity, but not to the point that it says to leave out all the vowels, to concatenate two adjacent words instead of preserving separation (e.g. the underscore), to eliminate punctuation, etc. Brevity should not be so slavishly emphasized as to affect comprehensibility, another lesson we should not forget. > # Comment Spacing Device Font > print("I love named parameter names", 5, laserprinter, helvetica); > print("My kingdom for a comment", 5, laserprinter, helvetica); > print("Self-documenting code? Hah!", 5, laserprinter, helvetica); > print("Pork bellies are looking good", 5, laserprinter, helvetica); >The latter is 25% shorter in vertical space, 25% longer horizontally, 50% the >number of characters, and a hundredfold more readable because the statements >are short enough to be written in a tabular fashion. The only expense, as far >as I can tell, is that the latter version is less tolerant to changes in the ^^^^^^^^^^^^^^^^^^^^^^^^ >function. A mere triviality, I'm sure--just ask any maintenance programmer... ;-) As a general, probably fundamental rule, the more information you can place IN THE CODE, and the more often you can do this IN ONE AND ONLY ONE PLACE, the more maintainable your code. I regard most comments as an admission of failure and/or a design flaw in the implementation language. Incidentally, as long as we're talking about multi-call cases, Ada has features to support this too--and without comments, with a single point of maintenance, and with even fewer arguments than in your example above (why is it I am always arguing Ada with people who don't know it, even though I DO know C and C++?). In Ada, I'd write the above as: procedure Default_Print (This_Comment : in String; With_Spacing : in Positive := 5; On_Device : in Printers.Kind := Printers.Laserprinter; In_Font : in Fonts.Kind := Fonts.Helvetica) renames Print; Default_Print ("I love named parameter names."); Default_Print ("My kingdom for a comment."); Default_Print ("Self-documenting code? Hah!"); Default_Print ("Pork bellies are looking good."); Default_Print ("Your move."); The "renames", by the way, is strictly a syntactic artifact--it has no run-time overhead, nor does it occupy space in the end executable (it is eliminated by the compiler). >There's a better example I'd love to harp on, the common practice of devoting >an entire line to compound statement delimiters. An ENTIRE LINE!?!?! For shame--just think of all that wasted disk space. ;-) -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
gaynor@romulus.rutgers.edu (Silver) (06/24/91)
jsl@netcom.com writes: > [Look at the wretched naming conventions typically adopted in C and on the > UNIX platform in general.] I agree with jls here. My own feelings on the lengths of symbols follow. 1. If a symbol is globally accessable, spell it out. If clash avoidance is necessary, put a prefix on it indicating its type or package or something. For instance, suppose I implemented dynamic hash tables in C. (In fact, I have!, mother of all wonders.) Externally referentiable functions tend to look like table_create, table_destroy, table_hash, table_compare, table_define, table_undefine, table_defined, table_put, table_unput, table_get, table_foreach, table_map, etc. 2. If a symbol is only locally accessable, use your best judgement. If it is used in complicated expressions or extremely frequently, make the symbol (or provide an alias that is) an acronym for its intended meaning, and a roadmap. In fact, I tend to do this so frequently, that for consistency's sake, I've made the acronyms my norm. I don't think jls is going to be overly fond of these conventions... :^) I'd certainly name my formal parameters verbosely and provide acronym aliases for all, and use the one which is most appropriate, if I used a language that supported this. Unfortunately, I'm stuck using C for the time being. > As for the C example, be real. Yes, people CAN write readable code in C, and > some even pride themselves on it. A little pride goes a long way. I spend quite a bit of time making sure that my code is good enough to be used and maintained instead of replaced. Some of the people I work with do not take such care. Thousands and thousands of lines of code implement services of whose wonders I shall never partake because of the total and complete lack of external documentation. > Consider, for example, the lovely naming used in UNIX itself: the semantic > content of such commands as "awk", "sed", "grep", "elm", "nn" blah blah blah > is effectively nil. Yeah, pretty bad. `ls', `dbx', `cat', `cd', `tr', `mv', `rm', ..., they should all be spelled out. UNIX provides more than adequate aliasing utilities in its command processors. If someone wants to do a little customization, they are welcome to do so. > Non-hackers--ordinary every day people who are just trying to get WORK done > atop UNIX--don't find UNIX charming or sophisticated or productive or all > those other words hackers used to describe it so glowingly...quite the > contrary, they HATE the damned thing, and that explains why they embrace > graphical, menuing interfaces that isolate them from the grunge of the > underlying UNIX command syntax. I'm not so terribly fond of UNIX. But I do not deny the fact that it is powerful and expressive once you know what you're about. One of the hardest things to swallow is that the provided on-line documentation is written assuming that you know what you're doing, and only need reminding. But because it is powerful, it is very easy to construct less dangerous, more intuitive environments for those who wish or require it. Out of the wrapper, UNIX is definitely not friendly. Which is ok with me, I require a powerful tool, not a friend. In summary, UNIX is pretty powerful, the naming conventions are really cryptic, the documentation assumes foreknowledge, it's trivial to customize. This does not bode well for the novice, but very well for the expert. >> |~~~~~~ Seattle: America's most attractive city... to the *jetstream* ~~~~~~| > Nice .sig! Cleveland: I spent a weak there one day... Regards, [Ag]
gaynor@brushfire.rutgers.edu (Silver) (06/24/91)
Good, good. The last time I made a similar posting, no one would bite. > Brevity should not be so slavishly emphasized as to affect comprehensibility, > another lesson we should not forget. I just read your Unix flame, and agree with many of your points, the same way I agree with the above line. I AM NOT saying toss clarity for brevity. I AM saying that the value of brevity should be accomodated when considering clarity. > As a general, probably fundamental rule, the more information you can place > IN THE CODE, and the more often you can do this IN ONE AND ONLY ONE PLACE, > the more maintainable your code. You cite a major consideration, but not the only one. How local is the definition of Default_Print to its use in the code? Does keeping it local break other conventions? Is it worth the trouble of adding it? By doing so, you double the code length in this example. (That is, it's more than a small constant amount of extra code. Otherwise the answer is of obviously "Yes.".) > I regard most comments as an admission of failure and/or a design flaw in the > implementation language. This is too easy a mark at face value. Please qualify. In general, I'll say that like anything else, comments can be abused. ;; Increment page counter is usually a total abuse, unless it is documenting something less intuitive than (setq page (+ page 1)) or there is some virtue to its placement. For instance, documenting the trivial `then' clause of a conditional to provide a visual match for the `else' clause. To wit, /* No further processing is usually required. However, such-n-such */ /* sometimes forces the condition, which is relatively rare. */ if (condition) then {/* Increment page counter */ i <- i + 1} else {/* An exception has occurred, probably by such-n-such. ... */ ...} > (why is it I am always arguing Ada with people who don't know it, even though > I DO know C and C++?) First off, I know or am familiar with all the languages in question, albeit some to a better extent than others. Second, Ada is not the be-all-end-all of languages. It has its good points and its bad points. Without spending a lot of time critiquing Ada, I'll simply say that I can appreciate some of its features without being terribly fond of it in general. In looking at your Default_Print, it's just too verbose for the job, and non-local. Consider #define _local_print(comment) print(comment, 5, laserprinter, helvetica) _local_print("a"); _local_print("b"); _local_print("c"); #undef _local_print or (mapcar '(lambda (comment) (print comment 5 laserprinter helvetica)) '("a" "b" "c")) or [(a) (b) (c)] {5 laserprinter helvetica print} foreach or ... >> There's a better example I'd love to harp on, the common practice of >> devoting an entire line to compound statement delimiters. > > An ENTIRE LINE!?!?! For shame--just think of all that wasted disk space. ;-) The device in question is not the disk, but rather, the window. These extra lines contain no semantic information that isn't made obvious by the indentation, and often as much as double the vertical length of the code. The only justifications I can think of are: - They make visual matching easier. But any editor worth its bits blinks matching parens more accurately than you could ever do manually. - Moving blocks of code around tends to be slightly easier. Conceded. I'll put in vertical whitespace where there should be some, but I won't dispense it wastefully. In increasing verbosity, if c if c if c then {s1 then { then s2 s1 { s3} s2 s1 else {s4 s3 s2 s5} } s3 else { } s4 else s4 { } s4 s5 } The rightmost case is common in non-Lispish languages. And is also twice as long, with no significant gain in readability. Note that if I thought the situation justified it, I would insert some white between the clauses. Fortunately, these kinds of transformations are mostly mechanical, and a programmable editor can be taught to make them on the fly. Unfortunately, it is only MOSTLY mechanical, so such transformations might not be perfect. Code is not usually examined in a vacuum. The amount of time required to switch buffers, shuffle printouts, scroll, look up documentation, etc., all contribute to the wholistic merit of a portion of code. Regards, [Ag]
philbo@arasta.uucp (Phillip Lindsay) (06/24/91)
>From: jls@netcom.COM (Jim Showalter) > >Ada programs of various sizes at companies ranging from just shy >of totally incompetent to quite good for the past four years, >and I'd say that 99.9% of the time all names are chosen with care. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Jim, you were standing behind the person when they picked the name? :-> >As for the C example, be real. Yes, people CAN write readable >code in C, and some even pride themselves on it. On the other .... words describing Jim's dis-like of Unix deleted >something of a fish in a different pond, I can rather accurately >observe and describe the water in which YOU swim. Consider, for ^^^^^^^^^^^^^^^ Jim, yow know the poster personally? :-} Really, Jim, it is getting very old. Your postings are very egocentric and a waste of bandwidth. The world knows you love Ada. I prefer not to like Ada (having spent three years doing Ada related DOD development). And Jim, what you choose to call Software Engineering is not the sole domain of Ada. Please, try using the net for more productive discussion. Thanks. Phillip Lindsay "Those environmentalists are just trying to ruin the world." Internet: ??????????????? Phone: Work7143852311 Home7142891201 UUCP : {spsd,zardox,felix}!dhw68k!arasta!philbo USMAIL : 152A S. Cross Creek Rd, Orange, Ca. 92669
diamond@jit533.swstokyo.dec.com (Norman Diamond) (06/24/91)
In article <Re8141w162w@arasta.uucp> philbo@arasta.uucp (Phillip Lindsay) writes: >Really, Jim, it is getting very old. Yes but... >I prefer not to like Ada (having spent three years doing Ada >related DOD development). Oh come on now, you don't judge a language on the basis of one of its customers. The military uses computers; doesn't that make you prefer not to like computers? -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it. Permission is granted to feel this signature, but not to look at it.
jls@netcom.COM (Jim Showalter) (06/25/91)
>I don't think jls is going to be overly fond of these conventions... Actually, this is good stuff. You're not the kind of C programmer who is causing the problems. >I spend quite a bit of time making sure that >my code is good enough to be used and maintained instead of replaced. Some of >the people I work with do not take such care. Thousands and thousands of lines >of code implement services of whose wonders I shall never partake because of >the total and complete lack of external documentation. Indeed, and this is the tragedy. Someone a few months ago made an excellent point about there being two kinds of programmers--those who write code for OTHERS, and those who ignore the fact that their code may have clients and may need to be maintained after they've been hit by a bus. The latter type are the ones who cost their employers lots and lots of money. >Yeah, pretty bad. `ls', `dbx', `cat', `cd', `tr', `mv', `rm', ..., they should >all be spelled out. HERETIC! ;-) >But because >it is powerful, it is very easy to construct less dangerous, more intuitive >environments for those who wish or require it. Indeed. However, this presupposes that an organization is willing to live with the overhead of having a sort of peripatetic toolsmith wandering around doing customizations for the great unwashed. This is okay, but you do need to factor in the cost of this if you want to do an honest accounting of the productivity of UNIX. For what it's worth, my brother took a class in UNIX and concluded that it "is a lot like MS-DOS, only harder to use"... -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
garry@alice.att.com (garry hodgson) (06/25/91)
In article <1991Jun21.013944.23970@netcom.COM>, jls@netcom.COM (Jim Showalter) writes: > kers@hplb.hpl.hp.com (Chris Dollin) writes: > It gets unacceptably ugly as the number of arguments increases above 1, which > means that in the typical case, you want named parameters: > Print (This_Comment => "I love named parameter names", > With_This_Spacing => 5, > On_This_Device => Devices.Laserprinter, > In_This_Font => Fonts.Helvetica); > and so forth. I find this considerably better than a name like > Print_Comment_With_Spacing_Device_and_Font_Toggles or some such. > >It can be too verbose to *read* as well. If it makes code unecessarily large, > >that is in and of itself a maintenance problem. > > Here we go again. The C equivalent of the above would typically look > something like: > prnt("I love named parameter names",5,lsptr,hlvtca); > This DOES take up less space. Is it more readable? You're doing it again, Jim. This is the kind of thing that caused all the flamage about your earlier C-bashing. Your points are valid enought without resorting to knocking down straw man code fragments. Try it this way: Here we go again. The C equivalent of the above would typically look something like: Print( "I love named parameter names", 5, Laserprinter, Helvetica ); This DOES take up less space. Is it more readable? My answer might be, "No, but with the exception of the wired-in constant 5 for spacing (which should have some useful name instead), it is about equally readable." People can write good or bad code in whatever language they choose. I get tired of always hearing that all C programmers are undisciplined losers who couldn't ( or wouldn't ) write a clean line of code if their lives depended on it. ( Yes, I Know you didn't say that ). Besides, complaining about C is sort of irrelevant. C++ is here now, and provides a variety of features that make it easier to write clean and robust code. It's like us raggin' on Ada because Pascal had problems. Who cares? -- Garry Hodgson AT&T Bell Labs
jls@netcom.COM (Jim Showalter) (06/25/91)
>Good, good. The last time I made a similar posting, no one would bite. Uh oh... ;-) >You cite a major consideration, but not the only one. How local is the >definition of Default_Print to its use in the code? Does keeping it local >break other conventions? Is it worth the trouble of adding it? By doing so, >you double the code length in this example. (That is, it's more than a small >constant amount of extra code. Otherwise the answer is of obviously "Yes.".) As with so many issues of good style, rules are made to be broken. Would I always rename Default_Print to make subsequent code more readable? Depends on the surrounding context. As you point out, in some cases this would just be overkill. In other cases, it would be the right thing to do. It is this subjective variability of proper style that makes me so suspicious of coding style guides, at least the ones that allow for no flexibility--"No loop shall have multiple exits", etc. Why not? What if the cleanest way to implement the code is with multiple exits in this particular case? And so forth. >> I regard most comments as an admission of failure and/or a design flaw in the >> implementation language. >This is too easy a mark at face value. Please qualify. I regard most comments as a failure to encode the same information in the source itself. This comes about either because the programmer has done a lousy job of naming, etc, so that the code is a cryptic mess that NEEDS comments (as opposed to well-written code, in which case the comments would be superfluous paraphrasings), or it comes about because the language itself lacks certain constructs, making the use of comments a necessary evil as a workaround (for example, not having formal parameter names forces the programmer to document each parameter with a comment). I do believe there is a role for higher-level documentation, such as an overall architecture/design document--but this sort of information is not appropriate for the code OR the comments. > /* No further processing is usually required. However, such-n-such */ > /* sometimes forces the condition, which is relatively rare. */ > if (condition) > then {/* Increment page counter */ > i <- i + 1} > else {/* An exception has occurred, probably by such-n-such. ... */ > ...} In Ada: begin Page_Counter := Page_Counter + 1; exception when Rare_Condition => [deal with error event] end; Note that this version requires no comments, and reads as clearly as the one with comments. This is an example of what I'm talking about: the lack of an exception construct in the C example is a LANGUAGE flaw, and so comments are required to work around it. (If the lack of exceptions is NOT a language flaw, why is Stroustrup working so hard to add them to C++?...) >In looking at your Default_Print, it's just too verbose for the job, and >non-local. Consider > #define _local_print(comment) print(comment, 5, laserprinter, helvetica) > _local_print("a"); > _local_print("b"); > _local_print("c"); > #undef _local_print Okay. So I'm a maintainer. I come along with no clue what you're up to, and I'm supposed to reason my way around the above example (don't even get me STARTED on the evils of macros and conditional compilation...). My first question is--what is the mystery number 5 for? Does it print the comment 5 times? Does it print the comment with 5 lines of spacing? Does it print the comment in a point size of 5? These are perfectly reasonable questions for a maintainer to ask, and they cannot be answered with just the code you show above, because the semantic content is insufficient. Yes, if I have a good development environment I can probably look up the original print operation fairly quickly...but what if I don't? What if I just have a gigantic cross reference listing, perhaps aggravated by overloading? In my "verbose" Ada example, there is no ambiguity or confusion: procedure Local_Print (This_Comment : in String; With_Line_Spacing : in Positive := 5; ... The maintainer is informed immediately that the spacing is 5. The information is local to its use. There is no mystery number. There is no need to look anything up. And there is no need for comments to explain what is going on. As a maintainer, I'd MUCH prefer the latter example to your example, and would not consider it verbose at all: I would appreciate your having been considerate enough to include as much information as I needed to get my job done as efficiently as possible. If "verbose" means "easily maintainable", then I guess I'm all in favor of verbosity. Sometimes I get the idea that when people say "verbose" what they are really saying is "I'm a slow typist", and that the issue really boils down to someone being to lazy to enter the requisite number of keystrokes to make their code easily comprehensible by others. This is an act of utmost selfishness, and could probably best be addressed by a remedial course in touch typing. > if c if c if c > then {s1 then { then > s2 s1 { > s3} s2 s1 > else {s4 s3 s2 > s5} } s3 > else { } > s4 else > s4 { > } s4 > s5 > } Well, in Ada the "then" and the "else" (and the "elsif"--missing from C) ARE the compound statement delimiters, so the above translates to: if c then s1; s2; s3; else s4; s5; end if; This is roughly equivalent to the first (and shortest) example given, with the added advantage that the dangling "else" problem is eliminated in Ada (there is a clear distinction between an "if" nested inside an "else" and an "elsif", eliminating a common source of errors). Or am I missing something? ;-) >such transformation >is only MOSTLY mechanical, so such transformations might not be perfect. With the ambiguity of the dangling else removed, the transformation is perfect. You can reorganize the lexical indentation of the branching construct to your heart's content and it will remain semantically identical. This remarkable innovation, by the way, existed when C was being invented, but for some reason it was deemed unworthy of inclusion... -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
jls@netcom.COM (Jim Showalter) (06/25/91)
>Really, Jim, it is getting very old. Your postings are very >egocentric and a waste of bandwidth. The world knows you love >Ada. I prefer not to like Ada (having spent three years doing Ada >related DOD development). And Jim, what you choose to call >Software Engineering is not the sole domain of Ada. Deep breath, mind calm... 1) Use your 'n' key, your 'k' key, or, for that matter, your .kill file. 2) I get a lot of positive feedback on my postings, so not everybody seems to agree that they are a waste of bandwidth. I TRY to add value to these groups. I TRY to post stuff based on real world experience on real projects at real companies with real problems. I don't see how this is egocentric. By the way, what have you contributed as of late, other than this flame? 3) The Ada examples are chosen because that is the software engineering language with which I am most familiar. The discussion concerned the value of formal parameter names, named parameter association, and so forth for documenting and resolving ambiguity in overloaded procedure names. If I was as facile with Eiffel or Modula-3 as I am with Ada, I could just as easily have cited examples in those languages, and, in fact, I would encourage those who ARE familiar with such languages to chime in. The issue is not Ada vs C--although that certainly seems to be the way the argument winds up getting cast most of the time--the issue is modern software engineering languages and their features vs languages that were invented a long time ago by people trying to solve tiny problems in comparison with the problems people are trying to solve today. >using the net for more productive discussion. Thanks. Please. By all means. Suggest another discussion. You're welcome. -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
philbo@arasta.uucp (Phillip Lindsay) (06/25/91)
diamond@jit533.swstokyo.dec.com (Norman Diamond) writes: > In article <Re8141w162w@arasta.uucp> philbo@arasta.uucp (Phillip Lindsay) wri > > >I prefer not to like Ada (having spent three years doing Ada > >related DOD development). > > Oh come on now, you don't judge a language on the basis of one of its > customers. The military uses computers; doesn't that make you prefer ^^^^^^^^^ > not to like computers? I wasn't making a judgment based on the "customer," but rather my personal experience with Ada. The work just happened to be related to DOD. Phillip Lindsay "Those environmentalists are just trying to ruin the world." Internet: ??????????????? Phone: Work7143852311 Home7142891201 UUCP : {spsd,zardox,felix}!dhw68k!arasta!philbo USMAIL : 152A S. Cross Creek Rd, Orange, Ca. 92669
jls@netcom.COM (Jim Showalter) (06/26/91)
>You're doing it again, Jim. This is the kind of thing that caused all >the flamage about your earlier C-bashing. Your points are valid enought >without resorting to knocking down straw man code fragments. Okay okay okay--fair enough. >Try it this way: > Here we go again. The C equivalent of the above would typically look > something like: > Print( "I love named parameter names", 5, Laserprinter, Helvetica ); > This DOES take up less space. Is it more readable? >My answer might be, "No, but with the exception of the wired-in constant >5 for spacing (which should have some useful name instead), it is about >equally readable." Well, in this particular case you know what Laserprinter and Helvetica happen to mean, so, unlike their friend the 5, they have sufficient semantic content to be readable as is. How about this sort of thing (this is NOT intended to be a straw man piece of bad code--I see this stuff all the time, so unless the code I review is, in fact, submitted to me by men made of straw, this rates as a legitimate code sample): argl (4.5, 8, INCR, "bargl"); Even with a more readable name for the function, the arguments remain essentially content-free without a lot of surrounding context. The whole point of named parameter association is to provide the missing semantics at the point of call, to wit: argl (Azimuth => 4.5, Inclination => 8, Mode => INCR, Options => "bargl"); Yes, this is still semi-dreadful, but it is a definite improvement over the first version, doesn't it? Why, you can almost start to figure out what is going on! Look, I'm not saying the advent of named parameter association will feed all the world's children, but I do tend to get a little hot under the collar when people--the very people you accuse me of inventing as straw men, by the way--respond to every advance in code readability with the "verbose" label. I've said it before and I'll say it again--there is nothing wrong with most hackers that couldn't be fixed with a remedial course in touch typing... >Besides, complaining about C is sort of irrelevant. C++ is here now, >and provides a variety of features that make it easier to write clean >and robust code. It's like us raggin' on Ada because Pascal had >problems. Who cares? Okay, true enough. I grant you that, much as I take issue with its warts, C++ DOES represent a golden opportunity to reboot the C/UNIX culture with a different mindset--one that recognizes the value of strong typing, abstraction, portability, maintainability, etc. On the other hand, if the very same people who argue that formal names for parameters are "verbose" are going to be doing the writing in C++, what makes you think anything is going to change? At least when people learn Ada they HAVE to learn a new language--it's not backward compatible with Pascal. -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
adam@visix.com (06/27/91)
In article <1991Jun26.001847.24239@netcom.COM>, jls@netcom.COM (Jim Showalter) writes: > argl (4.5, 8, INCR, "bargl"); > Even with a more readable name for the function, the arguments remain > essentially content-free without a lot of surrounding context. The whole > point of named parameter association is to provide the missing semantics > at the point of call, to wit: > argl (Azimuth => 4.5, Inclination => 8, Mode => INCR, Options => "bargl"); I almost never put raw constants in my code, both because of the thin semantics and because changing the constants becomes a ridiculous hunt-and-kill exercise. ("Search-and-replace: 5 [CR] with: 6 [CR]"). I would write the above in C as follows: In a header file, perhaps argl.h: #define STANDARD_AZIMUTH 4.5 #define STANDARD_INCLINATION 8 #define STANDARD_OPTIONS "bargl" In the code: argl( STANDARD_AZIMUTH, STANDARD_INCLINATION, INCR_MODE, STANDARD_OPTIONS ); Other common parameter sets might be called SECONDARY_AZIMUTH and so on. Derived or continuous values would necessarily be stored in variables, which I could then name accordingly. The primary motivation for all this is actually to provide a single maintenance point (the header file) for parametrizing the behavior of the code. The semantics part is simply choosing appropriate names. > Look, I'm not saying the advent of named parameter association will > feed all the world's children, but I do tend to get a little hot under > the collar when people--the very people you accuse me of inventing as > straw men, by the way--respond to every advance in code readability with > the "verbose" label. I've said it before and I'll say it again--there > is nothing wrong with most hackers that couldn't be fixed with a remedial > course in touch typing... Some people who complain about verbosity are hackers. Some people who complain about verbosity have given the matter a lot of thought and have useful points to make. Sometimes it's easy to confuse the two. Adam
garry@alice.att.com (garry hodgson) (06/27/91)
In article <1991Jun26.001847.24239@netcom.COM>, jls@netcom.COM (Jim Showalter) writes: > How about this sort of thing > (this is NOT intended to be a straw man piece of bad code--I see this > stuff all the time, so unless the code I review is, in fact, submitted > to me by men made of straw, this rates as a legitimate code sample): > argl (4.5, 8, INCR, "bargl"); Clearly, the solution here is to hunt down the author and kill him. I believe this solution is language independant. And so much fun :-) > The whole > point of named parameter association is to provide the missing semantics > at the point of call, to wit: > argl (Azimuth => 4.5, Inclination => 8, Mode => INCR, Options => "bargl"); > Yes, this is still semi-dreadful, but it is a definite improvement over > the first version, isn't it? Indeed it is, if you can convince the (now-deceased :-) author to use it. But anyone who would write code like that would be unlikely to take advantage of an admittedly nice feature. And many of the folks who would use it don't necessarily need it. I do, however, like the idea of specifying only those paramters you care about, letting others use default values. I believe this is supported. C++ allows this to a limited extent, but since parameters are positional, you're limited to the trailing ones getting defaults. > Okay, true enough. I grant you that, much as I take issue with its > warts, C++ DOES represent a golden opportunity to reboot the C/UNIX > culture with a different mindset--one that recognizes the value of > strong typing, abstraction, portability, maintainability, etc. When I first started using C++, I thought "Thank God, I finally have language support for all the stuff I've been trying to do in C all this time" It was an easy sell, for me. Other folks exemplify the "Real Men can write Fortran in any language" methodology. I doubt there is any hope for them, short of early retirement. > On the > other hand, if the very same people who argue that formal names for > parameters are "verbose" are going to be doing the writing in C++, > what makes you think anything is going to change? See above ("Real Men..."). I agree with you, it seems, on most of what you're saying. I just don't believe that language features can save those who don't want to be saved. I briefly thought that C++ could help; that by starting with a well-designed set of base classes one could force good style upon users of those classes. Then I saw a set of "spaghetti-classes", the OO equvalent of "spaghetti-code", and realized there was no hope... I suppose I fall on the verbose side of the fence, myself. I don't touch type, but I do type quickly, and tend to cut/paste/snarf more than type, anyway. I take great pains to make my code readable, obvious, and esthetically appealing. This last point is very important to me, and is, indeed, my main problem with Ada. It just doesn't appeal to my sense of esthetics. I realize this may seem silly, but it is there nonetheless. So while I can see the value to an organization using Ada, I just don't want to use it personally. -- Garry Hodgson One way or another, AT&T Bell Labs this darkness got to give...
amanda@visix.com (Amanda Walker) (06/27/91)
adam@visix.com (Adam Kao) writes:
I almost never put raw constants in my code, both because of the thin
semantics and because changing the constants becomes a ridiculous
hunt-and-kill exercise. ("Search-and-replace: 5 [CR] with: 6 [CR]").
I agree (which may not be a surprise :)). Use of macro-defined and
enumerated constants is an important aspect of good coding style, in C
as in any other language.
One of the things I like about Common Lisp is the way it handles "keyword
arguments." In particular, you can often write functions that have a
useful mixture of implicitly and explicity labelled parameters. For example:
(make-array '(2 2))
makes an uninitialized array (or perhaps one initialized to some default
value), while
(make-array '(2 2) :initial-contents '((1 2) (3 4)))
makes one with the specified initial contents, and so on.
--
Amanda Walker amanda@visix.com
Visix Software Inc. ...!uunet!visix!amanda
--
"I have never seen anything fill up a vacuum so fast and still suck."
-- Rob Pike commenting on the X Window System
dmg@ssc-vax (David M Geary) (06/27/91)
]]] Phillip Lindsay ]] Jim Showalter ] Garry Hodgson ]] ]] Here we go again. The C equivalent of the above would typically look ]] something like: ]] prnt("I love named parameter names",5,lsptr,hlvtca); ]] This DOES take up less space. Is it more readable? ] You're doing it again, Jim. This is the kind of thing that caused all ] the flamage about your earlier C-bashing. Your points are valid enought ] without resorting to knocking down straw man code fragments. ] Try it this way: ] Here we go again. The C equivalent of the above would typically look ] something like: ] Print( "I love named parameter names", 5, Laserprinter, Helvetica ); ] People can write good or bad code in whatever language they choose. ] I get tired of always hearing that all C programmers are undisciplined ] losers who couldn't ( or wouldn't ) write a clean line of code if their ] lives depended on it. ( Yes, I Know you didn't say that ). ] Besides, complaining about C is sort of irrelevant. C++ is here now, ] and provides a variety of features that make it easier to write clean ] and robust code. It's like us raggin' on Ada because Pascal had ] problems. Who cares? ]]] Really, Jim, it is getting very old. Your postings are very ]]] egocentric and a waste of bandwidth. The world knows you love ]]] Ada. I prefer not to like Ada (having spent three years doing Ada ]]] related DOD development). And Jim, what you choose to call ]]] Software Engineering is not the sole domain of Ada. Please, try ]]] using the net for more productive discussion. Thanks. D I T T O. -- |~~~~~~~~~~ David Geary, Boeing Aerospace, Seattle, WA. ~~~~~~~~~~| |-----------------------------------------------------------------------------| |~~~~~~ Seattle: America's most attractive city... to the *jetstream* ~~~~~~| |-----------------------------------------------------------------------------|
dmg@ssc-vax (David M Geary) (06/27/91)
]> Jim Showalter ] adam@visix ]> argl (4.5, 8, INCR, "bargl"); ] ]> Even with a more readable name for the function, the arguments remain ]> essentially content-free without a lot of surrounding context. The whole ]> point of named parameter association is to provide the missing semantics ]> at the point of call, to wit: ]> argl (Azimuth => 4.5, Inclination => 8, Mode => INCR, Options => "bargl"); ]I almost never put raw constants in my code, both because of the thin ]semantics and because changing the constants becomes a ridiculous ]hunt-and-kill exercise. ("Search-and-replace: 5 [CR] with: 6 [CR]"). ] ]I would write the above in C as follows: ] ]In a header file, perhaps argl.h: ] ]#define STANDARD_AZIMUTH 4.5 ]#define STANDARD_INCLINATION 8 ]#define STANDARD_OPTIONS "bargl" ] ]In the code: ] ]argl( STANDARD_AZIMUTH, STANDARD_INCLINATION, INCR_MODE, STANDARD_OPTIONS ); ] ]The primary motivation for all this is actually to provide a single maintenance ]point (the header file) for parametrizing the behavior of the code. The ]semantics I have worked exclusively with C programmers for 7 years in various software development environments in the real world, and have taught C for 5 yrs in a corporate setting. 3 points: 1. Defining constants as was done above is a standard C'ism. Anyone who has advanced past the first night of an introductory C course is aware of the mechanism for defining constants, and the value obtained by doing so. 14 pages into K&R, we find: "It's bad practice to bury "magic numbers" like 300 and 20 in a program; they convey little information to someone who might have to read the program later, and they are hard to change in a systematic way." 2. Anyone who has advanced past the first night of an introductory C course is also aware that one should name variables and functions with names that convey their meaning: 36 pages into K&R, we find: "It's wise to choose variable names that are related to the purpose of the variable ..." 3. In a posting a few months back, I posted some C code where I defined some functions to be static, which of course, as any C programmer knows, limits the scope of the function to the file that it is in. Jim, in a reply blasting my code did not seem to understand what the keyword static applied to a function meant. From the 3 points made above, I surmise: 1. Jim does not know that the vast majority of C programmers do not use raw constants in their code. 2. Jim does not know that the vast majority of C programmers do not use ridiculously terse names such as arg1() for function names. 3. Jim does not understand how to limit the scope of a function (in C) to the file it is in. 4. Jim does not understand the C language very well. 5. Jim is not qualified to criticize the C language, or it's users. Jim, go ahead and tell us how wonderful Ada is. Ada has some good points, and you can contribute something positive to this group by constantly referring back to the merits of Ada in a software engineering context. Avoid attacking the C language and it's users. You are not qualified to do so, and we are all tired of your exaggerated, absurd straw-man code fragments, and your backhanded insults to the C programming community. PS: Everyone else credits those whom they quote, why can't you? -- |~~~~~~~~~~ David Geary, Boeing Aerospace, Seattle, WA. ~~~~~~~~~~| |-----------------------------------------------------------------------------| |~~~~~~ Seattle: America's most attractive city... to the *jetstream* ~~~~~~| |-----------------------------------------------------------------------------|
jls@netcom.COM (Jim Showalter) (06/28/91)
>I agree (which may not be a surprise :)). Use of macro-defined and >enumerated constants is an important aspect of good coding style, in C >as in any other language. The difference, as I pointed out at the start of this thread-within-a- thread, is that in SOME languages the language designer is kind enough to supply the programmer with LANGUAGE constructs that directly support good coding style, and in others the onus is on the programmer. Thus, in the first kind of language the programmer has to go out of their way to defeat these mechanisms in order to degrade legibility, whereas in the latter kind of language the programmer has to go out of their way to work around the lack of such mechanisms. Human laziness, ignorance, and schedules being what they are, what do you think the default behavior turns out to be? Consider enumeration constants in C. Yes, very nice--very legible, helps a great deal during maintenance. I'm all for them. On the other hand, there are a lot of other languages that simply GIVE you enumeration types so you don't have to use good community hygiene in order to write readable code (even C++ has them...imagine that!). I was making a similar argument for formal parameter names and named parameter association when we veered off into this enumeration stuff. >One of the things I like about Common Lisp is the way it handles "keyword >arguments." In particular, you can often write functions that have a >useful mixture of implicitly and explicity labelled parameters. For example: > (make-array '(2 2)) >makes an uninitialized array (or perhaps one initialized to some default >value), while > (make-array '(2 2) :initial-contents '((1 2) (3 4))) >makes one with the specified initial contents, and so on. You might be amazed, but this is remarkably similar to Ada's formal parameter names, named parameter association, and default arguments, which I was discussing earlier in this thread. I guess there must be some consensus as to the value of such readability enhancers among language designers, huh? :-0 -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
jls@netcom.COM (Jim Showalter) (06/28/91)
> From the 3 points made above, I surmise:
[5 incorrect conclusions about my grasp of C and the C culture deleted]
[gratuitous personal attack deleted]
[poster's .sig (only remaining content to message) deleted]
Redirect to alt.flame.
--
*** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 ****
*Proven solutions to software problems. Consulting and training on all aspects*
*of software development. Management/process/methodology. Architecture/design/*
*reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
jls@netcom.COM (Jim Showalter) (06/28/91)
[several screenfulls of quotes from other people's posts deleted] [one word of original content deleted] [poster's .sig (only remaining content in message) deleted] All this in a message accusing ME of wasting bandwidth (and this is the SECOND flame in as many posts by this same guy). Redirect to alt.flame. -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
jimad@microsoft.UUCP (Jim ADCOCK) (06/29/91)
|akers@hplb.hpl.hp.com (Chris Dollin) writes: |] |]It gets unacceptably ugly as the number of arguments increases above 1, which |]means that in the typical case, you want named parameters: |] |] Print (This_Comment => "I love named parameter names", |] With_This_Spacing => 5, |] On_This_Device => Devices.Laserprinter, |] In_This_Font => Fonts.Helvetica); |] I'd claim named parameters are a poor substitute for methods and classes: StyledString str = "Named parameters are a poor substitute for OOP"; str.spacing(5); str.font(helvetica); laserPtr << str; When I see programmers using functions/methods with more than a couple parameters, I can be sure they aren't really into OOP yet.
amanda@visix.com (Amanda Walker) (06/29/91)
jls@netcom.COM (Jim Showalter) writes:
in SOME languages the language designer is kind enough to supply
the programmer with LANGUAGE constructs that directly support good
coding style, and in others the onus is on the programmer.
Jim, the onus is *always* on the programmer. I have never seen any
situation in which clear, legible code is easier to write than
confusing, illegible code. None. Zip. Nada. Writing well requires
skill and talent, whether you are writing C, Ada, or English.
there are a lot of other languages that simply GIVE you enumeration types
so you don't have to use good community hygiene in order to write readable
code (even C++ has them...imagine that!).
Yo. Even C has them. Has had for, oh, ten years or so. Modern compilers
even typecheck them for you. What a concept :).
You might be amazed, but this is remarkably similar to Ada's formal
parameter names, named parameter association, and default arguments,
which I was discussing earlier in this thread.
I never said Ada was a crock :). I just think your arguments for it (and
against "C") could be ... er ... better constructed.
--
Amanda Walker amanda@visix.com
Visix Software Inc. ...!uunet!visix!amanda
--
"C++ is like a glass of buttermilk: the taste doesn't bother you so much;
it's what it does to the glass afterwards." --Kurt Schmucker
jls@netcom.COM (Jim Showalter) (06/29/91)
amanda@visix.com (Amanda Walker) writes: >Jim, the onus is *always* on the programmer. I have never seen any >situation in which clear, legible code is easier to write than >confusing, illegible code. None. Zip. Nada. Writing well requires >skill and talent, whether you are writing C, Ada, or English. Well, I guess we have to agree to disagree on this point. That it is easier by far to write legible, unconfusing code than it is to write illegible, confusing code seems axiomatic to me. If the code is confusing, how then am I to debug it? Seems obvious--but you apparently disagree. It has ALWAYS seemed more straightforward to me to write code that is easy to read than to write code that is hard to read. To quote Dijkstra: "I have a small brain, but I've learned to live with it". How anybody can expend LESS energy writing hard-to-read code is beyond me. It would require a great effort on my part to do so. >Yo. Even C has them. Has had for, oh, ten years or so. Modern compilers >even typecheck them for you. What a concept :). Sorry, mea culpa. I read the original poster's example to be that he was concocting some enumeration literals. What he was doing was quite different--he was concocting some constants using #defines. I could revisit the topic and rip into the notion of constants as macros, but I think I'll just let it drop at this point. -- *** LIMITLESS SOFTWARE, Inc: Jim Showalter, jls@netcom.com, (408) 243-0630 **** *Proven solutions to software problems. Consulting and training on all aspects* *of software development. Management/process/methodology. Architecture/design/* *reuse. Quality/productivity. Risk reduction. EFFECTIVE OO usage. Ada/C++. *
plyon@ut-emx.uucp (Paul Lyon) (06/29/91)
So far as I know, enumerations, along with function prototypes, and several other things, were adopted into ANSI C after having first been included in C++. Competitive pressures in the MS-DOS market led to these features being included in MS-DOS C compilers some 4 or 5 years ago, but ANSI compliant UNIX C compilers seem still to be rather the exception than the rule. But, in reply to Amanda Walker, 10 years ago is pushing it, don't you think? Paul Lyon
marti@mint.inf.ethz.ch (Robert Marti) (06/29/91)
In article <1991Jun29.001927.18591@netcom.COM> jls@netcom.COM (Jim Showalter) writes: [on software engineering, programming style, C, Ada, macros, and enumerations] >I could revisit the topic and rip into the notion of constants as macros, >but I think I'll just let it drop at this point. Yes, please. After all, this is comp.object ... Robert Marti | Phone: +41 1 254 72 60 Institut fur Informationssysteme | FAX: +41 1 262 39 73 ETH-Zentrum | E-Mail: marti@inf.ethz.ch CH-8092 Zurich, Switzerland |
schwartz@groucho.cs.psu.edu (Scott Schwartz) (07/01/91)
In article <73230@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: | StyledString str = "Named parameters are a poor substitute for OOP"; SmallTalk has keyword parameters, and they are Real Nice.