[comp.object] Functions without side effects

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.