[comp.lang.icon] frequently-asked questions

goer@SOPHIST.UCHICAGO.EDU (Richard qua goer.) (05/05/90)

I wonder if we might do well to accumulate a "frequently-asked
questions" list, to make things easier for people starting to learn
Icon (presumably a large portion of the Icon-group's membership).
I'll just post an entry, and if anyone wants to add to it, I'll simply
append their additions to my list.  I find that people starting to
learn Icon tend to make similar mistakes, and I end up answering the
same questions over and over.  Not that answering them is difficult or
tedious.  I just hate to see people have to find out, after hours of
debugging, that they have run into a problem that might easily have
been avoided through the use of such a list.  Take five minutes out,
and add to the list!


Problem:  Why do I get unexpected results when I initialize a table
    like this:  tbl := table([])?  What I want is to make all the keys
    in tbl have empty lists as their initial values.

Answer:  Tables, sets, and lists in Icon are handled differently than,
    say, strings, csets, and integers.  When you "dereference" a
    variable whose value is a string, cset, or integer, you get a
    string, cset or integer (nothing complicated here).  In other
    words, if you say

	i := 1
	j := i

    j will end up with a value of 1.  When the i is dereferenced, it
    produces the integer 1, and *that* is what gets assigned to j.
    With structures like lists, however, dereferencing them produces a
    "pointer" to the structure in question.  It does not produce a
    copy of the structure (for that, you have to use copy()).  This is
    why, if you say

	l1 := ["hello"]
	l2 := ["hello"]
	if l1 === l2
	then write("the same")
	else write("different")

    you will see "different" written to the screen.  In effect, you
    have created two lists which, although they bear a structural
    similarity, reside in different places in memory, and therefore
    are *different lists*.

    What is the point here?  The point is that, if you say

	tbl := table([])

    you are actually setting up tbl so that each time you insert a new
    key, it will automatically be assigned the value produced by [].
    If you had said "tbl := table(1)" this would be fine.  "1"
    produces the integer 1.  Remember, however, that [] creates a
    specific structure (an empty list) and produces a pointer to that
    list.  What you'll end up with, therefore, is a table with keys
    whose values are all pointers to the one list structure!  What
    this does to your program is make it so that if you make any
    insertions into any key's value (e.g.  tbl[key1] |||:= ["hello"]
    or insert(tbl[key1],"hello")), you will find, suddenly, that *all*
    of the keys' values have been modified.

    To make the long story short, you have to initialize the table
    using &null,

	tbl := table()    # the same as tbl := table(&null)

    and then, each time you add a key, do this:

	/tbl[key] := []   # or /tbl[key] := list()

    The above expression first checks to see whether key has been
    inserted into tbl yet, and if not, makes its value the empty list
    (the forward slash tests for the null value, and so if key is
    already present in the table, and has been assigned a value,
    tbl[key] := [] will not take place).  You can then go about
    inserting things into this list as expected.