From: Adam Warner
Subject: Transparent wrappers/weak types?
Date: 
Message-ID: <pan.2004.10.23.05.39.03.187825@consulting.net.nz>
Hi all,

If I wrap an object in a structure S can code continue to run seamlessly
by wrapping the code in a TYPE-ERROR handler that checks if the object
causing the type error is of type S and if so returns the object itself?

For example, the goal is to have this code run without error by only
wrapping code around the LOOP:

(defstruct wrapped list)
(defparameter *list* (make-wrapped :list '(1 2 3)))

(loop for item in *list* do (print item))

When the type-error of *list* is encountered in the loop the error handler
should return the value (wrapped-list *list*) for processing to continue.

Thanks,
Adam

From: Barry Margolin
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <barmar-C0CF26.09281923102004@comcast.dca.giganews.com>
In article <······························@consulting.net.nz>,
 Adam Warner <······@consulting.net.nz> wrote:

> Hi all,
> 
> If I wrap an object in a structure S can code continue to run seamlessly
> by wrapping the code in a TYPE-ERROR handler that checks if the object
> causing the type error is of type S and if so returns the object itself?
> 
> For example, the goal is to have this code run without error by only
> wrapping code around the LOOP:
> 
> (defstruct wrapped list)
> (defparameter *list* (make-wrapped :list '(1 2 3)))
> 
> (loop for item in *list* do (print item))
> 
> When the type-error of *list* is encountered in the loop the error handler
> should return the value (wrapped-list *list*) for processing to continue.

I think this could only be expected to work if none of the code that 
makes use of wrapped objects is compiled with low safety.  Otherwise, 
they wouldn't be required to do type checks, and undefined behavior 
results.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Peter Seibel
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <m36551703y.fsf@javamonkey.com>
Barry Margolin <······@alum.mit.edu> writes:

> In article <······························@consulting.net.nz>,
>  Adam Warner <······@consulting.net.nz> wrote:
>
>> Hi all,
>> 
>> If I wrap an object in a structure S can code continue to run
>> seamlessly by wrapping the code in a TYPE-ERROR handler that checks
>> if the object causing the type error is of type S and if so returns
>> the object itself?
>> 
>> For example, the goal is to have this code run without error by
>> only wrapping code around the LOOP:
>> 
>> (defstruct wrapped list)
>> (defparameter *list* (make-wrapped :list '(1 2 3)))
>> 
>> (loop for item in *list* do (print item))
>> 
>> When the type-error of *list* is encountered in the loop the error
>> handler should return the value (wrapped-list *list*) for
>> processing to continue.
>
> I think this could only be expected to work if none of the code that
> makes use of wrapped objects is compiled with low safety. Otherwise,
> they wouldn't be required to do type checks, and undefined behavior
> results.

Also, even if the error is signaled, you won't have restarts at the
appropriate level of granularity to recover. For instance in this
case, to "fix" the type error you need a way to restart the LOOP
having replaced *list* with the wrapped list. What you really want is
for LOOP to have established a USE-VALUE restart around the right bit
of code so you can replace the mistyped object (i.e. *list*) with an
object of the right type and let LOOP proceed. But there's no such
restart documented as part of LOOP.

You say "the error handler should return the value ...". But that's
wrong--handlers don't handle errors by returning values; they handle
them by causing a non-local exit. Such as invoking a restart.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Adam Warner
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <pan.2004.10.23.22.54.18.773592@consulting.net.nz>
Hi Peter Seibel,

>> I think this could only be expected to work if none of the code that
>> makes use of wrapped objects is compiled with low safety. Otherwise,
>> they wouldn't be required to do type checks, and undefined behavior
>> results.
> 
> Also, even if the error is signaled, you won't have restarts at the
> appropriate level of granularity to recover. For instance in this case,
> to "fix" the type error you need a way to restart the LOOP having
> replaced *list* with the wrapped list. What you really want is for LOOP
> to have established a USE-VALUE restart around the right bit of code so
> you can replace the mistyped object (i.e. *list*) with an object of the
> right type and let LOOP proceed. But there's no such restart documented
> as part of LOOP.
> 
> You say "the error handler should return the value ...". But that's
> wrong--handlers don't handle errors by returning values; they handle
> them by causing a non-local exit. Such as invoking a restart.

Peter, thanks for confirming my rudimentary understanding of the condition
system. The meta question is why ANSI Common Lisp can't do this in
circumstances where it must maintain a reference to an object (such as it
has to do with dynamic variables).

I guess it's because there is no requirement in ANSI Common Lisp for
restarts in all functions with safe code. To implement this properly the
most basic functions such as CAR and CDR would have to be restartable if
given an incorrect type. This could slow down safe code (by limiting
inlining/reducing locality).

The approach could detract from the philosophy of Common Lisp
optimisation, where you're not supposed to lie to the compiler. The
program could break if safety was reduced because its correct operation
depends upon detecting deliberate type errors. One of the points in
running code with high safety is to detect and eliminate type errors in
expectation of being able to run the program faster with low safety.
Dynamically fixing type errors could kill this virtuous cycle.

The root problem is that LOOP and the built in functions are not
extensible. Fixing this requires shadowing half of Common Lisp. Any
sufficiently complicated domain-specific Lisp program contains an ad hoc
informally-specified bug-ridden slow implementation of half of Common Lisp.

Regards,
Adam
From: Rahul Jain
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <87u0sjbi3e.fsf@nyct.net>
Adam Warner <······@consulting.net.nz> writes:

> The root problem is that LOOP and the built in functions are not
> extensible.

So use SERIES. :)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Rahul Jain
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <87y8hvbi5b.fsf@nyct.net>
Adam Warner <······@consulting.net.nz> writes:

> If I wrap an object in a structure S can code continue to run seamlessly
> by wrapping the code in a TYPE-ERROR handler that checks if the object
> causing the type error is of type S and if so returns the object itself?

Isn't this what we call polymorphism? :)

Just use defmethod.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Barry Margolin
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <barmar-32181D.23535424102004@comcast.dca.giganews.com>
In article <··············@nyct.net>, Rahul Jain <·····@nyct.net> 
wrote:

> Adam Warner <······@consulting.net.nz> writes:
> 
> > If I wrap an object in a structure S can code continue to run seamlessly
> > by wrapping the code in a TYPE-ERROR handler that checks if the object
> > causing the type error is of type S and if so returns the object itself?
> 
> Isn't this what we call polymorphism? :)
> 
> Just use defmethod.

Except that LOOP doesn't necessarily call a generic function that you 
can extend with a new method.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Rahul Jain
Subject: Re: Transparent wrappers/weak types?
Date: 
Message-ID: <87ekjklrpw.fsf@nyct.net>
Barry Margolin <······@alum.mit.edu> writes:

> In article <··············@nyct.net>, Rahul Jain <·····@nyct.net> 
> wrote:
>
>> Isn't this what we call polymorphism? :)
>> 
>> Just use defmethod.
>
> Except that LOOP doesn't necessarily call a generic function that you 
> can extend with a new method.

He'd define the method at the higher level. The operator that will do
the looping itself. If he doesn't want to do that, he can use SERIES. :)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist