Newsgroups: comp.lang.smalltalk
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!news2.near.net!howland.reston.ans.net!math.ohio-state.edu!magnus.acs.ohio-state.edu!csn!col.hp.com!news.dtc.hp.com!hplextra!hplb!tgg
From: tgg@hplb.hpl.hp.com ()
Subject: Re: Common bugs
Sender: news@hplb.hpl.hp.com (Usenet News Administrator)
Message-ID: <CyqLqu.Fx3@hplb.hpl.hp.com>
Date: Fri, 4 Nov 1994 09:44:52 GMT
References: <Pine.3.81paf.9411031503.B8215-b100000@mailbox.swip.net>
Nntp-Posting-Host: thegnome.hpl.hp.com
Organization: Hewlett-Packard Laboratories, Bristol, England
X-Newsreader: TIN [version 1.2 PL0.7]
Lines: 556

Here is a previous thread on the same subject.


From johnson@m.cs.uiuc.edu Sat Jul 18 12:39:41 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: johnson@m.cs.uiuc.edu (Ralph Johnson)
Date: Sat, 18 Jul 1992 11:39:41 GMT
Date-Received: Sat, 18 Jul 1992 12:06:01 GMT
Subject: Classic Smalltalk bugs
Message-ID: <1992Jul18.113941.30839@m.cs.uiuc.edu>
Organization: University of Illinois, Dept. of Comp. Sci., Urbana, IL
Path: otter!hpltoad!hpopd!hplextra!hpscdc!news.dtc.hp.com!hp-col!sdd.hp.com!ux1.cso.uiuc.edu!m.cs.uiuc.edu!johnson
Newsgroups: comp.lang.smalltalk
Lines: 27

I'd like to start a collection of classic Smalltalk bugs.  These are
bugs that every new Smalltalk programmer runs into.  The idea is that
if we teach these bugs up front then people can learn to be good
programmers faster.

We just saw one; if you add an instance variable to a variable-sized
class then you have to make sure that if an instance grows then the
variable gets copied. 

Another bug that I see nearly everyone make is that add: returns its
argument, not the receiver, and people usually assume that it returns
its receiver.  Thus, they write "(c add: x) add: y" when they should
really write "c add: x; add: y" or else "c add: x. c add: y".  This
is a bug that would be caught by static type-checking.

Another classic bug is that a class instance creation method leaves
out the return statement, so it is 
  super new init
instead of 
  ^super new init
The result is that you have the class where you want the instance of
the class.  It seems to me that half the time I leave off a return,
it is in an instance creation method.

What common bugs do you see?  What bug bit you most recently?

Ralph Johnson -- University of Illinois at Urbana-Champaign

From steinman@is.morgan.com Sun Jul 19 01:24:31 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: steinman@is.morgan.com (Jan Steinman)
Date: Sun, 19 Jul 1992 00:24:31 GMT
Date-Received: Sun, 19 Jul 1992 01:05:12 GMT
Subject: Re: Classic Smalltalk bugs
Message-ID: <STEINMAN.92Jul18192431@hawk.is.morgan.com>
Organization: Morgan Stanley & Company
Path: otter!hpltoad!hpopd!hplextra!hpscdc!sdd.hp.com!wupost!uunet!s5!is1.is.morgan.com!is0.is.morgan.com!steinman
Newsgroups: comp.lang.smalltalk
References: <1992Jul18.113941.30839@m.cs.uiuc.edu>
Sender: news@is.morgan.com
Lines: 25
In-Reply-To: johnson@m.cs.uiuc.edu's message of Sat, 18 Jul 1992 11:39:41 GMT
Nntp-Posting-Host: hawk

In article <1992Jul18.113941.30839@m.cs.uiuc.edu> johnson@m.cs.uiuc.edu (Ralph Johnson) writes:

   Another bug that I see nearly everyone make is that add: returns its
   argument, not the receiver, and people usually assume that it returns
   its receiver.  Thus, they write "(c add: x) add: y" when they should
   really write "c add: x; add: y" or else "c add: x. c add: y".  This
   is a bug that would be caught by static type-checking.

