From: ·······@gmail.com
Subject: make-instance inherited class
Date: 
Message-ID: <1174395275.023484.11870@e1g2000hsg.googlegroups.com>
Hi,

I want to read a file with lots of different objects and make the
objects in lisp. I have made the classes and all classes derive from
one superclass.  All classes have different slots, who are unique for
their class.
The problem is: in the file the objects are not in a specific order.
Is there a way for me to make the objects without knowing which class
they belong to?  Is there a way for lisp to detect which slots are
used, and make the objects like that?

From: Pascal Costanza
Subject: Re: make-instance inherited class
Date: 
Message-ID: <56a49dF277tkeU1@mid.individual.net>
·······@gmail.com wrote:
> Hi,
> 
> I want to read a file with lots of different objects and make the
> objects in lisp. I have made the classes and all classes derive from
> one superclass.  All classes have different slots, who are unique for
> their class.
> The problem is: in the file the objects are not in a specific order.
> Is there a way for me to make the objects without knowing which class
> they belong to?  Is there a way for lisp to detect which slots are
> used, and make the objects like that?

A trivial way would be to have a hash table that maps slot names to 
class names. But maybe that's too simple.

Can you provide examples of what's in such a file and what the class 
definitions look like?

Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: ·······@gmail.com
Subject: Re: make-instance inherited class
Date: 
Message-ID: <1174396575.914352.60290@y80g2000hsf.googlegroups.com>
> A trivial way would be to have a hash table that maps slot names to
> class names. But maybe that's too simple.
>
> Can you provide examples of what's in such a file and what the class
> definitions look like?

Thanks for the quick response.

example:
superclass:
(defclass superclass ()
  ((id :accessor id)
   (name :accessor name)))
class1:
(defclass class1 (superclass)
 ((comment :accessor comment)
  (number1 :acessor number1)))

class2:
(defclass class2 (superclass)
 ((biblio :accessor biblio)
  (number2 :accessor number2)))

file:
-----
(id1 (
 (name "nameobj1")
 (comment "blablabla")))

(id2 (
 (name "nameobj2")
 (id "obj2")
 (number1 "1.2.3")))

(id3 (
 (id "obj3")
 (number2 "2.2.2")))

Not all the slots from the class are given a value.
So id1 and id2 should be objects of class1 and id3 should be of
class2.
From: Wade Humeniuk
Subject: Re: make-instance inherited class
Date: 
Message-ID: <pGRLh.112049$Du6.52011@edtnps82>
The condition system is your friend,  you can attempt to make-instance
for the class and on failure handle the problem and try something else.
All the information is held within the class definitions, let the
system do the work determining if it can be instantiated.

(defclass superclass ()
   ((id :accessor id :initarg id :initarg :id)
    (name :accessor name :initarg name :initarg :name)))

(defclass class1 (superclass)
  ((comment :accessor comment :initarg comment)
   (number1 :accessor number1 :initarg number1)))

(defclass class2 (superclass)
  ((biblio :accessor biblio :initarg biblio)
   (number2 :accessor number2 :initarg number2)))

(defun flatten-list (list)
   (loop for obj in list
         if (listp obj) nconc obj
         else nconc (list obj)))

