From: rif
Subject: Typed-slots?
Date: 
Message-ID: <wj0u1a7o5q4.fsf@five-percent-nation.mit.edu>
As far as I can tell, neither ACL nor CMUCL enforce the :type keyword
in slot definitions for CLOS classes.  Is this correct?  Is there any
reason to use :type in a slot definition under either of these
systems?

Cheers,

rif

From: Raymond Toy
Subject: Re: Typed-slots?
Date: 
Message-ID: <4nn0fza1xt.fsf@edgedsp4.rtp.ericsson.se>
>>>>> "rif" == rif  <···@mit.edu> writes:

    rif> As far as I can tell, neither ACL nor CMUCL enforce the :type keyword
    rif> in slot definitions for CLOS classes.  Is this correct?  Is there any
    rif> reason to use :type in a slot definition under either of these
    rif> systems?

The latest CVS versions of CMUCL will do this and can optimize based
on it.  (I think).

Ray
From: Kent M Pitman
Subject: Re: Typed-slots?
Date: 
Message-ID: <sfw4r271hev.fsf@shell01.TheWorld.com>
rif <···@mit.edu> writes:

> As far as I can tell, neither ACL nor CMUCL enforce the :type keyword
> in slot definitions for CLOS classes.  Is this correct?  Is there any
> reason to use :type in a slot definition under either of these
> systems?

Please tell me the above question is asked in jest.

To my ears, this sounds a like:

  Hardly anyone ever comes to the art center where I'm going to
  hang my painting, so do I really have to spend a lot of time 
  making the painting look good?

  Very few people will ever walk on the bridge I'm building, so 
  does it really have to be all that strong?

  No one ever drives through my neighborhood at night, so do I
  really have to drive with my headlights on?

Program not just for today but for the future.  Your code should be
portable.  Not just in space (to other implementations) but in time
(to other releases of the implementations you use).  Just because
an implementation doesn't do a certain optimization today doesn't
mean it always won't do it.  We've given you the tools to express
future needs today.

If the program runs "fast enough", then it may be a waste of time
to add such declarations.  But if you'd like it to run faster, and
you think it could run faster with better declarations, add them.
If implementations fail to optimize as you expected, send a bug report.
But no one's going to improve their compiler to handle cases no one
is using.  There are many different ways compilers can be extended, but
implementors tend toward extending them to cover cases people actually
use.

A declaration is not just an obscure incantation for "give me one of
the 17 known optimizations".  If we wanted to do that, we would have
done something like (declare (please-use-fixnum-only-arithmetic)).
Then you would have the sinking certainty that you would not get any
optimization for which you did not know the specific name.  Instead,
we make you declare types of arguments and values in a distributed
way.  We've tried to make optimization open-ended, with lots of future
work for compiler writers to do.  Over time, compilers are expected to
get better and better, even on programs written long before.  Because
you say general information that is not specific to certain
implementations, and over time there are new kinds of tricks that can
be learned.  But you totally defeat that by saying "I'm not going to
declare anything for which I don't know there is a declaration."

So if you think you want to write declarations and you fail to, it's
you who are creating the world in which these don't get used.
From: rif
Subject: Re: Typed-slots?
Date: 
Message-ID: <wj01xxbb7nv.fsf@five-percent-nation.mit.edu>
Allow me to amend my question slightly.  I agree that programs
*should* be portable in time as well as space, in the sense that this
is a desirable goal, all else being equal.  On the other hand, the
goals of getting programs working quickly and making them fast enough
on the implementations that are available to me today are vastly more
important than portability in either space or time.  A program which
can be written in a reasonable amount of time and is fast enough on
today's CMUCL lets me "win".  A program which will run on a variety of
CLs, but is either too much work to write or too slow on all the
implementations currently available makes me "lose".  These are my
constraints.