Even worse is if someone implements #add: so that it returns "self",
and the experienced user of that method assumes that it returns the
argument, like all other well-behaved adding protocol!

Adding protocol returns the argument for a good reason: it often keeps
you from resorting to temps. You can create the argument to #add: on
the fly, and then do other things with it after the #add:.

In keeping with the subject line, how about the common assumption that
returned Collections can be modified? I recently had an ugly fight
with "ScheduledControllers scheduledControllers" until I realized that
it is implemented as "^scheduledControllers copy"!

--
: : Jan Steinman	   steinman@is.morgan.com		 Bytesmiths : :
: : 2002 Parkside Court				   West Linn, OR 97068-2767 : :
: : 503/657-7703					       212/956-8722 : :

From peterg@netcom.com Sun Jul 19 22:35:09 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: peterg@netcom.com (Peter Goodall)
Date: Sun, 19 Jul 1992 21:35:09 GMT
Date-Received: Mon, 20 Jul 1992 00:11:22 GMT
Subject: Re: Classic Smalltalk bugs
Message-ID: <x8bmmvn.peterg@netcom.com>
Organization: Netcom - Online Communication Services  (408 241-9760 guest)
Path: otter!hpltoad!hpopd!hplextra!hpscdc!sdd.hp.com!mips!decwrl!decwrl!netcomsv!mork!peterg
Newsgroups: comp.lang.smalltalk
References: <1992Jul18.113941.30839@m.cs.uiuc.edu>
Lines: 25

johnson@m.cs.uiuc.edu (Ralph Johnson) writes:

>I'd like to start a collection of classic Smalltalk bugs.  These are
>bugs that every new Smalltalk programmer runs into.  The idea is that
>if we teach these bugs up front then people can learn to be good
>programmers faster.

I have just been cleaning up a system that uses Pool Dictionaries in a
fairly dynamic way. The biggest problem is that the associations whose keys
are the referenced names in the Pool Dictionary are stored in the
CompiledMethods at compile time. If you create a new version of the Pool
Dictionary and install it by simple assignment. The compiled methods still
refer to the old associations. This can easily lead to strange behavior.

If you substitute a new instance of Dictionary or replace, rather thatn
update an association in a pool dictionary, you have to recompile all
methods using variables scoped to that Pool.

This is is also annoying when using ENVY, where the methods are under
strict control. Perhaps Pool Dictionaries should be be first-class
versioned pre-requisites of Classes, just like the class definition.

BTW we are using/VPM 1.4 with ENVY 1.3

Peter Goodall -- pererg@netcom.com

From knight@mrco.carleton.ca Mon Jul 20 03:50:39 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: knight@mrco.carleton.ca (Alan Knight)
Date: Mon, 20 Jul 1992 02:50:39 GMT
Date-Received: Mon, 20 Jul 1992 04:16:21 GMT
Subject: Re: Classic Smalltalk bugs
Message-ID: <knight.711600639@cunews>
Organization: Carleton University
Path: otter!hpltoad!hpopd!hplextra!hpscdc!sdd.hp.com!cs.utexas.edu!torn!cunews!cunews!knight
Newsgroups: comp.lang.smalltalk
References: <1992Jul18.113941.30839@m.cs.uiuc.edu> <STEINMAN.92Jul18192431@hawk.is.morgan.com>
Sender: news@cunews.carleton.ca (News Administrator)
Reply-To: knight@mrco.carleton.ca (Alan Knight)
Lines: 17

>In article <1992Jul18.113941.30839@m.cs.uiuc.edu> johnson@m.cs.uiuc.edu (Ralph Johnson) writes:

>   Another bug that I see nearly everyone make is that add: returns its
>   argument, not the receiver, and people usually assume that it returns
>   its receiver.  Thus, they write "(c add: x) add: y" when they should
>   really write "c add: x; add: y" or else "c add: x. c add: y".  This
>   is a bug that would be caught by static type-checking.

