rick@tetrauk.UUCP (Rick Jones) (11/17/90)
Following my recent posting about variable argument problems, and Bertrand
Meyer's response concerning TUPLEs to be introduced in version 3, I decided to
reconsider the problem (I can't defer the whole problem until V3 is released!).
I also looked again at some prototype class code I was sent some time ago by
ISE which tried to address the problem of formatted print. The result is a
class VLIST which allows variable size lists to be effectively coded "in-line".
The code for VLIST is given below, its usage is best explained by first giving
an example:
class EXP -- experiments on building string lists
inherit
STD_FILES
feature
Create is
local
vl: VLIST[STRING] ; -- a variable list
do
vl.Create ;
lprint (vl -- VLIST is filled as part of the call
.v ("This") -- to lprint
.v ("is")
.v ("a")
.v ("sentence")
) ;
end ;
lprint (l: LIST[STRING]) is
-- prints all the strings in the list
do
from
l.start
until
l.offright
loop
putstring (l.item) ; putchar (' ') ;
l.forth ;
end ;
new_line ;
end ;
end
When run, this will print "This is a sentence".
VLIST inherits from LINKED_LIST and exports a single feature "v" whose argument
is an object of the type which it contains. The return value is the object
itself. This allows indefinite cascading of calls to feature "v".
This is what is shown in the Create routine above, and since the return value
of the complete chain of calls is the list itself, this can be passed directly
as a LIST argument to the required routine. The cascading calls are coded on
multiple lines, since this separates the items clearly. A more conventional
format would be:
lprint (vl.v("This").v("is").v("a").v("sentence")) ;
The VLIST class is as follows:
----------------------------------------------------------------------
class VLIST [T] -- variable-argument list
export
v
inherit
LINKED_LIST [T]
feature
v (t: T): like Current is
require
new: offright ;
do
put_left (t) ;
Result := Current ;
ensure
inserted: t = last ;
grown: count = old count + 1 ;
end ;
end
----------------------------------------------------------------------
A similar class can be based on FIXED_LIST, which has the advantage that the
resulting object conforms to both LIST and ARRAY:
----------------------------------------------------------------------
class VALIST [T] -- variable-argument list using FIXED_LIST
export
v
inherit
FIXED_LIST [T]
rename Create as f_create
feature
Create is
do
f_create (0) ;
end ;
v (t: T): like Current is
local
up: INTEGER ;
do
-- must cater for an empty list when upper < lower
-- (this only arises because an empty array is always
-- initialised with lower=0 and upper=-1. If it were done
-- so that lower=minindex and upper=lower-1 it would be
-- more consistent and avoid this extra check)
--
if upper > 0 then up := upper end ;
-- else default value = 0 ;
force (t, up + 1) ;
Result := Current ;
ensure
inserted: t = last ;
grown: count = old count + 1 ;
end ;
end
----------------------------------------------------------------------
Although this breaks a rule of the Eiffel philosophy - "A function which
returns a value should not have side effects", it clearly provides extremely
useful functionality. I hope this may prove useful to other Eiffel users who
have experienced similar problems.
Since the resulting C code is a nest of function calls, too many arguments can
cause compiler overflow. My compiler (SCO Unix V/386, which is more limited
than many) can manage up to 14 string arguments before it gives up.
To change the subject, I recently posted an article on exception handling, with
the code of a class which allowed an object to be passed from an exception to
the rescue clause which traps it. However, my system's comms link was in a
mess that night and several things disappeared into a black hole! Could
someone email me if they have seen this article? If nobody did I shall re-post
it. Thanks.
--
Rick Jones
Tetra Ltd. Maidenhead, Berks, UK
rick@tetrauk.uucp Absence of .signature is not .signature of absence