(defun make-id-list (list)
   (cons 'id (cons (car list) (flatten-list (cadr list)))))


(defun attempt-make-instance (class args)
   (handler-case
       (apply #'make-instance class args)
     (#+lispworks conditions:unknown-keyword-error () nil)))

(defun convert-id-to-instance (id &aux (id-list (make-id-list id)))
   (or (attempt-make-instance 'class1 id-list)
       (attempt-make-instance 'class2 id-list)
       nil))

CL-USER 12 > (convert-id-to-instance '(id2 (
  (name "nameobj2")
  (id "obj2")
  (number1 "1.2.3"))))
#<CLASS1 20674F84>

CL-USER 13 > (convert-id-to-instance '(id3 (
  (id "obj3")
  (number2 "2.2.2"))))
#<CLASS2 2068734C>

CL-USER 14 > (convert-id-to-instance '(id1 (
  (name "nameobj1")
  (comment "blablabla"))))
#<CLASS1 20670654>

Wade
From: ·······@gmail.com
Subject: Re: make-instance inherited class
Date: 
Message-ID: <1174466279.639706.46540@l75g2000hse.googlegroups.com>
On 20 mrt, 14:52, Wade Humeniuk <··················@telus.net> wrote:
> The condition system is your friend,  you can attempt to make-instance
> for the class and on failure handle the problem and try something else.
> All the information is held within the class definitions, let the
> system do the work determining if it can be instantiated.
>
> (defclass superclass ()
>    ((id :accessor id :initarg id :initarg :id)
>     (name :accessor name :initarg name :initarg :name)))
>
> (defclass class1 (superclass)
>   ((comment :accessor comment :initarg comment)
>    (number1 :accessor number1 :initarg number1)))
>
> (defclass class2 (superclass)
>   ((biblio :accessor biblio :initarg biblio)
>    (number2 :accessor number2 :initarg number2)))
>
> (defun flatten-list (list)
>    (loop for obj in list
>          if (listp obj) nconc obj
>          else nconc (list obj)))
>
> (defun make-id-list (list)
>    (cons 'id (cons (car list) (flatten-list (cadr list)))))
>
> (defun attempt-make-instance (class args)
>    (handler-case
>        (apply #'make-instance class args)
>      (#+lispworks conditions:unknown-keyword-error () nil)))
>
> (defun convert-id-to-instance (id &aux (id-list (make-id-list id)))
>    (or (attempt-make-instance 'class1 id-list)
>        (attempt-make-instance 'class2 id-list)
>        nil))
>
> CL-USER 12 > (convert-id-to-instance '(id2 (
>   (name "nameobj2")
>   (id "obj2")
>   (number1 "1.2.3"))))
> #<CLASS1 20674F84>
>
> CL-USER 13 > (convert-id-to-instance '(id3 (
>   (id "obj3")
>   (number2 "2.2.2"))))
> #<CLASS2 2068734C>
>
> CL-USER 14 > (convert-id-to-instance '(id1 (
>   (name "nameobj1")
>   (comment "blablabla"))))
> #<CLASS1 20670654>
>
> Wade

Hi

I've tried it like you said, but it doesn't work.  When the object I'm
trying to make is not from the first class I try, I get an error.
When I test your code, I also get an error when I try to make the
object for the second class:
(convert-id-to-instance '(id3 (
  (id "obj3")
  (number2 "2.2.2"))))

Error:
"Invalid initialization argument:
  NUMBER2
in call for class #<STANDARD-CLASS CLASS1>.
    [Condition of type SB-PCL::INITARG-ERROR]"

Inge
From: ·······@gmail.com
Subject: Re: make-instance inherited class
Date: 
Message-ID: <1174468714.715129.232680@e65g2000hsc.googlegroups.com>
Ok, with (error () (values nil)) at the end of the handler-case, it
works.
Thanks!
From: Wade Humeniuk
Subject: Re: make-instance inherited class
Date: 
Message-ID: <RQaMh.114234$Du6.24806@edtnps82>
·······@gmail.com wrote:
> Ok, with (error () (values nil)) at the end of the handler-case, it
> works.
> Thanks!
> 

Do you understand why it works?  From the trace from your
previous post

(sb-pcl::initarg-error () (values nil))

should also work.

You must have noticed (and removed) the #+lispworks from my
original.

Wade
From: ·······@gmail.com
Subject: Re: make-instance inherited class
Date: 
Message-ID: <1174487051.128476.187800@o5g2000hsb.googlegroups.com>
> Do you understand why it works?  From the trace from your
> previous post
>
> (sb-pcl::initarg-error () (values nil))
>
> should also work.
>
> You must have noticed (and removed) the #+lispworks from my
> original.
>
> Wade

It threw a different error, no?
Thanks

I have another problem: in the file there is a line ' (OG::PARENTS |
bal|) )'
(id3 (
(name "name")
(comment "kmljsdfs")
(OG::PARENTS |bkjsq|))

When I read it, it searches for a package OG and gives me a READER-
ERROR, I want to just skip the line when I get the error, but I'm
using (loop for l = (read input nil) .....).
Is there a way I get the rest of my lines into l, without getting the
error?
From: Wade Humeniuk
Subject: Re: make-instance inherited class
Date: 
Message-ID: <B2fMh.4$x9.0@edtnps89>
·······@gmail.com wrote:

> I have another problem: in the file there is a line ' (OG::PARENTS |
> bal|) )'
> (id3 (
> (name "name")
> (comment "kmljsdfs")
> (OG::PARENTS |bkjsq|))
> 
> When I read it, it searches for a package OG and gives me a READER-
> ERROR, I want to just skip the line when I get the error, but I'm
> using (loop for l = (read input nil) .....).
> Is there a way I get the rest of my lines into l, without getting the
> error?
> 

The simplest way is to defpackage the missing package and then....

(unless (find-package "OG")
   (defpackage :og))

(defclass superclass ()
   ((id :accessor id :initarg id :initarg :id)
    (name :accessor name :initarg name :initarg :name)))

(defclass class1 (superclass)
  ((comment :accessor comment :initarg comment)
   (number1 :accessor number1 :initarg number1)))

(defclass class2 (superclass)
  ((biblio :accessor biblio :initarg biblio)
   (number2 :accessor number2 :initarg number2)))

(defun flatten-list (list)
   (loop for obj in list
         if (listp obj) nconc obj
         else nconc (list obj)))

(defun make-id-list (list)
   (cons 'id (cons (car list) (flatten-list (cadr list)))))

(defun attempt-make-instance (class args)
   (handler-case
       (apply #'make-instance class args)
     (#+lispworks conditions:unknown-keyword-error () nil)))

(defun convert-id-to-instance (id &aux (id-list (make-id-list id)))
   (remf id-list 'og::parents)
   (or (attempt-make-instance 'class1 id-list)
       (attempt-make-instance 'class2 id-list)
       nil))

CL-USER 1 > (convert-id-to-instance '(id3 (
(name "name")
(comment "kmljsdfs")
(OG::PARENTS |bkjsq|))))
#<CLASS1 2069391C>

CL-USER 2 >

Wade
From: Vassil Nikolov
Subject: Re: make-instance inherited class
Date: 
Message-ID: <m3slbygfob.fsf@localhost.localdomain>
On 21 Mar 2007 07:24:11 -0700, ·······@gmail.com said:
| ...
| I have another problem: in the file there is a line ' (OG::PARENTS |
| bal|) )'
| (id3 (
| (name "name")
| (comment "kmljsdfs")
| (OG::PARENTS |bkjsq|))

| When I read it, it searches for a package OG and gives me a READER-
| ERROR, I want to just skip the line when I get the error, but I'm
| using (loop for l = (read input nil) .....).
| Is there a way I get the rest of my lines into l, without getting the
| error?

  Assuming that ignoring a missing (or mis-spelt) package is indeed
  appropriate in the case at hand (it usually isn't, but you know what
  you are doing), one way may be to establish (a) a restart that
  resumes the loop and (b) a handler for READER-ERROR which invokes
  that restart.

  ---Vassil.


-- 
The truly good code is the obviously correct code.
From: ·······@gmail.com
Subject: Re: make-instance inherited class
Date: 
Message-ID: <1174556395.871167.298160@d57g2000hsg.googlegroups.com>
>   Assuming that ignoring a missing (or mis-spelt) package is indeed
>   appropriate in the case at hand (it usually isn't, but you know what
>   you are doing), one way may be to establish (a) a restart that
>   resumes the loop and (b) a handler for READER-ERROR which invokes
>   that restart.
>

I really don't need the line, so I just want to skip it.
How do I restart it without losing the previous lines?
I'm now using a read, that reads a whole list, which is one object.
So something like this:
(loop for l = (handler-case (read input nil)
                 (reader-error () ......))
I don't know how to restart the read so it keeps the lines he already
read.
Thanks for your help
From: Vassil Nikolov
Subject: Re: make-instance inherited class
Date: 
Message-ID: <m3lkhncodf.fsf@localhost.localdomain>
On 22 Mar 2007 02:39:55 -0700, ·······@gmail.com said:

|| Assuming that ignoring a missing (or mis-spelt) package is indeed
|| appropriate in the case at hand (it usually isn't, but you know what
|| you are doing), one way may be to establish (a) a restart that
|| resumes the loop and (b) a handler for READER-ERROR which invokes
|| that restart.
|| 

| I really don't need the line, so I just want to skip it.
| How do I restart it without losing the previous lines?
| I'm now using a read, that reads a whole list, which is one object.
| So something like this:
| (loop for l = (handler-case (read input nil)
|                  (reader-error () ......))
| I don't know how to restart the read so it keeps the lines he already
| read.

  Well, you are right, it is more involved than my little hurried
  sketch.  I think it can be done without undue effort, but it is a
  hard week's night; I'll try to follow up over the weekend.

  ---Vassil.


-- 
The truly good code is the obviously correct code.
From: Vassil Nikolov
Subject: Re: make-instance inherited class
Date: 
Message-ID: <m3hcs8dcsd.fsf@localhost.localdomain>
On 23 Mar 2007 22:27:24 -0500, Vassil Nikolov <···············@pobox.com> said:
| ...
|   I think it can be done without undue effort

  Well, "undue" is a nicely fuzzy notion; besides, I can't say I am
  sufficiently happy with the code below, but it may serve.  (I
  suppose in the proverbial perfect world, READ would be specified to
  define some useful restarts.  Here, we roll our own, in a somewhat
  half-hearted way.)

  The idea is to call READ-SKIPPING-SPURIOUS-OBJECTS instead of READ
  in the loop that consumes the lists from which objects are to be
  created (see also the "demo" cases at the end).  Disclaimer: this
  code is really only a proof of concept [1], and I have only verified
  it in limited ways.

  [1] You probably don't want to change the default readtable as the
      call to SET-MACRO-CHARACTER does below.


  (defun read-skipping-spurious-objects (&optional stream (eof-error-p t) eof-value recursive-p)
    "Read and return the next \"good\" object, skipping any that do not read cleanly."
    (multiple-value-bind (object errors)
                         (read-even-with-errors stream eof-error-p eof-value recursive-p)
      (if errors (read-skipping-spurious-objects stream eof-error-p eof-value recursive-p)
        object)))

  (declaim (special *ignored-errors*))

  (defun read-even-with-errors (&optional stream (eof-error-p t) eof-value recursive-p)
    "Read an object and return it together with a list of any (accumulated) errors.
  This is only useful in conjunction with TOLERANT-LIST-READER."
    (let* ((*ignored-errors* '())
           ;; this implicitly calls READ-LIST-WITH-RESTART-FOR-REST when
           ;; TOLERANT-LIST-READER is set as the left-parenthesis reader:
           (object (read stream eof-error-p eof-value recursive-p)))
        (values object *ignored-errors*)))

  (defun read-list-with-restart-for-rest (&optional stream recursive-p)
    "Read a right-parenthesis-delimited list, establishing a READ-REST restart.
  Invoking that restart would cause the remaining unread part of the list to
  be consumed and returned."
    (loop (restart-case (return (read-list-ignoring-errors stream recursive-p))
            (read-rest ()))))

  (defun read-list-ignoring-errors (&optional stream recursive-p)
    "Read a right-parenthesis-delimited list, ignoring errors other than EOF.
  Should be called in the dynamic extent of a call to READ-EVEN-WITH-ERRORS.
  Requires the READ-REST restart as established by READ-LIST-WITH-RESTART-FOR-REST."
    (handler-case (read-delimited-list #\) stream recursive-p)
      (end-of-file (c) (error c))  ;this cannot be ignored
      ;; we would only like to handle PARSE-ERROR (or READER-ERROR)
      ;; here, but this is implementation-dependent territory...
      (error (c)
        (push c *ignored-errors*)
        (invoke-restart 'read-rest))))

  (defun tolerant-list-reader (stream char)
    "The left-parenthesis reader that ignores errors in the list."
    (declare (ignore char))
    (read-list-with-restart-for-rest stream t))

  (set-macro-character #\( #'tolerant-list-reader)

  ;; a few test cases (to illustrate):

  (with-input-from-string (s "foo bar baz)")
    (let (*ignored-errors* '())
      (values (read-list-with-restart-for-rest s) *ignored-errors*)))

  (with-input-from-string (s "foo x::bar baz)")
    (let (*ignored-errors* '())
      (values (read-list-with-restart-for-rest s) *ignored-errors*)))

  (with-input-from-string (s "(foo (bar) baz)")
    (read-even-with-errors s))

  (with-input-from-string (s "(foo (x::bar) baz)")
    (read-even-with-errors s))

  (with-input-from-string (s "(foo (bar) baz) (quux)")
    (read-skipping-spurious-objects s))

  (with-input-from-string (s "(foo (x::bar) baz) (quux)")
    (read-skipping-spurious-objects s))


  ---Vassil.


-- 
The truly good code is the obviously correct code.