With collections, there is also the classic error of iterating over a
collection which the iteration loop somehow modifies. In some cases
the modification can be quite indirect and the effects difficult to
locate.
-- 
 Alan Knight  knight@mrco.carleton.ca  +1 613 788 2600x5783   Join
 Dept. of Mechanical and Aerospace Engineering                the
 Carleton University, Ottawa, Ontario, Canada, K1S 5B6        LPF


From scrl Mon Jul 20 08:28:42 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: scrl@otter.hpl.hp.com (Simon Lewis)
Date: Mon, 20 Jul 1992 07:28:42 GMT
Date-Received: Mon, 20 Jul 1992 07:28:42 GMT
Subject: Re: Classic Smalltalk bugs
Message-ID: <2610024@otter.hpl.hp.com>
Organization: Hewlett-Packard Laboratories, Bristol, UK.
Path: otter!scrl
Newsgroups: comp.lang.smalltalk
Posting-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
References: <1992Jul18.113941.30839@m.cs.uiuc.edu>

Not so much a bug, but a common mistake I think :-

(a < b) ifTrue: [a := a + 1].     "Works fine."
(a < b) whileTrue: [a := a + 1].  "Is an error.  Should be [a < b]."

I've seen people do this, and take an awfully long time to figure out why
the second one doesn't work, particularly if they *know* the system implements
whileTrue:, but have a less than perfect understanding of *how* it works.


Simon Lewis,
HP Labs, Bristol, UK.
From johnson@m.cs.uiuc.edu Wed Aug 12 23:29:16 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: johnson@m.cs.uiuc.edu (Ralph Johnson)
Date: Wed, 12 Aug 1992 22:29:16 GMT
Date-Received: Thu, 13 Aug 1992 00:59:58 GMT
Subject: catalog of classic bugs
Message-ID: <1992Aug12.222916.18784@m.cs.uiuc.edu>
Organization: University of Illinois, Dept. of Comp. Sci., Urbana, IL
Path: otter!hpltoad!hpopd!hplextra!hpscdc!sdd.hp.com!ux1.cso.uiuc.edu!m.cs.uiuc.edu!johnson
Newsgroups: comp.lang.smalltalk
Lines: 321
Summary: version 1 of the catalog of classic Smalltalk bugs

Classic Smalltalk Bugs

compiled by Ralph Johnson -- University of Illinois at Urbana-Champaign

Every programming system is prone to certain kinds of bugs.  A good
programmer learns these bugs, and how to avoid them.  Smalltalk is
no different.  Smalltalk eliminates lots of bugs that are common in
other languages, such as bugs in linear search algorithms.  (Just use do:)
However, it has its own set of classic bugs, which every new Smalltalk 
programmer runs into.  

There are several reasons to collect classic bugs.  The first is that
it will help experienced programmers test and debug programs, and can
help us design better programs in the first place.  Second, if we
teach these bugs up front then people should learn to be good
programmers faster.  Third, perhaps we can redesign the system to
eliminate some of these bugs, or we can write checking tools to
spot them automatically.

Bug 1: Variable-sized classes

Set, Dictionary, and OrderedCollection are variable-sized classes
that grow.  They grow by making a copy of themselves and "becoming"
the copy.  If you add new instance variables to a subclass then
you have to make sure that these instance variables get copied, too,
or else you will mysteriously lose the values of the instance
variables at random points in time.

Smalltalk-80 R4.0 (and probably some earlier versions) has a
copyEmpty: method in Collection that you are supposed to override
if you make a subclass of Collection that adds instance varaibles.
The solution to this bug is to write a version of copyEmpty: for
your class.

It has been suggested that it would be easy to write a tool that
checked that every new subclass of Collection that added instance
variables also defined a method for copyEmpty:.

Collection bugs

Bug 2: add: returns its argument

For every collection that grows, add: returns its argument,
not the receiver, and people usually assume that it returns
its receiver.  Thus, they write "(c add: x) add: y" when they should
really write "c add: x; add: y" or else "c add: x. c add: y".
Note that this is one of the good uses for "yourself", you can write
(Set new 
	add: x; 
	add: y;
	...;
	yourself) 
to make sure that you have the new Set.

Note that there are good reasons why add: returns its arguments,
and even if there weren't, it is a very, very bad mistake to
implement add: so that it returns the receiver, and so confuse
every other Smalltalk programmer on the planet.
Making add: return its argument often keeps you from resorting
to temps, because you can create the argument to add: on the
fly, and then do other things with it after the add:.  If you
want to access the collection, you can do it with yourself or
cascaded messages, as described above.

Bug 3: changing collection while iterating over it

You should never, never, never iterate over a collection which
the iteration loop somehow modifies. Elements of the collection
will be moved during the iteration, and elements might be missed
or handled twice.  Instead, make a copy of the collection you
are iterating over, i.e.
   aCollection copy do: [:each | aCollection remove: each]
is a good program, but if you leave out the copy then it isn't.

Mario Wolczko suggested a solution that catches this problem the
instance it occurs (at some performance penalty of course).  The
solution is to change the collection classes.  Each iteration method
enters that collection into a set of collections being iterated over
(IteratedCollections), executes the block, then removes the collection
from the set.  Collections are usually (only?) modified using at:put:
or basicAt:put:, so these are overriden to check that the collection
is not in IteratedCollections.  If it is, an error is signalled.  You
can either use this technique all the time, or you can just install
these classes when you are testing and debugging your program.  These
changes are packaged in a file Iterator-check.st that is available on
the Manchester and Illinois servers.  On the Illinois server, it is
in /pub/MANCHESTER/manchester/4.0/Iterator-check.st.

Bug 4: modifying copies of collections

It is common for an object to have an accessing method that returns a
collection of objects that you can modify.  However, sometimes
an object will return a copy of this collection to keep you from
modifying it.  Instead, you are probably supposed to use messages
that will change the collection for you.  The problem is that this
is often poorly documented, and a person who likes to modify collections
directly will run into problems.  See  "ScheduledControllers
scheduledControllers" for an example.

The solution is to either provide better documentation, to claim
that nobody is allowed to modify copies of collections returned
from other objects, or to have objects that don't want their
collections modified to return immutable versions of the collections
that will give an error if you try to modify them.

Bug 5: Missing ^

It is very easy to leave off a return caret on an expression.
If there is no return at the end of a method, Smalltalk returns
the receiver of the method.  It only takes one missing return
to mess up a long chain of method invocations.

Bug 6: Class instance creation methods

Writing a correct instance create method is apparently non-trivial.
The correct way to do it is to have something like
new
  ^super new init
where you redefine init in each class to initialize that class's
instance variables.  In turn, init is defined as a class method
init
  super init "to initialize inherited instance variables"
  "initialize variables that I define"

There are lots of ways to do this wrong.  Perhaps the most common
is to forget the return, i.e. to write
   super new init
The result is that you have the class where you want the instance of
the class.  This is a special case of bug #?.

Another error is to make an infinite loop by writing
  ^self new init

If Smalltalk doesn't respond when you think it should, press ^C to
get the debugger.  If the debugger shows a stack of "new" messages
then you know you made this mistake.

Finally, you should only define "new" once for each class hierarchy
and let subclasses inherit the method.  If you redefine it in each
class then you will reinitialize the new object many times, wasting
time and perhaps memory.

One way to keep this from happening is to make the "new" method in
Object send init, and have the "init" method in Object do nothing.
Of course, sometimes the version of init that you define has arguments,
and this wouldn't help those cases.  It is probably better to rely
on education to eliminate this kind of error.

Bug 7: Recompiling bugs in Smalltalk/V

It is easy to have references to obsolete objects in Smalltalk/V
if you change code without cleaning things up carefully. For example,
the associations whose keys are the referenced names in the Pool 
Dictionary are stored in the CompiledMethods at compile time. If you 
create a new version of the Pool Dictionary and install it by simple
assignment then the compiled methods still refer to the old associations.

If you substitute a new instance of Dictionary or replace, rather than
update an association in a pool dictionary, you have to recompile all
methods using variables scoped to that Pool.

This is is also annoying when using ENVY, where the methods are under
strict control. Perhaps Pool Dictionaries should be be first-class
versioned pre-requisites of Classes, just like the class definition.

BTW we are using/VPM 1.4 with ENVY 1.3

1. If you prune & graft a subtree of your class structure you have to
make sure that all referencing methods are recompiled. Otherwise you
will run (or your customer, because this is only detected at run time)
into an Deleted class error message.
Thomas Muhr posted a "Bite" a while ago to handle this problem for
Smalltalk/V 286.

Bug 8: Opening windows

Neither Smalltalk-80 nor Smalltalk-V return to the sender when a
new window is opened in a standard fashion. Thus, any code after
a message to open a window will never be executed.  This is the
cause of much frustration.  For example, if you try to open two
windows at once, i.e.

TextPane new open.
TextPane new open

is Smalltalk-V and

aScheduledWindow1 open.
aScheduledWindow2 open

in Smalltalk-80, then you will get only one open window,
and one forgotten piece of code.

I don't know the fix for Smalltalk-V.  The fix for Smalltalk-80 is
to use the openNoTerminate method to open the window, which does
not transfer control to it.  A useful trick is to store the new
window in a global variable so you can test it.  In earlier
versions of Smalltalk-80, open would obliterate the current
process, not just never return to it.  In Version 4.1 that
never happens.

Bug 9: blocks

Blocks are very powerful, and it isn't hard for programmers to get
into trouble trying to be too tricky.  To compound problems, the
two versions of Smalltalk have slightly different semantics for
blocks, and one of them often leads to problems.

Originally blocks did not have truly local variables.  The block
parameters were really local variables in the enclosing method.
Thus,

| x y |
  x := 0.
  (1 to: 100) do: [:z | x := x + z]

actually had three temporaries, x, y, and z.  This leads to bugs
like the following

someMethod

 | a b  |
 a := #(4 3 2 1).
 b := SortedCollection sortBlock: [:a :b | a someOperation: b].
 b addAll: a.
 Transcript show: a.

When elements are added to b, the sortBlock is used to tell where
to put them, but this will change a and b.  addAll: is OK, but
the "a" that gets displayed on the transcript will be an integer,
not an array.

Early versions of Smalltalk-80 (2.4 and before?) implemented blocks
like this, and Smalltalk/V still does.  However, in current PPS
implementations, blocks are close to being closures. You can declare
variables local to a block, and the names of the block parameters are
local to the block. Most people agree that this is a much better
definition of blocks than the original one.  Nevertheless, people
planning to use Smalltalk/V should realise that it has a different
semantics for blocks.

This difference can lead to some amusing problems.  For example, here
is some code written by someone who had obviously learned Scheme.

| anotherArray aBlockArray |

aBlockArray := Array new: 4.
anotherArray := #(1 2 4 8).

1 to: 4 do: [ :anIndex |
 aBlockArray at: anIndex put: [ (anotherArray at: anIndex) * 2 ]].


The programmer expected that each block would be stored in the array
along with its own value of anIndex.  If anIndex were just a local
variable of the method then this will not work.  It assumes that 
each execution of the block gets its own version of anIndex, and
Smalltalk/V and old Smalltalk-80 actually make each execution share
the same version.

So, if you are using Smalltalk/V then be careful not to reuse the
names of arguments of blocks unless you know that the blocks are
not going to have their lives overlap.  Thus,

  aCollect do: [:i | ...].
  bCollect do: [:i | ...].

is probably OK because do: does not store its argument, so the
blocks will be garbage by the time the method is finished.
However, if the first block were stored in a variable somewhere
and evaluated during the execution of the second block then
problems would probably occur.

