From: Peter Seibel
Subject: Reasonable use of change-class?
Date: 
Message-ID: <m3r86lk0gh.fsf@javamonkey.com>
Suppose I'm writing some code to read data from a file. I want to
create instances of user-defined classes to represent the various
pieces of data in the file.

Some of the data in the file is structured so that you know you're
going to read some kind of "foo" but only after have you read the
first bit do you know exactly what kind of "foo".

One approach I'm considering is to write a function READ-FOO that
creates an instance of FOO and reads the data common to all FOO's
stashing it in the appropriate slots. Then, after deciding what
subtype of FOO is really being read, based on the data read so far, it
will CHANGE-CLASS the object to the appropriate subclass, say BAR-FOO,
and pass it to a generic function FINSH-READ which will have methods
to read the data for the BAR-FOO specific slots. In theory a method on
FINISH-READ could further dispatch to a sub-sub-type by another
CHANGE-CLASS and invocation of FINISH-READ.

Does this seem like a reasonable approach?

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp

From: Kenny Tilton
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <3ED369D8.50404@nyc.rr.com>
Peter Seibel wrote:
> Suppose I'm writing some code to read data from a file. I want to
> create instances of user-defined classes to represent the various
> pieces of data in the file.
> 
> Some of the data in the file is structured so that you know you're
> going to read some kind of "foo" but only after have you read the
> first bit do you know exactly what kind of "foo".
> 
> One approach I'm considering is to write a function READ-FOO that
> creates an instance of FOO and reads the data common to all FOO's
> stashing it in the appropriate slots. Then, after deciding what
> subtype of FOO is really being read, based on the data read so far, it
> will CHANGE-CLASS the object to the appropriate subclass, say BAR-FOO,
> and pass it to a generic function FINSH-READ which will have methods
> to read the data for the BAR-FOO specific slots. In theory a method on
> FINISH-READ could further dispatch to a sub-sub-type by another
> CHANGE-CLASS and invocation of FINISH-READ.
> 
> Does this seem like a reasonable approach?

Well, without the whole picture it is tough to say, so I'll shoot from 
the hip: I don't like it. It seems to divide expression of desired 
semantics across the parsing logic, the CLOS hierarchy, and the data file.

Example: the structure of the data file must satisfy the rest of the 
approach, by requiring that all class-specific, instance-filling data 
follow the class-identifying data. That is de facto easy but in 
principle troubling.

I also imagine myself bouncing back and forth between the data file 
structure design and the class hierarchy and parser, sometimes tweaking 
one, sometimes tweaking the other.

If the data file simply defines the instance in a single form (let's say 
you are using the reader and lisp forms to build the data file), then 
you can just read the form in, decide on the class and make-instance on 
the final intended class.

OK, that assumes you have control over the input data. If not, it seems 
to me possible that filling data will be encountered before you know 
what class to make, so you could end up having to stash that somewhere 
for use post change-class.

I see where you are going ("bootstrap-instance"?), I just do not think 
the problem justifies the double-clutching.

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Everything is a cell." -- Alan Kay
From: Peter Seibel
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <m34r3gjo1u.fsf@javamonkey.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> Peter Seibel wrote:
> > Suppose I'm writing some code to read data from a file. I want to
> > create instances of user-defined classes to represent the various
> > pieces of data in the file.
> > Some of the data in the file is structured so that you know you're
> 
> > going to read some kind of "foo" but only after have you read the
> > first bit do you know exactly what kind of "foo".
> > One approach I'm considering is to write a function READ-FOO that
> 
> > creates an instance of FOO and reads the data common to all FOO's
> > stashing it in the appropriate slots. Then, after deciding what
> > subtype of FOO is really being read, based on the data read so far, it
> > will CHANGE-CLASS the object to the appropriate subclass, say BAR-FOO,
> > and pass it to a generic function FINSH-READ which will have methods
> > to read the data for the BAR-FOO specific slots. In theory a method on
> > FINISH-READ could further dispatch to a sub-sub-type by another
> > CHANGE-CLASS and invocation of FINISH-READ.
> > Does this seem like a reasonable approach?
> 
> 
> Well, without the whole picture it is tough to say, so I'll shoot
> from the hip: I don't like it. It seems to divide expression of
> desired semantics across the parsing logic, the CLOS hierarchy, and
> the data file.
> 
> 
> Example: the structure of the data file must satisfy the rest of the
> approach, by requiring that all class-specific, instance-filling
> data follow the class-identifying data. That is de facto easy but in
> principle troubling.
> 
> 
> I also imagine myself bouncing back and forth between the data file
> structure design and the class hierarchy and parser, sometimes
> tweaking one, sometimes tweaking the other.