Making type declarations that you know that your implementation (or
any implementation you're considering running) can't use seems to me
to be a case of premature optimization.  According to this approach,
should we always declare the types of everything whose type is known,
because "some future compiler" might be able to use this fact to
generate faster code (assuming our program isn't already "fast
enough")?  I just don't feel that making type declarations that I feel
"should" improve performance, and then filing bug reports when they
don't, is a very effective way to get faster programs over a
moderately short timeframe.  I could be wrong about this.

In any case, I'm not opposed to the idea of including type
declarations in slots if it makes the program more clear.  I was
really more interested in whether there is any direct programmatic
advantage on today's compilers --- I'd hope that this question need
not be asked in jest to be meaningful.

I've been informed that the very latest CMUCL does make use of these
slot-type declarations; I'm trying to compile CMUCL from CVS sources
now, but so far without luck.

Cheers,

rif
From: Steven E. Harris
Subject: Re: Typed-slots?
Date: 
Message-ID: <q673chrdyj8.fsf@raytheon.com>
rif <···@mit.edu> writes:

> I'm not opposed to the idea of including type declarations in slots
> if it makes the program more clear.

This thread quickly turned to performance optimizations, but I remain
interested in safety and restrictions one can enforce with these type
declarations. If I create an array with some class specified as the
element type, I don't want to be able to put some other type into that
array. I want the compiler (or runtime interpreter) to stop me,
because it's probably a mistake. But CLISP, for example, doesn't check
this�, and that frustrates me.

Your concern is with slot type declarations, which differ from my
array example above. The HyperSpec says:

  The :type slot option specifies that the contents of the slot will
  always be of the specified data type. It effectively declares the
  result type of the reader generic function when applied to an object
  of this class. The consequences of attempting to store in a slot a
  value that does not satisfy the type of the slot are undefined.

At least there if the implementation does nothing, it's not violating
any rules, because doing nothing is still undefined. As I often read
in the C++ groups, "It's a QoI issue."

I know that CL doesn't share the B&D obsession with restrictive type
declarations like, say, C++, but when I do go the extra step to
mention types, I want my B&D desires indulged and respected.

Kent says to submit a bug report. As a newbie learning CL, my first
humble conclusion is to respect the implementation's behavior. I was
left thinking, "Well, that must not be what the type declarations are
for. How misleading."


Footnotes: 
� By asking here, I learned about upgraded-array-element-type, and how
  an implementation can fold just about every type up to T, and get
  away with abiding by the spec by essentially ignoring the type
  specification through over-generalization.

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: Joe Marshall
Subject: Re: Typed-slots?
Date: 
Message-ID: <y8zi1grc.fsf@ccs.neu.edu>
Steven E. Harris <········@raytheon.com> writes:

> rif <···@mit.edu> writes:
> 
> > I'm not opposed to the idea of including type declarations in slots
> > if it makes the program more clear.
> 
> This thread quickly turned to performance optimizations, but I remain
> interested in safety and restrictions one can enforce with these type
> declarations. 

You cannot enforce *any* restrictions with type declarations.  A type
declaration is a promise from you to the compiler that a
variable/slot/expression/whatever will a-priori always be of the
declared type.

If you want to *enforce* a type restriction, use CHECK-TYPE.  (If you
want to enforce some generic restriction, use ASSERT.)

Some compilers will check your type declarations when safety is high,
but any compiler is free to ignore your type declarations at any
time.  The compiler is not free to ignore CHECK-TYPE or ASSERT,
however. 
From: Kent M Pitman
Subject: Re: Typed-slots?
Date: 
Message-ID: <sfw65mm1d04.fsf@shell01.TheWorld.com>
Joe Marshall <···@ccs.neu.edu> writes:

> Steven E. Harris <········@raytheon.com> writes:
> 
> > rif <···@mit.edu> writes:
> > 
> > > I'm not opposed to the idea of including type declarations in slots
> > > if it makes the program more clear.
> > 
> > This thread quickly turned to performance optimizations, but I remain
> > interested in safety and restrictions one can enforce with these type
> > declarations. 
> 
> You cannot enforce *any* restrictions with type declarations.

This is a bit strong.  I think you mean to say "rely on enforcement of".
It's true that type declarations are not imperative requests, but neither
are they prohibitions against such requests.  After all, an implementation
if free to be doing whatever type checks are semantically valid at any 
point along the data pipe...

> A type
> declaration is a promise from you to the compiler that a
> variable/slot/expression/whatever will a-priori always be of the
> declared type.
> 
> If you want to *enforce* a type restriction, use CHECK-TYPE.  (If you
> want to enforce some generic restriction, use ASSERT.)
> 
> Some compilers will check your type declarations when safety is high,
> but any compiler is free to ignore your type declarations at any
> time.  The compiler is not free to ignore CHECK-TYPE or ASSERT,
> however. 

Well, I don't use CMUCL, so correct me if I'm wrong, but I've heard it
said that CMUCL will, perhaps only under some option setting?, try to
prove the things you declare and if it can't it will insert a type
check for the parts of the type information it could not prove.

Symbolics CLOE Developer and CL Developer products had a similar switch;
in that case, there was no proof attempt.  You could just have DECLARE
"expand" into a CHECK-TYPE for development testing.
From: Joe Marshall
Subject: Re: Typed-slots?
Date: 
Message-ID: <n0fy1a4l.fsf@ccs.neu.edu>
Kent M Pitman <······@world.std.com> writes:

> Joe Marshall <···@ccs.neu.edu> writes:
> 
> > Steven E. Harris <········@raytheon.com> writes:
> > 
> > > rif <···@mit.edu> writes:
> > > 
> > > > I'm not opposed to the idea of including type declarations in slots
> > > > if it makes the program more clear.
> > > 
> > > This thread quickly turned to performance optimizations, but I remain
> > > interested in safety and restrictions one can enforce with these type
> > > declarations. 
> > 
> > You cannot enforce *any* restrictions with type declarations.
> 
> This is a bit strong.  I think you mean to say "rely on enforcement of".

I was going to agree with you, but enforcement is enforcement.  If you
cannot count on an error being raised it isn't enforced.  Sure a
platform or particular implementation *may* raise an error if the
declared type doesn't match the actual type, but if you are
programming in a `platform neutral' manner, then simply declaring
something to be of a particular type is not going `enforce' this to be
the case.

In any case, when you declare something to be of some type, the
compiler is allowed to trust you, and your program is not conforming
if the actual type is not a subtype of the declared type.

> > Some compilers will check your type declarations when safety is high,
> > but any compiler is free to ignore your type declarations at any
> > time.  The compiler is not free to ignore CHECK-TYPE or ASSERT,
> > however. 
> 
> Well, I don't use CMUCL, so correct me if I'm wrong, but I've heard it
> said that CMUCL will, perhaps only under some option setting?, try to
> prove the things you declare and if it can't it will insert a type
> check for the parts of the type information it could not prove.
> 
> Symbolics CLOE Developer and CL Developer products had a similar switch;
> in that case, there was no proof attempt.  You could just have DECLARE
> "expand" into a CHECK-TYPE for development testing.

These are all fine behaviors, but they aren't required.

The point for newbies is that declarations are promises from you about
things that the compiler might not otherwise be able to figure out,
and the compiler may blindly take your word for it.  If you want the
compiler to explicitly check, use check-type or assert.

Here is a demo from some code I've written.  For high-performance
coding, I often write a highly bummed version of a routine, and then a
small `wrapper' routine that knows how to call the bummed routine:

(defun %unsafe-hack-vector (vector beginning end)
  ;; I promise to the compiler to obey this API.
  (declare (type (vector fixnum) vector)
           (type (integer 0 #.(array-dimension-limit)) beginning end)
           (optimize (speed 3) (safety 0)))
      ....)

(defun hack-vector (vector &optional (beginning 0) (end (length vector)))
  ;; I enforce the correct values here.
  (check-type vector (vector fixnum))
  (check-type beginning (integer 0 #.(array-dimension-limit)))
  (check-type end       (integer 0 #.(array-dimension-limit)))
  (assert (<= 0 beginning end (length vector)))
  (%unsafe-hack-vector vector beginning end))

Routines that are known to obey the high-performance API can use the
bummed version directly.  Any caller can use the `safe' version.
From: Kent M Pitman
Subject: Re: Typed-slots?
Date: 
Message-ID: <sfw4r26fbmy.fsf@shell01.TheWorld.com>
Joe Marshall <···@ccs.neu.edu> writes:

> I was going to agree with you, but enforcement is enforcement.  If you
> cannot count on an error being raised it isn't enforced.

Ah, then you're saying the US drug laws aren't enforced.

Must be a relief for the folks in prison.

The world is not all black and white.  The gray areas need a name, too,
and I guess I think that "selective enforcement" is still enforcement.

> Sure a platform or particular implementation *may* raise an error if the
> declared type doesn't match the actual type, but if you are
> programming in a `platform neutral' manner, then simply declaring
> something to be of a particular type is not going `enforce' this to be
> the case.

Although this thread opened with a discussion of specific platforms.

> In any case, when you declare something to be of some type, the
> compiler is allowed to trust you, and your program is not conforming
> if the actual type is not a subtype of the declared type.

Certainly a worthwhile point.
From: Joe Marshall
Subject: Re: Typed-slots?
Date: 
Message-ID: <he6611l3.fsf@ccs.neu.edu>
Kent M Pitman <······@world.std.com> writes:

> Joe Marshall <···@ccs.neu.edu> writes:
> 
> > I was going to agree with you, but enforcement is enforcement.  If you
> > cannot count on an error being raised it isn't enforced.
> 
> Ah, then you're saying the US drug laws aren't enforced.
> 
> Must be a relief for the folks in prison.
> 
> The world is not all black and white.  The gray areas need a name, too,
> and I guess I think that "selective enforcement" is still enforcement.

To use your analogy, CHECK-TYPE is like the drug-sniffing dog;  If
properly implemented it ensures that no drugs enter the schoolyard.

DECLARE is like the sign near the school that says `Drug-Free Zone'.
You may make the assumption that there are no drugs within that zone,
and assuming everyone conforms, the assumption may be made that the
drug-sniffing dogs can be sent home.  But maybe the dogs are there
anyway.

If you want to *enforce* the drug laws, you get the dog.  The sign
won't help.
From: Thomas F. Burdick
Subject: Re: Typed-slots?
Date: 
Message-ID: <xcv8yrhu0e8.fsf@famine.OCF.Berkeley.EDU>
Joe Marshall <···@ccs.neu.edu> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > Joe Marshall <···@ccs.neu.edu> writes:
> > 
> > > I was going to agree with you, but enforcement is enforcement.  If you
> > > cannot count on an error being raised it isn't enforced.
> > 
> > Ah, then you're saying the US drug laws aren't enforced.
> > 
> > Must be a relief for the folks in prison.
> > 
> > The world is not all black and white.  The gray areas need a name, too,
> > and I guess I think that "selective enforcement" is still enforcement.
> 
> To use your analogy, CHECK-TYPE is like the drug-sniffing dog;  If
> properly implemented it ensures that no drugs enter the schoolyard.
> 
> DECLARE is like the sign near the school that says `Drug-Free Zone'.
> You may make the assumption that there are no drugs within that zone,
> and assuming everyone conforms, the assumption may be made that the
> drug-sniffing dogs can be sent home.  But maybe the dogs are there
> anyway.
> 
> If you want to *enforce* the drug laws, you get the dog.  The sign
> won't help.

This depends.  ANSI doesn't guarantee that the sign will work, it just
lets you put the sign there.  Individual implementations (I'm looking
in SBCL's direction) can interpret the signs as things to be enforced.
You're basically leaving the amount of enforcement to local
authorities -- whereas CHECK-TYPE and friends (eg, DEFMETHOD) are
specific instructions on how to implement the law.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Steven M. Haflich
Subject: Re: Typed-slots?
Date: 
Message-ID: <3F0193CC.6050506@alum.mit.edu>
rif wrote:
> As far as I can tell, neither ACL nor CMUCL enforce the :type keyword
> in slot definitions for CLOS classes.

What do you mean by the word "enforce"?

> Is this correct?  Is there any
> reason to use :type in a slot definition under either of these
> systems?

In some circumstances the compiler attaches the type information
to values stored in or retrieved from the slot and computations
on these values, just like it uses type declarations on variables,
etc.