Bug 10: Smalltalk/V class library
Thomas Muhr makes these comments about bugs in the Smalltalk/V
class library that you should know if you want to keep your
programs fast and correct.

2. Never use symbols to label objects if you are dealing with many
objects. This will slow down your system to an almost dead halt. Use
strings instead.
3. Never use Sets when you can otherwise assure the uniqueness. Look
at the implementation of "add:" for Sets and you'll know what I mean:
on every "add:" the new element is compared to all others resulting
into a nonlinear time for adding to Sets.
4. Do not think that if you "collect:" something from a
SortedCollection, that your result will be sorted as the origin,
unless you use the default sortBlock. This is one of the bugs provided
by the language vendor



Many thanks to the many people who contributed bugs or solutions to bugs
to the list.  These include

 muhr@opal.cs.tu-berlin.de (Thomas Muhr)
 steinman@is.morgan.com (Jan Steinman)
 knight@mrco.carleton.ca (Alan Knight)
 mario@cs.man.ac.uk (Mario Wolczko)
 peterg@netcom.com (Peter Goodall)
 Aad Nales <nales@cs.few.eur.nl>
 scrl@otter.hpl.hp.com (Simon Lewis)
 msmith@volcano.ma30.bull.com (Mike Smith)
 dai@mrco.carleton.ca (Naci Dai)
 dcr0@speedy.enet.dec.com (Dave Robbins)
 randy@tigercat.den.mmc.com (Randy Stafford)
 Hubert.Baumeister@mpi-sb.mpg.de (Hubert Baumeister)
 eliot@dcs.qmw.ac.uk (Eliot Miranda)
 dmm@aristotle.ils.nwu.edu (donald)
 amir@is.morgan.com (Amir Bakhtiar)
 Kurt Piersol <Piersol@Apple.com>
 sullivan@ticipa.ti.com (Michael Sullivan)
 terry@zoe.network23.com (Terry)
 brent@uwovax.uwo.ca (Brent Sterner)
 frerk@informatik.uni-kl.de
 nicted@toz.buffalo.ny.us (Nicole Tedesco)
 riks@ogicse.ogi.edu (Rik Fischer Smoody)
 marten@feki.toppoint.de (Marten Feldtmann) 

Comments and additions are welcome.  Please post to comp.lang.smalltalk
or e-mail to johnson@cs.uiuc.edu.

From scrl Thu Aug 13 08:15:11 1992
Relay-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
From: scrl@otter.hpl.hp.com (Simon Lewis)
Date: Thu, 13 Aug 1992 07:15:11 GMT
Date-Received: Thu, 13 Aug 1992 07:15:11 GMT
Subject: Re: catalog of classic bugs
Message-ID: <2610027@otter.hpl.hp.com>
Organization: Hewlett-Packard Laboratories, Bristol, UK.
Path: otter!scrl
Newsgroups: comp.lang.smalltalk
Posting-Version: version Notes 2.8  87/9/11; site otter.hpl.hp.com
References: <1992Aug12.222916.18784@m.cs.uiuc.edu>

In comp.lang.smalltalk, johnson@m.cs.uiuc.edu (Ralph Johnson) writes:

> Classic Smalltalk Bugs

> Neither Smalltalk-80 nor Smalltalk-V return to the sender when a
> new window is opened in a standard fashion.

Not any more.  In Objectworks\Smalltalk release 4.1 (what you're calling
Smalltalk-80), open now does return, so...

> aScheduledWindow1 open.
> aScheduledWindow2 open
 
...now works as you might expect.

Simon.


--
===============================================================================
  Tom Gardner                 Hewlett Packard Laboratories, Filton Rd, 
  tgg@hplb.hpl.hp.com	      Stoke Gifford, Bristol, Avon, BS12 6QZ, ENGLAND.
  Fax: +44 1179 228920        Tel: +44 1179 799910 ext. 28192
            Too many Heritage Centres make you go blind.
===============================================================================