> If the data file simply defines the instance in a single form (let's
> say you are using the reader and lisp forms to build the data file),
> then you can just read the form in, decide on the class and
> make-instance on the final intended class.
> 
> 
> OK, that assumes you have control over the input data. If not, it
> seems to me possible that filling data will be encountered before you
> know what class to make, so you could end up having to stash that
> somewhere for use post change-class.

So I don't have control over the input data. The data format is fixed.
(ID3 tags in an mp3 file in this case. Similar problems arise when
parsing Java .class files.) In these situations it turns out that the
super classes will naturally have fields to hold all the data that is
read before the decision is made what more specific type to read. Thus
I don't have to tidy anything up after CHANGE-CLASS. But I could also
just arrange to hold the data I need to create the instance in some
other data structure and once I actually know exactly what type I
want, to instantiate an object using that data. Anyway, I'll be
working on this and will probably try a couple different
approaches--I'll let you know how it turns out. Thanks.

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Barry Margolin
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <_jOAa.23$Y07.119@paloalto-snr1.gtei.net>
In article <··············@javamonkey.com>,
Peter Seibel  <·····@javamonkey.com> wrote:
>So I don't have control over the input data. The data format is fixed.
>(ID3 tags in an mp3 file in this case. Similar problems arise when
>parsing Java .class files.) In these situations it turns out that the
>super classes will naturally have fields to hold all the data that is
>read before the decision is made what more specific type to read. Thus
>I don't have to tidy anything up after CHANGE-CLASS. But I could also
>just arrange to hold the data I need to create the instance in some
>other data structure and once I actually know exactly what type I
>want, to instantiate an object using that data.

That's probably how I would do it.  This "other data structure" could
simply be a list containing all the initialization arguments, and then you
can do:

(apply #'make-instance actual-class data)

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, 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.
From: Peter Seibel
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <m3ptm4hzg0.fsf@javamonkey.com>
Barry Margolin <··············@level3.com> writes:

> In article <··············@javamonkey.com>,
> Peter Seibel  <·····@javamonkey.com> wrote:
> >So I don't have control over the input data. The data format is fixed.
> >(ID3 tags in an mp3 file in this case. Similar problems arise when
> >parsing Java .class files.) In these situations it turns out that the
> >super classes will naturally have fields to hold all the data that is
> >read before the decision is made what more specific type to read. Thus
> >I don't have to tidy anything up after CHANGE-CLASS. But I could also
> >just arrange to hold the data I need to create the instance in some
> >other data structure and once I actually know exactly what type I
> >want, to instantiate an object using that data.
> 
> That's probably how I would do it. This "other data structure" could
> simply be a list containing all the initialization arguments, and
> then you can do:
> 
> (apply #'make-instance actual-class data)

Yup. That was what I was thinking of. The only trick there is then I
have to keep track of where I am in the "parse" to know how to parse
the next bits; in the CHANGE-CLASS the (new) type of the object makes
that dispatching automatic. Without it I need some other way to know
what to do next. (Not saying that's impossible, or even hard, just
that I need to pick one of the many ways of doing it.) Thanks for your
response.

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Wade Humeniuk
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <1mRAa.277$vi4.233225@news0.telusplanet.net>
"Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
> > (apply #'make-instance actual-class data)
> 
> Yup. That was what I was thinking of. The only trick there is then I
> have to keep track of where I am in the "parse" to know how to parse
> the next bits; in the CHANGE-CLASS the (new) type of the object makes
> that dispatching automatic. Without it I need some other way to know
> what to do next. (Not saying that's impossible, or even hard, just
> that I need to pick one of the many ways of doing it.) Thanks for your
> response.

Could we see your actual code?  It sounds like you are making your
life difficult when there is probably a limited number of variants and
after it is coded it does not need to be extensible.  It also sounds like
you are having difficulty parsing.

Wade
From: Peter Seibel
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <m33cizj545.fsf@javamonkey.com>
"Wade Humeniuk" <····@nospam.nowhere> writes:

> "Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
> > > (apply #'make-instance actual-class data)
> > 
> > Yup. That was what I was thinking of. The only trick there is then I
> > have to keep track of where I am in the "parse" to know how to parse
> > the next bits; in the CHANGE-CLASS the (new) type of the object makes
> > that dispatching automatic. Without it I need some other way to know
> > what to do next. (Not saying that's impossible, or even hard, just
> > that I need to pick one of the many ways of doing it.) Thanks for your
> > response.
> 
> Could we see your actual code?  It sounds like you are making your
> life difficult when there is probably a limited number of variants and
> after it is coded it does not need to be extensible.  It also sounds like
> you are having difficulty parsing.

Well, the code is still very much a sketch--I'm not sure I have any
concrete questions that I can put into useful forms like, "I'm trying
to do X and I can't figure out how" or "Here's what I've done, how can
I make it better?"

I know that I *am* making my life difficult but not, perhaps, for the
reasons you suspect. Mostly I've been down this path of parsing binary
files a few times before, once in Lisp and a couple times in Java, and
I'm beginning to get an idea of what I want as far as a macro package
to express "here's how you take apart a binary file". So the tendency
to generalize is not coming from just this one problem--id3 tags just
happen to be the latest one.

But thanks for your offer to take a look at my code--maybe once I've
got something that's I can ask a more specific question about, I'll
take you up on it.

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Timothy Moore
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <bb1bef$5cb$0@216.39.145.192>
Peter Seibel <·····@javamonkey.com> writes:

> "Wade Humeniuk" <····@nospam.nowhere> writes:
> 
> > "Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
> > > > (apply #'make-instance actual-class data)
> > > 
> > > Yup. That was what I was thinking of. The only trick there is then I
> > > have to keep track of where I am in the "parse" to know how to parse
> > > the next bits; in the CHANGE-CLASS the (new) type of the object makes
> > > that dispatching automatic. Without it I need some other way to know
> > > what to do next. (Not saying that's impossible, or even hard, just
> > > that I need to pick one of the many ways of doing it.) Thanks for your
> > > response.
> > 
> > Could we see your actual code?  It sounds like you are making your
> > life difficult when there is probably a limited number of variants and
> > after it is coded it does not need to be extensible.  It also sounds like
> > you are having difficulty parsing.
> 
> Well, the code is still very much a sketch--I'm not sure I have any
> concrete questions that I can put into useful forms like, "I'm trying
> to do X and I can't figure out how" or "Here's what I've done, how can
> I make it better?"
> 

For the record, I think the change-class strategy is a fine idea. Why
screw around with lists of arguments, especially if there are
multiple pointers to the as-yet unknown class?

Tim
From: Kenny Tilton
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <3ED4BFD7.3080507@nyc.rr.com>
>>>"Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
>>>
>>>>>(apply #'make-instance actual-class data)
>>>>
>>>>Yup. That was what I was thinking of. The only trick there is then I
>>>>have to keep track of where I am in the "parse" to know how to parse
>>>>the next bits; ...

But that requires only one state variable, say, instance-class. I can 
imagine there must be in your parser a lot of code like:

     (setf (slot-x new-thing) newest-parsed-value)

ie, you want to populate the slots as you go, not have them in state 
variables later passed to make-instance as initargs.

Here is something I just focused on over here: the consequence of this 
is that you end up allocating two instances (that's how change-class 
works) in order to make one, which is a priori a Bad Thing. I do not 
mean the performance problem, just that it is a Message From God(tm) 
that the approach is over-compilcated.

I could stop there, but another Bad Sign is that your intended parser of 
this MP3 stuff is now more a conduit from MP3 to one very specific class 
hierarchy.

If instead, as you parse, you maintain two state variables, 
instance-class and instance-initargs:

     (nconc instance-initargs (list :slot-x newest-parsed-value))

You avoid the extra instantiation and have a purpose-neutral parse 
product. If you /really/ want to decompose the parse logic by taking 
advantage of what has been determined so far (the eventual class), you 
can dispatch thus:

    (defmethod mp3-parse ((i-class 'mp3-whatever) stream)...

Were you just looking for a good application of "change-class"? I think 
that should involve a long-lived instance which starts as one class, 
serves for a while, then changes class.


-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Everything is a cell." -- Alan Kay
From: Wade Humeniuk
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <R55Ba.3218$fs1.760520@news1.telusplanet.net>
"Kenny Tilton" <·······@nyc.rr.com> wrote in message ·····················@nyc.rr.com...
> Were you just looking for a good application of "change-class"? I think
> that should involve a long-lived instance which starts as one class,
> serves for a while, then changes class.

Actually I have used it, as a necessity.  In LW comm:open-tcp-stream
returns an instance of comm:socket-stream.  I subclassed it with
a http-stream.  I call comm:open-tcp-stream and  then change-class
it into the subclass.  It is totally out of necessity because of library issues,
I cannot change comm:open-tcp-stream.

(defun open-http-stream (host port &key (direction :io) (connect-time-limit 30))
  (let* ((process mp:*current-process*)
         (timer
          (mp:make-timer
           (lambda ()
             (mp:process-interrupt process
                                   (lambda () (error 'open-http-stream-timeout
                                                     :host host
                                                     :port port
                                                     :connect-time-limit connect-time-limit)))))))
    (unwind-protect
        (progn
          (mp:schedule-timer-relative timer connect-time-limit)
          (change-class (comm:open-tcp-stream host port :direction direction :errorp t)
'http-stream))
      (ignore-errors (mp:unschedule-timer timer)))))

Wade
From: Arthur Lemmens
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <3ED52710.47618986@xs4all.nl>
Wade Humeniuk wrote:
> 
> Actually I have used it, as a necessity.  In LW comm:open-tcp-stream
> returns an instance of comm:socket-stream.  I subclassed it with
> a http-stream.  I call comm:open-tcp-stream and  then change-class
> it into the subclass.  It is totally out of necessity because of library 
> issues, I cannot change comm:open-tcp-stream.

You can also use Gray streams in situations like this to encapsulate the 
socket-stream.

Arthur Lemmens
From: Wade Humeniuk
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <jLaBa.3637$fs1.976655@news1.telusplanet.net>
"Arthur Lemmens" <········@xs4all.nl> wrote in message ······················@xs4all.nl...
> 
> Wade Humeniuk wrote:
> > 
> > Actually I have used it, as a necessity.  In LW comm:open-tcp-stream
> > returns an instance of comm:socket-stream.  I subclassed it with
> > a http-stream.  I call comm:open-tcp-stream and  then change-class
> > it into the subclass.  It is totally out of necessity because of library 
> > issues, I cannot change comm:open-tcp-stream.
> 
> You can also use Gray streams in situations like this to encapsulate the 
> socket-stream.

I started out that way (actually encapsulating the socket-stream in 
LW stream, see stream package).  Everything seemed to work fine
but I still had a nagging voice in the back of my head that I may
be introducing some bugs in implementing the methods
for the stream.  There was also the possiblity that Xanalys may 
have been doing something special behind the scenes with 
the socket-stream instances that I could not be a aware of.  If
my stream was a socket-stream then it would inherit that 
hidden behaviour.

I realized that Xanalys had done all this work already and it
was thoroughly tested.  I was not adding any new functionality to
the IO, just passing things on.  So..  I just subclassed it added some
:after methods to detect stream activity and went from there.
I added chunking-encoder and chunking-decoder classes which
temporarily intercept stream io and use http-streams to
do their work.

Wade
From: Peter Seibel
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <m3smqzgcjf.fsf@javamonkey.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> >>>"Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
> >>>
> >>>>>(apply #'make-instance actual-class data)
> >>>>
> >>>>Yup. That was what I was thinking of. The only trick there is then I
> >>>>have to keep track of where I am in the "parse" to know how to parse
> >>>>the next bits; ...
> 
> But that requires only one state variable, say, instance-class. I can
> imagine there must be in your parser a lot of code like:
> 
> 
>      (setf (slot-x new-thing) newest-parsed-value)
> 
> ie, you want to populate the slots as you go, not have them in state
> variables later passed to make-instance as initargs.

Well, the problem--as I see it--is not where to stash the values but
how to know how to decode the next parsed value (is it going to be a
unsigned byte, or a string, or what?) until I know what kind of thing
I'm trying to read. But I can, as you suggest, dispatch on something
other than the type of the instance. (I was thinking more of EQL
specializers on symbols, but I think that's more or less the same as
the dispatch-on-the-class approach you suggest below.

> Here is something I just focused on over here: the consequence of
> this is that you end up allocating two instances (that's how
> change-class works) in order to make one, which is a priori a Bad
> Thing. I do not mean the performance problem, just that it is a
> Message From God(tm) that the approach is over-compilcated.

Yeah. I know what you mean. I do try to pay attention to those
Messages.

> I could stop there, but another Bad Sign is that your intended
> parser of this MP3 stuff is now more a conduit from MP3 to one very
> specific class hierarchy.

I'm not sure why this is a Bad Sign. My *goal* is to have an object
representation of the stuff in an ID3 tag so I can get at the data
easily. I'm designing the class hierarchy to suit my needs--why
wouldn't I want to get the data into that class hierarchy?

> If instead, as you parse, you maintain two state variables,
> instance-class and instance-initargs:
> 
>      (nconc instance-initargs (list :slot-x newest-parsed-value))
> 
> You avoid the extra instantiation and have a purpose-neutral parse
> product. If you /really/ want to decompose the parse logic by taking
> advantage of what has been determined so far (the eventual class),
> you can dispatch thus:
> 
> 
>     (defmethod mp3-parse ((i-class 'mp3-whatever) stream)...
> 
> Were you just looking for a good application of "change-class"? I
> think that should involve a long-lived instance which starts as one
> class, serves for a while, then changes class.

"Looking for" might be putting it a bit strongly. I happend to notice
it was one way I could slice the problem but it seemed like a bit of a
dramatic way to do it so I thought I'd ask what other people thought.

My current theory--changes every hour--is that what I really want is
to parse the data into a bunch of generic id3-frame objects. Each
frame starts with a tag and a length field and then 'length' more
bytes of data, I can make classes like:

  (defclass id3v2.2-frame ()
    ((tag :initarg :tag :reader tag)
     (length :initarg :length :accessor length)))

  (defclass generic-id3v2.2-frame (id3v2.2-frame)
    ((data :initarg :data :accessor data)))


and then create instances of generic-id3v2.2-frame that hold the data
as raw bytes. At this point I'll know what kinds of frames I have
(based on the values of 'tag') and can lazily parse the data in any
given frames when I actually need it. At that point using change-class
and update-instance-for-different-class seems like a reasonably way to
go, to convert the raw bytes of 'data' in a generic-id3v2.2-frame to
whatever structured form is implied by the specific type of frame.
Assuming I have a hash table of 'tag' to classes, maybe something
like:

  (defun convert-frame (generic-frame)
    (change-class 
      generic-frame
      (gethash (tag generic-frame) *frame-classes*)))

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kenny Tilton
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <3ED51416.5030403@nyc.rr.com>
Peter Seibel wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>>>>"Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
>>>>>
>>>>>
>>>>>>>(apply #'make-instance actual-class data)
>>>>>>
>>>>>>Yup. That was what I was thinking of. The only trick there is then I
>>>>>>have to keep track of where I am in the "parse" to know how to parse
>>>>>>the next bits; ...
>>>>>
>>But that requires only one state variable, say, instance-class. I can
>>imagine there must be in your parser a lot of code like:
>>
>>
>>     (setf (slot-x new-thing) newest-parsed-value)
>>
>>ie, you want to populate the slots as you go, not have them in state
>>variables later passed to make-instance as initargs.
> 
> 
> Well, the problem--as I see it--is not where to stash the values but
> how to know how to decode the next parsed value (is it going to be a
> unsigned byte, or a string, or what?) until I know what kind of thing
> I'm trying to read.

I should confess that this is where I get lost. I am imagining a nice 
little finite state machine parser, which as a matter of course reads a 
little data and enters a new state, perhaps also stashing some 
supporting state. The only complexity I see is that the tokenizer has to 
look at the current state to decide how to parse the binary stuff. That 
can be a case statement (in which several cases will share the same 
parsing logic, which is logically driven by what is in the MP3, not the 
class hierarchy you choose to make out of the MP3).


>>I could stop there, but another Bad Sign is that your intended
>>parser of this MP3 stuff is now more a conduit from MP3 to one very
>>specific class hierarchy.
> 
> 
> I'm not sure why this is a Bad Sign. My *goal* is to have an object
> representation of the stuff in an ID3 tag so I can get at the data
> easily. I'm designing the class hierarchy to suit my needs--why
> wouldn't I want to get the data into that class hierarchy?

Build it (an intermediate lightweight representation of the MP3 data) 
and they (other uses) will come. Mind you, at this point I am handwaving 
about a general approach to problems: break the one process I have to do 
now into two steps, to decouple parsing from the end product I want, so 
as to reap vaguely imagined /possible/ benefits. Like, OK, Something 
Changes, maybe I just have to play with the parser, or maybe just the 
class hierarchy instantiated inthe second step. Or as i started with, 
maybe I can do something with the lightweight representation without all 
the class stuff, release it under GPL as a lib, or hell, don't even make 
the intermediate rep, just play the MP3 with user control over some 
parameters.

> "Looking for" might be putting it a bit strongly. I happend to notice
> it was one way I could slice the problem but it seemed like a bit of a
> dramatic way to do it so I thought I'd ask what other people thought.

OK, I'll shut up, you know about the dramatic quality. :)

> 
> My current theory--changes every hour--is that what I really want is
> to parse the data into a bunch of generic id3-frame objects. Each
> frame starts with a tag and a length field and then 'length' more
> bytes of data, I can make classes like:
> 
>   (defclass id3v2.2-frame ()
>     ((tag :initarg :tag :reader tag)
>      (length :initarg :length :accessor length)))
> 
>   (defclass generic-id3v2.2-frame (id3v2.2-frame)
>     ((data :initarg :data :accessor data)))
> 
> 
> and then create instances of generic-id3v2.2-frame that hold the data
> as raw bytes. At this point I'll know what kinds of frames I have
> (based on the values of 'tag') and can lazily parse the data in any
> given frames when I actually need it. At that point using change-class
> and update-instance-for-different-class seems like a reasonably way to
> go, to convert the raw bytes of 'data' in a generic-id3v2.2-frame to
> whatever structured form is implied by the specific type of frame.
> Assuming I have a hash table of 'tag' to classes, maybe something
> like:
> 
>   (defun convert-frame (generic-frame)
>     (change-class 
>       generic-frame
>       (gethash (tag generic-frame) *frame-classes*)))

Oh. Lazy conversion. OK, you have the tag (I am guessing) before you 
make the instance, so just make the right class of instance straightway.

Then just:

(defmethod data :around (frame)
   (if (data-converted-p frame) ;; new slot (if nec.)
      (call-next-method)
      (setf (slot-value frame 'data)
               (convert-data frame (slot-value frame 'data))
            (data-converted-p frame) t)))


-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Everything is a cell." -- Alan Kay
From: Peter Seibel
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <m3fzmyhij9.fsf@javamonkey.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> Peter Seibel wrote:
> > Kenny Tilton <·······@nyc.rr.com> writes:
> >
> 
> >>>>>"Peter Seibel" <·····@javamonkey.com> wrote in message ···················@javamonkey.com...
> >>>>>
> >>>>>
> >>>>>>>(apply #'make-instance actual-class data)
> >>>>>>
> >>>>>>Yup. That was what I was thinking of. The only trick there is then I
> >>>>>>have to keep track of where I am in the "parse" to know how to parse
> >>>>>>the next bits; ...
> >>>>>
> >>But that requires only one state variable, say, instance-class. I can
> >>imagine there must be in your parser a lot of code like:
> >>
> >>
> >>     (setf (slot-x new-thing) newest-parsed-value)
> >>
> >>ie, you want to populate the slots as you go, not have them in state
> >>variables later passed to make-instance as initargs.
> > Well, the problem--as I see it--is not where to stash the values but
> 
> > how to know how to decode the next parsed value (is it going to be a
> > unsigned byte, or a string, or what?) until I know what kind of thing
> > I'm trying to read.
> 
> I should confess that this is where I get lost. I am imagining a nice
> little finite state machine parser, which as a matter of course reads
> a little data and enters a new state, perhaps also stashing some
> supporting state. The only complexity I see is that the tokenizer has
> to look at the current state to decide how to parse the binary stuff.
> That can be a case statement (in which several cases will share the
> same parsing logic, which is logically driven by what is in the MP3,
> not the class hierarchy you choose to make out of the MP3).

Right. Using classes is just a way to *implement* the FSM. The
"current state" is captured by what class I happen to be dealing with
and I get to stash the "supporting state" in the slots of the object.

Maybe I should ask you this: how would *you* actually implement such a
FSM in Lisp? (I.e. I'm not asking because I can't think of a handful
of ways to do it--I'm asking because I'm interested in how *you*, or
anyone else who thinks they have a good way to represent FSMs in Lisp,
does it.)

> >>I could stop there, but another Bad Sign is that your intended
> >>parser of this MP3 stuff is now more a conduit from MP3 to one
> >>very specific class hierarchy.

> > I'm not sure why this is a Bad Sign. My *goal* is to have an
> > object representation of the stuff in an ID3 tag so I can get at
> > the data easily. I'm designing the class hierarchy to suit my
> > needs--why wouldn't I want to get the data into that class
> > hierarchy?
> 
> Build it (an intermediate lightweight representation of the MP3
> data) and they (other uses) will come. Mind you, at this point I am
> handwaving about a general approach to problems: break the one
> process I have to do now into two steps, to decouple parsing from
> the end product I want, so as to reap vaguely imagined /possible/
> benefits.

I think I get--in a handwaving sort of way--what you're getting at but
I'm not sure it applies in this case. At any rate, I don't have any
idea what "lightweight reperesentation" I would use that would be more
convenient than the objects I'm trying to create.

I can certainly imagine how to write a parser that builds up a plist
or something of tagged data and then how I would later create
instances of my classes from those plists. But I just don't see what
I'm winning. Especially if using the automatic dispatching provided by
specialized methods makes writing the parser easier. (Though that's
yet to be demonstrated. ;-))

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Thomas F. Burdick
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <xcvu1be7amg.fsf@famine.OCF.Berkeley.EDU>
Peter Seibel <·····@javamonkey.com> writes:

> Right. Using classes is just a way to *implement* the FSM. The
> "current state" is captured by what class I happen to be dealing with
> and I get to stash the "supporting state" in the slots of the object.
> 
> Maybe I should ask you this: how would *you* actually implement such a
> FSM in Lisp? (I.e. I'm not asking because I can't think of a handful
> of ways to do it--I'm asking because I'm interested in how *you*, or
> anyone else who thinks they have a good way to represent FSMs in Lisp,
> does it.)

Where you're using STANDARD-INSTANCE object identity, I've ended out
usinf cons-cell object identity.

> I think I get--in a handwaving sort of way--what you're getting at but
> I'm not sure it applies in this case. At any rate, I don't have any
> idea what "lightweight reperesentation" I would use that would be more
> convenient than the objects I'm trying to create.
> 
> I can certainly imagine how to write a parser that builds up a plist
> or something of tagged data and then how I would later create
> instances of my classes from those plists. But I just don't see what
> I'm winning.

Some idea of the performance of the system.  CHANGE-CLASS is *great*,
in theat it exists, and works.  I have no qualms (anymore) about using
it where I feel it's needed or justified, so long as it's a very
infrequent operation.  Basically, if it can solve some edge cases, and
thus allow me to use a simpler algorithm, I use it.

> Especially if using the automatic dispatching provided by
> specialized methods makes writing the parser easier. (Though that's
> yet to be demonstrated. ;-))

Oh, I definately found that using methods to dispatch on type made my
code much nicer to write.  Until I realized that I should be using
much more macrology.  Put a big, thick layer of macros between
yourself and the dispatch mechanism, and *poof* -- the advantage goes
away.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kenny Tilton
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <3ED54447.1020307@nyc.rr.com>
Peter Seibel wrote:
> Right. Using classes is just a way to *implement* the FSM. The
> "current state" is captured by what class I happen to be dealing with
> and I get to stash the "supporting state" in the slots of the object.
> 
> Maybe I should ask you this: how would *you* actually implement such a
> FSM in Lisp? (I.e. I'm not asking because I can't think of a handful
> of ways to do it--I'm asking because I'm interested in how *you*, or
> anyone else who thinks they have a good way to represent FSMs in Lisp,
> does it.)

Oh, i thought the crux of the matter was the lazy parsing of the raw 
data (hence I should have deleted the first 90% of my last post!). Anyway...

Well, I have not had to do an FSM in lisp, so your ideas are as good as 
mine. Off the top of my head I'd express states and transiton routines 
as symbols and store transitions in a hashtable keyed on the 
currentstate-token pair, stash everything in a nice fat FSM struct with 
room for whatever other state is necessary.

> I think I get--in a handwaving sort of way--what you're getting at but
> I'm not sure it applies in this case. At any rate, I don't have any
> idea what "lightweight reperesentation" I would use that would be more
> convenient than the objects I'm trying to create.
> 
> I can certainly imagine how to write a parser that builds up a plist
> or something of tagged data and then how I would later create
> instances of my classes from those plists. But I just don't see what
> I'm winning. 

Speed, and de-coupling from the semantics of the class hierarchy. Of 
course if your hierarchy is a CLOS mirroring of MP3, then the answer is 
just "speed". I like CLOS and beat on it like I was its daddy, but it 
can be overkill.

-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Everything is a cell." -- Alan Kay
From: Thomas A. Russ
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <ymik7c9n3r1.fsf@sevak.isi.edu>
We have used just this approach in the Loom(tm) Knowledtge
Representation language to handle certain types of forward reference.
For example, one is able to create sets of any object: concepts,
relations, instances, etc.  Supporting the forward references means that
when we encounter the name of such an object, we don't know what type of
object it will be yet.  So we create an instance object.  If we then
later discover that it should be a concept or relation (when we finally
encounter the definition), then we use change-class to substitute the
correct object type without having to manually track down all the
pointers to the instance from other parts of the knowledge base. 


-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
Loom is a trademark of the University of Southern California
From: james anderson
Subject: Re: Reasonable use of change-class?
Date: 
Message-ID: <3ED69994.E0757504@setf.de>
"Thomas A. Russ" wrote:
> 
> We have used just this approach in the Loom(tm) Knowledtge
> Representation language to handle certain types of forward reference.
> For example, one is able to create sets of any object: concepts,
> relations, instances, etc.  Supporting the forward references means that
> when we encounter the name of such an object, we don't know what type of
> object it will be yet.  So we create an instance object.  If we then
> later discover that it should be a concept or relation (when we finally
> encounter the definition), then we use change-class to substitute the
> correct object type without having to manually track down all the
> pointers to the instance from other parts of the knowledge base.

the forward reference issues were only part of the original topic.
another aspect was to use the successively changing provisional class to
control the processing. it's as if, to express it in terms of loom, each
additional piece of information which refined the definition would cause an
immediate change-class, and thereby change the instance's subsequent
interaction with further information.

while this does not seem inappropriate for a domain such as knowledge
representation, it is not as convincing an approach to implementing control in
a parser. to the extent that the search space for a parser is static, both
within the scope of a single parse and over an implementation cycle, to use
objects in that manner seems to too similar to computed goto statements in
fortran. 

...