Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Stupid question (creating a sequence of *different* objects)

14 views
Skip to first unread message

Marco Antoniotti

unread,
Jul 16, 2001, 12:17:30 PM7/16/01
to

Hi

I know how to do it. I a just wondering what people feel would be a
good interface (in the spirit of the PARTITION/SPLIT-SEQUENCE and
EXTREMIZE debate).

I often find myself doing things like

(loop for i from 0 to N collect (make-something))

just because

(make-list N :initial-element (make-something))

fills the list with EQ elements. (The same applies to MAKE-ARRAY, of
course).

I was thinking to write something along the lines of

(defun make-list-collecting (n &key
(element-constructor (lambda () nil)))
(loop for i from 0 below N collect (funcall f)))

(of course this could - and maybe should - be generalized to various
sequences and arrays).

What does the "vox populi" say?

Cheers

--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
719 Broadway 12th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.

Barry Margolin

unread,
Jul 16, 2001, 2:22:01 PM7/16/01
to
In article <y6c66cs...@octagon.mrl.nyu.edu>,

Marco Antoniotti <mar...@cs.nyu.edu> wrote:
>I know how to do it. I a just wondering what people feel would be a
>good interface (in the spirit of the PARTITION/SPLIT-SEQUENCE and
>EXTREMIZE debate).
>
>I often find myself doing things like
>
> (loop for i from 0 to N collect (make-something))
>
>just because
>
> (make-list N :initial-element (make-something))
>
>fills the list with EQ elements. (The same applies to MAKE-ARRAY, of
>course).

I wonder why you do this so much? It seems to me that most of the time
when I've wanted to initialize a sequence by doing a computation, the
indices frequently apply. E.g. something like:

(loop for i below n collect (* i 2))

If they're not a function of the index, they're usually a function of
something that will be discovered later, so I let the elements default to
NIL (or unspecified, in the case of an array) and fill them in later.

--
Barry Margolin, bar...@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

Marco Antoniotti

unread,
Jul 16, 2001, 3:41:00 PM7/16/01
to

Barry Margolin <bar...@genuity.net> writes:

> In article <y6c66cs...@octagon.mrl.nyu.edu>,
> Marco Antoniotti <mar...@cs.nyu.edu> wrote:
> >I know how to do it. I a just wondering what people feel would be a
> >good interface (in the spirit of the PARTITION/SPLIT-SEQUENCE and
> >EXTREMIZE debate).
> >
> >I often find myself doing things like
> >
> > (loop for i from 0 to N collect (make-something))
> >
> >just because
> >
> > (make-list N :initial-element (make-something))
> >
> >fills the list with EQ elements. (The same applies to MAKE-ARRAY, of
> >course).
>
> I wonder why you do this so much? It seems to me that most of the time
> when I've wanted to initialize a sequence by doing a computation, the
> indices frequently apply. E.g. something like:
>
> (loop for i below n collect (* i 2))
>
> If they're not a function of the index, they're usually a function of
> something that will be discovered later, so I let the elements default to
> NIL (or unspecified, in the case of an array) and fill them in later.

You are forgetting copier functions. Sometimes I find it better to
allocate a vector of (different) objects and then modify them
appropriately.

Moreover, if you initialize a vector with NIL elements, you will have
to declare it as

(vector (or null <your-type>))

I find this cluttering. If possible I'd like to always declare

(vector <your-type>)

Of course it isn't something I need to die over. I can always trade
off.

Barry Margolin

unread,
Jul 16, 2001, 4:17:18 PM7/16/01
to
In article <y6c3d7w...@octagon.mrl.nyu.edu>,

Marco Antoniotti <mar...@cs.nyu.edu> wrote:
>Moreover, if you initialize a vector with NIL elements, you will have
>to declare it as
>
> (vector (or null <your-type>))

That's why I said to let them default, rather than initializing them
explicitly to anything.

But I admit that I've never bothered with such declarations in the first
place. The only array element type declarations that I've ever found
useful were the ones that affected the array representation; typically
these are element types like FIXNUM, SHORT-FLOAT, BIT, and CHARACTER.

Christophe Rhodes

unread,
Jul 17, 2001, 2:58:10 AM7/17/01
to
Marco Antoniotti <mar...@cs.nyu.edu> writes:

> just because
>
> (make-list N :initial-element (make-something))
>
> fills the list with EQ elements. (The same applies to MAKE-ARRAY, of
> course).
>
> I was thinking to write something along the lines of
>
> (defun make-list-collecting (n &key
> (element-constructor (lambda () nil)))
> (loop for i from 0 below N collect (funcall f)))
>
> (of course this could - and maybe should - be generalized to various
> sequences and arrays).
>
> What does the "vox populi" say?

This came up just the other day on IRC; we came up with the following
idiom:

(let ((a (map-into (make-list 10) #'make-foo)))
...)

I don't know that there's any great advantage in standardizing a
wrapper around this, though I'm obviously not averse to it either if
people wish it.

Cheers,

Christophe
--
Jesus College, Cambridge, CB5 8BL +44 1223 510 299
http://www-jcsu.jesus.cam.ac.uk/~csr21/ (defun pling-dollar
(str schar arg) (first (last +))) (make-dispatch-macro-character #\! t)
(set-dispatch-macro-character #\! #\$ #'pling-dollar)

Kalle Olavi Niemitalo

unread,
Jul 17, 2001, 7:12:56 AM7/17/01
to
Barry Margolin <bar...@genuity.net> writes:

> In article <y6c3d7w...@octagon.mrl.nyu.edu>,
> Marco Antoniotti <mar...@cs.nyu.edu> wrote:
> >Moreover, if you initialize a vector with NIL elements, you will have
> >to declare it as
> >
> > (vector (or null <your-type>))
>
> That's why I said to let them default, rather than initializing them
> explicitly to anything.

Thanks. I learned something. :-)
Here's how it happened.

First, I was wondering if there is a difference between initializing
array elements and letting them default: in (let ((x nil) y)), there
is no such difference. However, CLHS says that if I make an array
with (make-array 5 :element-type <my-type>), then I'm not allowed to
read elements I haven't initialized; thus MAKE-ARRAY doesn't have to
initialize the array. This is surprising, but I suppose it saves time
with large arrays.

(misguidedly

Is the resulting array then of type (vector <my-type>)? I guess it
is, except some elements haven't been initialized and must not be
read.

Am I allowed to (check-type <my-array> '(vector <my-type>))? If
that has to read and check every element, including the
uninitialized ones, then it is not allowed.

What if I assign the array to a variable whose type I've declared as
(vector <my-type>), and the Lisp chooses to check the type of the
array before letting the assignment succeed? That would be
equivalent to the forbidden CHECK-TYPE. Can Lisp implementations
then run automatic checks of that kind at all?)

However: CHECK-TYPE need not scan through the array, because it
doesn't check the actual elements, but rather what kind of elements
the array *could* contain, and that cannot change after the array has
been created! Thus all the problems disappear.

I still find it odd that the parameters of type specifiers VECTOR and
ARRAY work so differently from CONS, where the actual values in the
car and the cdr are checked. Does this difference have a name? All
these types are listed as "Compound Type Specifier Kind: Specializing."

Raymond Toy

unread,
Jul 17, 2001, 8:43:00 AM7/17/01
to
>>>>> "Kalle" == Kalle Olavi Niemitalo <k...@iki.fi> writes:

Kalle> Barry Margolin <bar...@genuity.net> writes:
>> In article <y6c3d7w...@octagon.mrl.nyu.edu>,
>> Marco Antoniotti <mar...@cs.nyu.edu> wrote:
>> >Moreover, if you initialize a vector with NIL elements, you will have
>> >to declare it as
>> >
>> > (vector (or null <your-type>))
>>
>> That's why I said to let them default, rather than initializing them
>> explicitly to anything.

Kalle> Thanks. I learned something. :-)
Kalle> Here's how it happened.

Kalle> First, I was wondering if there is a difference between initializing
Kalle> array elements and letting them default: in (let ((x nil) y)), there
Kalle> is no such difference. However, CLHS says that if I make an array
Kalle> with (make-array 5 :element-type <my-type>), then I'm not allowed to
Kalle> read elements I haven't initialized; thus MAKE-ARRAY doesn't have to
Kalle> initialize the array. This is surprising, but I suppose it saves time
Kalle> with large arrays.

But practically speaking, it has to be initialized to something. If
(upgraded-array-element-type <my-type>) => T, then the elements have
to be initialized to something useful otherwise the potentially random
elements would confuse the garbage collector.

Ray


Kalle Olavi Niemitalo

unread,
Jul 17, 2001, 9:09:13 AM7/17/01
to
Raymond Toy <t...@rtp.ericsson.se> writes:

> But practically speaking, it has to be initialized to something. If
> (upgraded-array-element-type <my-type>) => T, then the elements have
> to be initialized to something useful otherwise the potentially random
> elements would confuse the garbage collector.

The implementation could put a magic value in the first element, and
then the second element would say how many uninitialized elements
follow. This would satisfy the GC... but slow down SETF of AREF.

If Lisp implementations always initialize arrays whose upgraded
element type is T, can I specify an initial value for free?

Kent M Pitman

unread,
Jul 17, 2001, 9:49:26 AM7/17/01
to
Kalle Olavi Niemitalo <k...@iki.fi> writes:

No, because it may be that the host operating system offers you a way to
get a block of data initialized to "something known to the vendor" but not
"something agreed upon community-wide across vendors of Lisp". The vendor
is free to implement their GC so as to take advantage of the "something
known" even if the something known is something conceptually "dumb" as long
as it's "gc-recognizable". For you to be able to substitute something might
slow things down by requiring a user-level iteration across something the
system was already going to have initialized.

This is, in effect, the price of "portabilty" in Lisp design. People talk
about how C is touted as portable, but in practice Lisp is believed by many
Lisp programmers to port better. I think the reason is situations like
this where C would happily offer you a per-vendor spec of what the memory
you grab will be initialized to and let you call it, even though it might
vary by vendor. So when you port, you find places like this getting all kinds
of little conditionals as we find that someone else initialized something
differently so the setup of this page has to be different. There might be
a place where Lisp is less efficient than C as a result, but at least Lisp
will port on this point without you having to re-examine how memory is
initialized. Bugs introduced by variances like this are subtle and can take
forever to track down. Lisp spares you that as well.

Revel in it. Don't try to fight it... It's doing you a favor. Let it.

Duane Rettig

unread,
Jul 17, 2001, 10:57:30 AM7/17/01
to
Kalle Olavi Niemitalo <k...@iki.fi> writes:

> Raymond Toy <t...@rtp.ericsson.se> writes:
>
> > But practically speaking, it has to be initialized to something. If
> > (upgraded-array-element-type <my-type>) => T, then the elements have
> > to be initialized to something useful otherwise the potentially random
> > elements would confuse the garbage collector.
>
> The implementation could put a magic value in the first element, and
> then the second element would say how many uninitialized elements
> follow. This would satisfy the GC... but slow down SETF of AREF.

I can't see any serious implementation doing any such thing. As you
say, it would seriously slow down _every_ setf of aref even after
such an array is all "fixed up", because the magic value would always
have to be checked for.

> If Lisp implementations always initialize arrays whose upgraded
> element type is T, can I specify an initial value for free?

In Allegro CL, at least, the answer is "yes" for heap-allocated arrays,
and "no" for stack-allocated arrays. Stack-allocated arrays, even of type
T, are allocated without initialization when no :initial-element argument
is given, so they're fast. However, it is up to you to initialize them
before you use them.

--
Duane Rettig Franz Inc. http://www.franz.com/ (www)
1995 University Ave Suite 275 Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253 du...@Franz.COM (internet)

Erik Naggum

unread,
Jul 17, 2001, 12:15:51 PM7/17/01
to
* Kalle Olavi Niemitalo <k...@iki.fi>

> First, I was wondering if there is a difference between initializing
> array elements and letting them default: in (let ((x nil) y)), there is
> no such difference.

There is, but it does not matter, because the only rational thing to do
is to initialize the variable to nil, and that is also specified. If,
however, you declare a variable's type such that nil is not a possible
value, you must, because the language does not _strongly_ support type
declarations (such as by requiring that type violations be signaled as
compile-time errors where possible to determine and warning about the
inability to determine them where not), initialize the variable properly.

For instance, given the following function definition, do you expect (foo
0) to return nil or 0 or something else or do you expect it to signal an
error?

(defun foo (bar &aux zot)
(declare (optimize (speed 3) (safety 0) (debug 0) (space 3))
(type fixnum bar zot))
(+ bar zot))

Please note that this is _not_ safe code (in as many meanings as you can
find of that term :), and that by asking for maximum performance and no
safety, _I_ expect this to return whatever machine representation adding
the machine word that represents the fixnum 0 to the machine word that
represents nil, which in some cases might well return nil, unless the
hardware has type bit checks, like the good old SPARC does.

In my opinion, it is important that variables are initialized before use,
and I think that it should be an error if a variable can be determined to
be referenced for its value before it is initialized. If it cannot be
determined that it has been initialized before any given use, that should
produce be a warning.

> However, CLHS says that if I make an array with (make-array 5
> :element-type <my-type>), then I'm not allowed to read elements I haven't
> initialized; thus MAKE-ARRAY doesn't have to initialize the array. This
> is surprising, but I suppose it saves time with large arrays.

Huh? You asked it not to be initialized. Why did you expect it to be?
If you want something to be initialized, ask for it. I routinely ask
make-array to initialize things for me unless the first thing I will do
is to initialize it myself, in which case it would be time worth saving
to avoid the double initialization.

> (misguidedly
>
> Is the resulting array then of type (vector <my-type>)? I guess it
> is, except some elements haven't been initialized and must not be
> read.

The vector and its elements have _separate_ types. Type theory and type
practice are not quite compatible in many cases, because so much type
theory is wrong. If type theory had dealt with typed data and not typed
variables, so much more progress would have occured in this area. What
theoretical foundation we have today is largely useless in a world where
there is a universal supertype for all types, since they all assume a
disjoint type space. I have never figured out why this is a smart thing
to assume in a theoretical framework -- it seems downright stupid to me,
and makes "object-oriented" programming so much harder to fit into it and
describe. (I fault "modern" type theory for most of the disasters in
"modern" programming language design. All of the wonderful things they
want (such as static type checking and program validation) are just as
hard and no harder to do in a dynamically typed than a statically typed
value universe, and they prove themselves useless in a world where all
"object-oriented" objects descend from some super-Object, too.) It also
seems that your confusions stem from a type theoretical background that
has failed to describe the real world and fit a _too_ simple mathematical
model of whatever they thought they saw.

> Am I allowed to (check-type <my-array> '(vector <my-type>))? If that
> has to read and check every element, including the uninitialized ones,
> then it is not allowed.

When you query the type of the vector, you only query the type of the
container. When you query the type of each element, you query the type
of the contained. These are very different operations and concepts.

> However: CHECK-TYPE need not scan through the array, because it
> doesn't check the actual elements, but rather what kind of elements
> the array *could* contain, and that cannot change after the array has
> been created! Thus all the problems disappear.

Not actually true, but close enough. See upgraded-array-element-type.

> I still find it odd that the parameters of type specifiers VECTOR and
> ARRAY work so differently from CONS, where the actual values in the
> car and the cdr are checked. Does this difference have a name? All
> these types are listed as "Compound Type Specifier Kind: Specializing."

cons is a special case, just like complex. E.g., you can use the form
(typep (list 1 2 3) '(cons integer (cons integer (cons integer)))) to
test a list, but this does not mean that you will succeed with the more
obvious (typep (list 1 2 3) '(list integer)). Maybe it should, though.

#:Erik
--
Travel is a meat thing.

Kalle Olavi Niemitalo

unread,
Jul 17, 2001, 1:07:49 PM7/17/01
to
Erik Naggum <er...@naggum.net> writes:

> For instance, given the following function definition, do you expect (foo
> 0) to return nil or 0 or something else or do you expect it to signal an
> error?
>
> (defun foo (bar &aux zot)
> (declare (optimize (speed 3) (safety 0) (debug 0) (space 3))
> (type fixnum bar zot))
> (+ bar zot))

I expect the compiler to signal a warning and the function to signal
an error. The addition can be optimized out.

> Huh? You asked it not to be initialized. Why did you expect it to be?

Because LET initializes things without being asked to, and I
remembered the need to make the default NIL fit the declared type of
the variable, and imagined I'd have to do something similar with the
default contents of arrays too (as if there were any).

> It also seems that your confusions stem from a type theoretical
> background that has failed to describe the real world and fit a
> _too_ simple mathematical model of whatever they thought they saw.

I haven't studied type theory. I know C and C++ though, and there
you cannot implicitly convert T** to const T**. This seems related
to Common Lisp's disjoint (array X) and (array Y) types (assuming
X and Y are upgraded types).

CL's OR and SATISFIES type specifiers were quite an astonishment when
I first read about them, kind of like Scheme's continuations.

> cons is a special case, just like complex.

Are there any others like them?

What if I make an array with element-type (cons symbol fixnum); is the
Lisp required to upgrade that to at least CONS, or can it preserve the
exact type and let me store only conses pointing to symbols and
fixnums? What happens if I mutate the cons after storing it in the
array -- is that OK as long as I don't use that element of the array?
With subtypes of COMPLEX, there are no such problems, I think.

Erik Naggum

unread,
Jul 17, 2001, 4:47:24 PM7/17/01
to
* Kalle Olavi Niemitalo <k...@iki.fi>
> Because LET initializes things without being asked to, [...]

No, it does not. This is a confusion in your own mind. Only you can fix
it. Please do not state your conclusions as if they were _observations_
from a specification. Binding and initialization are conceptually so far
apart that I have a hard time figuring out how to respond to you, but you
have gone astray somewhere, thinking they are the same. Please backtrack
to that point and take the right path. I fear that several other weird
conclusions come from this strange mistake. Perhaps you believe that a
variable is some kind of data storage that is initialized to something in
a let binding, just like a cons cell is a kind of data storage that is
explicitly initialized to hold some data when you call the constructor
cons. If you think at this C level, maybe it works for you to consider a
binding as affecting a pointer in a variable and initialization as
affecting the pointed-to object. But please, do not think at the C level
-- the more you succeed in doing so, the harder it will be to get back to
the truth when you realize that you are stuck. It _will_ be painful.

> I haven't studied type theory.

Good for you, but you have absorbed a great deal of trash from it, anyway.
Sometimes, one has to discard what one think one knows in order to learn
what is right in both the old and the new context.

> I know C and C++ though, and there you cannot implicitly convert T** to
> const T**. This seems related to Common Lisp's disjoint (array X) and
> (array Y) types (assuming X and Y are upgraded types).

No, not at all related. (array (signed-byte 32)) and (array single-float)
are disjoint for _exactly_ the same reason that int[] and float[] are.

> CL's OR and SATISFIES type specifiers were quite an astonishment when I
> first read about them, kind of like Scheme's continuations.

Types in Common Lisp are named partitions of a mathematical value space.
Types in C are hardware implementations of partitions of the hardware
value space, plus a little compile-time noise thrown in for good measure.
The C type concept is easy to understand from a Common Lisp point of
view, but coming from C, you have to realize that your "type" concept is
really a very peculiar special case of a much broader, general concept.
This is why C and the like are horrible languages to expose beginners to.

> Are there any others like them?

Not that I can recall, but you should not worry about these things now.

> What if I make an array with element-type (cons symbol fixnum); is the
> Lisp required to upgrade that to at least CONS, or can it preserve the
> exact type and let me store only conses pointing to symbols and
> fixnums? What happens if I mutate the cons after storing it in the
> array -- is that OK as long as I don't use that element of the array?
> With subtypes of COMPLEX, there are no such problems, I think.

The specialized array is a concession to hardware. The type is upgraded
to the most fitting hardware-supported type available. E.g., you could
ask for an array of 32-bit integers, or floating point numbers of single
or double precision (but not both). If you asked for anything that would
store any type of Lisp object, as opposed to _some_ types of fast and
hardware-supported objects, your type would be upgraded to type t with no
questions asked.

My advice to you at this stage in our Lisp experience is to drop _all_ of
your concerns about types. Do not think about it. Force yourself _not_
to think about types. Think about _values_.

Kaz Kylheku

unread,
Jul 17, 2001, 5:05:48 PM7/17/01
to
In article <32043916...@naggum.net>, Erik Naggum wrote:
>* Kalle Olavi Niemitalo <k...@iki.fi>
>> Because LET initializes things without being asked to, [...]
>
> No, it does not. This is a confusion in your own mind. Only you can fix
> it. Please do not state your conclusions as if they were _observations_
> from a specification. Binding and initialization are conceptually so far
> apart that I have a hard time figuring out how to respond to you, but you
> have gone astray somewhere, thinking they are the same. Please backtrack
> to that point and take the right path. I fear that several other weird
> conclusions come from this strange mistake. Perhaps you believe that a
> variable is some kind of data storage that is initialized to something in
> a let binding, just like a cons cell is a kind of data storage that is
> explicitly initialized to hold some data when you call the constructor
> cons. If you think at this C level, maybe it works for you to consider a

One who thinks in C should have no problem seeing the difference
between the association of a name with location and the storage of an
initial value in that location. Binding and initialization are also far
apart in C. Fo far apart that one is often done without the other,
without any diagnosis. :)

>> I know C and C++ though, and there you cannot implicitly convert T** to
>> const T**. This seems related to Common Lisp's disjoint (array X) and
>> (array Y) types (assuming X and Y are upgraded types).
>
> No, not at all related. (array (signed-byte 32)) and (array single-float)
> are disjoint for _exactly_ the same reason that int[] and float[] are.

And T** and const T** are also disjoint for the same reason.
T* and const T* are distinct, incompatible types. So types derived
from them are also distinct, incompatible types. Think of T* as X
and const T* as Y.

That you can assign T* to const T* is a special exception, which
recognizes a special closeness between two incompatible types. That
exception is not inherited by derived types.

A similar relationship is recognized between the floating and
integral types; conversions are allowed which do not extend
to derived pointer types.

Kaz Kylheku

unread,
Jul 17, 2001, 5:18:18 PM7/17/01
to
In article <MM157.2316$0C.4...@news1.rdc1.bc.home.com>, Kaz Kylheku wrote:
>initial value in that location. Binding and initialization are also far
>apart in C. Fo far apart that one is often done without the other,
>without any diagnosis. :)

Of course, I meant ``So far apart'', but I was chewing on some food.

Barry Margolin

unread,
Jul 17, 2001, 5:47:01 PM7/17/01
to
In article <32043916...@naggum.net>, Erik Naggum <er...@naggum.net> wrote:
>* Kalle Olavi Niemitalo <k...@iki.fi>
>> Because LET initializes things without being asked to, [...]
>
> No, it does not. This is a confusion in your own mind. Only you can fix
> it. Please do not state your conclusions as if they were _observations_
> from a specification. Binding and initialization are conceptually so far
> apart that I have a hard time figuring out how to respond to you, but you
> have gone astray somewhere, thinking they are the same.

CL doesn't provide any way to bind a lexical variable without initializing
it. So even though they're conceptually far apart, it's hard to think
about binding without initialization also coming to mind. Perhaps instead
of "without being asked to", a better phrasing would be "even if it's not
desired." Leaving out the initialization form looks intuitively like a
request not to initialize (if there were a way to do it, this would
probably be the syntax, just as omitting :INITIAL-xxx is for arrays). The
typical style of use is to leave out the initializer when you don't care
(you plan on SETQing before accessing it) and explicitly initialize to NIL
when this initial value is important. In this respect, letting it default
is conceptually similar to "without being asked to."

This is the first time I've dared respond to a post by Erik in several
months (actually, it's one of the first ones I've seen from him in a while,
but I've not been reading any of the long threads like "Engineering envy").
I don't think anything in the above paragraph can be interpreted as
hateful, but I'm never sure how he'll take my messages.

Kent M Pitman

unread,
Jul 17, 2001, 7:18:31 PM7/17/01
to
Barry Margolin <bar...@genuity.net> writes:

> In article <32043916...@naggum.net>, Erik Naggum <er...@naggum.net> wrote:
> >* Kalle Olavi Niemitalo <k...@iki.fi>
> >> Because LET initializes things without being asked to, [...]
> >
> > No, it does not. This is a confusion in your own mind. Only you can fix
> > it. Please do not state your conclusions as if they were _observations_
> > from a specification. Binding and initialization are conceptually so far
> > apart that I have a hard time figuring out how to respond to you, but you
> > have gone astray somewhere, thinking they are the same.
>
> CL doesn't provide any way to bind a lexical variable without initializing
> it. So even though they're conceptually far apart, it's hard to think
> about binding without initialization also coming to mind. Perhaps instead
> of "without being asked to", a better phrasing would be "even if it's not
> desired." Leaving out the initialization form looks intuitively like a
> request not to initialize (if there were a way to do it, this would
> probably be the syntax, just as omitting :INITIAL-xxx is for arrays). The
> typical style of use is to leave out the initializer when you don't care
> (you plan on SETQing before accessing it) and explicitly initialize to NIL
> when this initial value is important. In this respect, letting it default
> is conceptually similar to "without being asked to."

I concur with this.

However, [not speaking to Barry now but to the original poster],
it's so rare that an implementation actually specializes storage
associated with a LET to make it "smaller" than is needed to represent a full
pointer, that I think another way to look at it is to say that it really just
doesn't, in practice, cost anything to say the variable initially holds a
value of a specialized type. And you can always use either LOCALLY or THE
or yet another let binding to arrange for the remaining uses of the variable
to be properly type-constrained even if the point-of-binding is not type
constrained. So, for example, if you want
(let (x)
(blah)
(setq x (compute-init-array-initial-value))
... uses of array x ...)
you can do
(let (x)
(blah)
(setq x (compute-init-array-initial-value))
(locally (declare (type array x))
...))
etc.

> This is the first time I've dared respond to a post by Erik in several
> months (actually, it's one of the first ones I've seen from him in a while,
> but I've not been reading any of the long threads like "Engineering envy").
> I don't think anything in the above paragraph can be interpreted as
> hateful, but I'm never sure how he'll take my messages.

FWIW, I concur with this, too, actually.

Erik Naggum

unread,
Jul 18, 2001, 5:51:26 AM7/18/01
to
* Barry Margolin <bar...@genuity.net>

> CL doesn't provide any way to bind a lexical variable without
> initializing it.

Wrong. Lexical variables are bound to pre-existing objects, initialized
elsewhere and usually elsewhen (that should have been a word).

> This is the first time I've dared respond to a post by Erik in several
> months (actually, it's one of the first ones I've seen from him in a
> while, but I've not been reading any of the long threads like
> "Engineering envy"). I don't think anything in the above paragraph can
> be interpreted as hateful, but I'm never sure how he'll take my messages.

Your personal need to post this crap speaks volumes about your hatred and
other personal problems. Keep them both off the Net. You do not _have_
to post such filth to attempt to elevate yourself. You still reek of the
place such things originate. I suggest you refrain from replying to me
at all when you cannot even imagine posting anything without adding such
demeaning insults to try to make yourself a better person at my expense.
Anyone with half a brain can see through your pathetic attempt to shift
the blame for your personal problems onto me. Just _quit_ it, idiot.

Coby Beck

unread,
Jul 18, 2001, 12:20:18 PM7/18/01
to

"Erik Naggum" <er...@naggum.net> wrote in message
news:32044386...@naggum.net...
> * Barry Margolin <bar...@genuity.net>

> > I don't think anything in the above paragraph can
> > be interpreted as hateful, but I'm never sure how he'll take my
messages.
>
> [...] crap [...] hatred [...] personal problems. [...] filth [...]
reek [...] demeaning insults [...] half a brain [...] pathetic [...]
personal problems [...] idiot.
>

I'd say he took it bad... : )

Coby
--
(remove #\space "coby . beck @ opentechgroup . com")


Barry Margolin

unread,
Jul 18, 2001, 2:28:41 PM7/18/01
to
In article <sfwzoa3...@world.std.com>,

Kent M Pitman <pit...@world.std.com> wrote:
>However, [not speaking to Barry now but to the original poster],
>it's so rare that an implementation actually specializes storage
>associated with a LET to make it "smaller" than is needed to represent a full
>pointer, that I think another way to look at it is to say that it really just
>doesn't, in practice, cost anything to say the variable initially holds a
>value of a specialized type.

And the reason why arrays have specialized types is because there are many
common uses of arrays where it *does* pay to reduce the size of each
element. When large amounts of similar data are accessed, arrays are
probably the most common storage mechanism. If the compiler can optimize
out the type dispatching in the inner loop that processes the array, it can
have a significant impact.

There have also been some implementations where the storage space for a
fixnum or single-float is half that of a pointer that's used for general
references. If you have a huge array, reducing its footprint in half can
improve performance quite a bit due to reduced paging. As memory has
gotten cheaper this has become less significant, although not as much as
you'd think because applications have also grown in size (some say "bloat")
to take up the available space.

But the general point is that arrays are more often used for the types of
things that can most benefit from these types of compiler optimizations.
While it's also common to iterate through lists like this, I don't think
they tend to grow to the enormous sizes that arrays sometimes do. The
types of applications that require such huge data sets often match arrays'
properties pretty well (this is why vector processors are a common feature
of supercomputers).

Barry Margolin

unread,
Jul 18, 2001, 2:34:06 PM7/18/01
to
In article <32044386...@naggum.net>, Erik Naggum <er...@naggum.net> wrote:
>* Barry Margolin <bar...@genuity.net>
>> CL doesn't provide any way to bind a lexical variable without
>> initializing it.
>
> Wrong. Lexical variables are bound to pre-existing objects, initialized
> elsewhere and usually elsewhen (that should have been a word).

Are we talking about different things? I was talking about initializing
the variable, not the contents of the object that it refers to.

>> This is the first time I've dared respond to a post by Erik in several
>> months (actually, it's one of the first ones I've seen from him in a
>> while, but I've not been reading any of the long threads like
>> "Engineering envy"). I don't think anything in the above paragraph can
>> be interpreted as hateful, but I'm never sure how he'll take my messages.
>
> Your personal need to post this crap speaks volumes about your hatred and
> other personal problems.

You manage to read hatred into whatever I write. I didn't write that
because I hate you, I wrote it because I was *scared* of you, since no
matter what I write you always manage to turn it into a sign of hatred.

I just can't win.

Bulent Murtezaoglu

unread,
Jul 18, 2001, 2:38:53 PM7/18/01
to
>>>>> "BarMar" == Barry Margolin <bar...@genuity.net> writes:

BarMar> ... If you have
BarMar> a huge array, reducing its footprint in half can improve
BarMar> performance quite a bit due to reduced paging. As memory
BarMar> has gotten cheaper this has become less significant,
BarMar> although not as much as you'd think because applications
BarMar> have also grown in size (some say "bloat") to take up the
BarMar> available space. ...

Just an addition, (and I am sure you know this but the OP might not)
storing the data itself directly in the array as opposed to pointers
gets you a big win due to caching if your access pattern to the
array has some locality. As you point out, paging is less of a
concern now but the speed difference between main memory and fast l1
and l2 caches seem to be increasing, giving rise to a similar concern.

cheers,

BM

Tim Bradshaw

unread,
Jul 18, 2001, 2:45:12 PM7/18/01
to
* Barry Margolin wrote:

> There have also been some implementations where the storage space for a
> fixnum or single-float is half that of a pointer that's used for general
> references. If you have a huge array, reducing its footprint in half can
> improve performance quite a bit due to reduced paging. As memory has
> gotten cheaper this has become less significant, although not as much as
> you'd think because applications have also grown in size (some say "bloat")
> to take up the available space.

Even without paging it can really help, both because just walking
through the array requires half the memory fetches, and because you
don't have to make at least one further fetch to get at the actual
object. Even without the pointer-is-two-single-floats problem you
still save a fair bit of memory traffic, and the traffic you have
probably has better characteristics for caches.

--tim

Erik Naggum

unread,
Jul 18, 2001, 3:47:35 PM7/18/01
to
* Barry Margolin

> Are we talking about different things? I was talking about initializing
> the variable, not the contents of the object that it refers to.

Yes, that is the point of difference and the reason one is called binding
and the other is called initialization. Programming languages that treat
their lexical variables as data storage perpetuate the notion that they
take space of the same kind as data storage in objects. There are some
very important differences that make them worthy of different concepts.
You always bind a variable to an object, but you may initialize an object
with some other data. If you just allocate space for something in a
variable, that may just not be good coding style. Several languages have
made it so much easier in recent years to have lexical variables defined
where they are first needed, but I think (Common) Lisp was there first,
although we do have support for variables-as-temporary-data-storage, too,
like many other things that _sometimes_ come in handy, despite general
rules to the contrary.

> You manage to read hatred into whatever I write.

I read you to want the general public to applaud you moral superiority
over me, because you could behave like a normal human being and actually
manage to be to the point and _not_ attack me out of the blue, as opposed
to me, whom you expect to slaughter you in response, but what did you do
in that last paragraph? You went out of your wray to depict me as
someone who _will_ respond hostilely to absolutely _anything_, while
wearing a halo and a smirk as _you_ say it. Hatred takes many forms.
The kind of holier-than-thou disrespect you simply cannot help yourself
from spewing is one form that several other (groups of) people who have
experienced systematic hatred know all too well, and not surprisingly,
those who have built their hatred into their personality, do not even
recognize it when they show it to people.

It is blindingly obvious that you hate _me_, but I only hate what you
keep _doing_ to me. If you simply _stopped_ your insane need to paint me
as the devil himself, maybe you would be treated as something other than
the insanely hateful person you continue to look like. It does not take
much: Simply _refrain_ from accusing people, directly or indirectly, of
things they have not even done, and especially not _yet_.

> I didn't write that because I hate you, I wrote it because I was *scared*
> of you, since no matter what I write you always manage to turn it into a
> sign of hatred.

Just behave. You do not have to point out that you have behaved and
imply that others have not before they had a chance to do anything. If
you poke people in the eye and say "look, I did not kill you, but God
knows what someone like _you_ will do next", what do you _expect_?

Well, one way is to show you the same kind of _disrespect_ you show
others and exclaim extactically that "look, everybody, Barry Margolin is
so happy he can actually behave like a normal human being that he must
tell us and virtually asks us all to applaud him! HOORAY for Barry!",
but I somehow maintain that respectful behavior towards others is the
baseline. That is why I keep getting angry at people like you who seem
unable to deal with others respectfully no matter _what_ they do to you.

> I just can't win.

Yes, you can. That you have failed to figure it out, frankly amazes me.
Just make an effort to treat people _fairly_ and _respectfully_ when they
have, in fact, not attacked you. As long as you keep doing your moral
superiority stunt, expect hostile response. Try it with other people and
see if _maybe_ it is how you behave that is the cause. How would _you_
react if someone took every opportunity to imply that you were insane or
at the very least a very, very bad person, no matter what they did? If
you feel like you "just can't win", just _try_ to imagine how you have
_purposefully_ made me feel for the longest time! If you do not like it
happening to yourself, consider the fact that you have other options than
constantly doing it to somebody else.

Just behave, Barry Margolin. You do not need to tell anyone and you most
certainly do not need to be applauded for it when you accomplish it. I
assume that you are sufficiently smart to figure out that if you insult
people, you will not be treated nicely in return. I assume, however,
that you are not _willing_ to consider the fact that you insult people
with your moral superiority stunts and your disrespectfulness because
something (probably a bad religion) tells you that you have the _right_
to do that to other people. I know from the past that you have a very
hard time actually dealing with people based on what they do -- you have
been guilty several times in the past of not even being able to _see_
what people are doing, but have imputed evil to their intentions no
matter what you actually see. You should have recognized it, since you
have done it to me for years, much like some of the other kooks here who
have a hard time dealing with reality, but somehow that moral superority
of yours have kept you from realizing it. Look at your own behavior and
see if you would let _me_ "win". You _know_ that I let people off the
hook if they stop doing the _specific_ things I criticize them for, but
you keep being _unspecific_ and _not_ letting me off the hook. Do you
need to be treated the same before you realize what you are doing, or are
you smart enough to figure it out on your own? It is your choice.

You are among the most _unfair_ people I have had the displeasure of
dealing with, Barry Margolin, and it will take me some time to recover
from the hostility I feel towards you and expect from you, which you have
managed to inflame _again_, out of nowhere. I _never_ know when you will
come out of nowhere and attack me brutally for things I have not even
_done_. You could at least have confined yourself to stuff I _have_ done
-- any sane person can always find something _real_ to attack in another
person if he wants to, but the insane need to invent evil that is not
there. Since you have done the latter towards me for a _very_ long time,
I assume it will require massive effort on your part to disestablish this
vile habit of yours. I wish you the best of look, though. It sure will
be eaiser to deal with you if you can deal with me as a _person_, and not
the scary monster you appear to see when you just see my name.

#:Erik
--
There is nothing in this message that under normal circumstances should
cause Barry Margolin to announce his moral superiority over others, but
one never knows how he needs to behave to maintain his belief in it.

Barry Margolin

unread,
Jul 18, 2001, 6:05:02 PM7/18/01
to
In article <87r8vea...@nkapi.internal>,

Bulent Murtezaoglu <b...@acm.org> wrote:
>Just an addition, (and I am sure you know this but the OP might not)
>storing the data itself directly in the array as opposed to pointers
>gets you a big win due to caching if your access pattern to the
>array has some locality. As you point out, paging is less of a
>concern now but the speed difference between main memory and fast l1
>and l2 caches seem to be increasing, giving rise to a similar concern.

I didn't mention it because most Lisp implementations use an immediate
representation for fixnums. So even if you don't declare the type, you get
this benefit.

However, if the array type is short-float, most implementations would box
them unless you specialize the array. You get a big win by avoiding boxing
and unboxing, as well as better cache utilization.

Bernhard Pfahringer

unread,
Jul 18, 2001, 6:37:56 PM7/18/01
to
In article <ey3k816...@cley.com>, Tim Bradshaw <t...@cley.com> wrote:
>
>Even without paging it can really help, both because just walking
>through the array requires half the memory fetches, and because you
>don't have to make at least one further fetch to get at the actual
>object. Even without the pointer-is-two-single-floats problem you
>still save a fair bit of memory traffic, and the traffic you have
>probably has better characteristics for caches.
>
>--tim

And a smart GC can be spared from walking the array at all,
as no entry could possibly be a pointer.

Bernhard
--
--------------------------------------------------------------------------
Bernhard Pfahringer Dept. of Computer Science, University of Waikato
http://www.cs.waikato.ac.nz/~bernhard +64 7 838 4041
--------------------------------------------------------------------------

Kalle Olavi Niemitalo

unread,
Jul 17, 2001, 9:10:49 PM7/17/01
to
Erik Naggum <er...@naggum.net> writes:

> * Kalle Olavi Niemitalo <k...@iki.fi>
> > Because LET initializes things without being asked to, [...]
>
> No, it does not.

Are you objecting to "LET initializes things" or to "without
being asked to"?

(let (x)
(lambda ()
(push t x)))

As I understand this, LET binds the variable name X to a location
and initializes that location as NIL, even though I didn't say I
want it initialized. If the LET is evaluated another time, it
binds X to a different location, as can be seen by calling the
returned closures. Do you agree?

> > I know C and C++ though, and there you cannot implicitly convert T** to
> > const T**. This seems related to Common Lisp's disjoint (array X) and
> > (array Y) types (assuming X and Y are upgraded types).
>
> No, not at all related. (array (signed-byte 32)) and (array single-float)
> are disjoint for _exactly_ the same reason that int[] and float[] are.

Actually I was thinking of (array t) and (array fixnum); even
though a FIXNUM is always a T, an (array fixnum) is not an (array
t) because you can't put non-fixnums in it (again assuming
FIXNUM upgrades to itself). There is a similar problem in
converting from T** to const T**.

In C++, converting from T *const * to const T *const * is
allowed; similarly, Common Lisp could define (array fixnum) as a
subtype of (constant-array t), if there were such a type.

> My advice to you at this stage in our Lisp experience is to drop _all_ of
> your concerns about types.

"Our"?

Ole Rohne

unread,
Jul 19, 2001, 3:32:22 AM7/19/01
to
Kalle Olavi Niemitalo <k...@iki.fi> writes (to Erik Naggum <er...@naggum.net>):

> Are you objecting to "LET initializes things" or to "without
> being asked to"?
>
> (let (x)
> (lambda ()
> (push t x)))
>
> As I understand this, LET binds the variable name X to a location
> and initializes that location as NIL, even though I didn't say I
> want it initialized. If the LET is evaluated another time, it
> binds X to a different location, as can be seen by calling the
> returned closures. Do you agree?

I think it goes like this in classical lisp speak:

LET initially *binds* X to the *value* NIL. Each time the resulting
closure is evaluated, (CONS T X) is computed and X is rebound to the
resulting *value*.

No locations and no initializations here - only bindings and values.

The Hyperspec does use the word "location" a few places, notably in
the glossary section for `generalized reference'. IIUC, archetypical
locations (places) are the CAR and CDR of a CONS, and you cannot bind
variables to these.

Regards, Ole

Christopher Stacy

unread,
Jul 19, 2001, 4:15:33 AM7/19/01
to
>>>>> On 19 Jul 2001 09:32:22 +0200, Ole Rohne ("Ole") writes:
Ole> No locations and no initializations here - only bindings and values.

Ole> The Hyperspec does use the word "location" a few places, notably in
Ole> the glossary section for `generalized reference'. IIUC, archetypical
Ole> locations (places) are the CAR and CDR of a CONS, and you cannot bind
Ole> variables to these.

I think it probably tries to avoid "location" because of the
difference between a variable binding versus storing into a location,
and the lack of first-class locative pointers in Common Lisp.

0 new messages