Programming Corner from Icon Newsletter 32


January 15, 1990 ; Version 7

Cset Operations

Dave Cargo poses the following problem:
I wanted to know if the intersection of two csets is empty and wrote
if c1 ** c2 == ' ' then 
but then I realized I wasn't sure if == was the right operator to use.

The best operation for comparing two csets is c1 === c2

This operation compares the bit vectors used to represent the characters in csets; it is fast and direct. The operation c1 == c2 first converts c1 and c2 to strings and then compares the resulting strings. The conversion is time-consuming and unnecessary.

To determine if the intersection of two csets is empty, another formulation is
if *(c1 ** c2) = 0 then 

Black Holes

In almost every programming language, it is possible (even easy) to get into an endless loop. While no one would intentionally write something like
while 1
in a real program, its equivalent happens to us all from time to time. Such problems are easy to understand if not always easy to find.

Icon with its generators has the potential for a somewhat subtler kind of problem -- endless generation within the expression-evaluation mechanism. Consider, for example, the following suggested method for writing all the values in the list L:
every write(L[seq()])
(The function seq() generates an endless sequence of integers, 1, 2, 3, ... .)

The problem here is that when the end of the list is reached, the every expression does not stop even though the list reference fails; seq() continues to generate, L[seq()] continues to fail, and so on.

Fortunately, such evaluation "black holes" rarely occur in Icon programs. If they were common, Icon would be a useless programming language. Incidentally, it's this problem that motivated the special termination condition for |expr, which stops if expr ever fails to produce a single result. Otherwise, evaluation of an expression such as |read() would never stop.

Records

Steve Wampler writes:
I just discovered that
record t(a, b, c)

procedure main(args)
   tmp := t()
   every !tmp := get(args)
   every write(!tmp)
end
works just fine. How nice! I just figured out a use for that.

Yes, even though records usually are accessed by their field names, their components can be subscripted, as in tmp[1], and generated as you've observed. In fact the operations X[i], !X, ?X, and *X apply to all structure types with the exception of X[i], which does not apply to sets, since there is no concept of order for the members of a set (although we could invent one).

Idiomatic Icon

Anthony Hewitt wrote this clever little program to filter out adjacent duplicate lines in a file:
procedure main()
   write(s := !&input)
   every write(s ~==:= !&input)
end

Trivia Corner

What's the shortest complete Icon program that will compile and execute without error?

Confusing hint: It's not
procedure main()
end 

Icon home page