Shen-Language / shen-cl

Shen for Common Lisp (Unmaintained)
BSD 3-Clause "New" or "Revised" License
122 stars 11 forks source link

I/O error in underlying platform while running on Clozure #12

Open bluejay77 opened 6 years ago

bluejay77 commented 6 years ago

I m creating a Shen OO capability based on Paul Graham's book On Lisp, Ch 25, Object-Oriented LISP.

A version of this capability is in the file oo.shen.

An attempt to track the function (create-class...) makes Shen crash:

Shen, copyright (C) 2010-2015 Mark Tarver
www.shenlanguage.org, Shen 21
running under Common Lisp, implementation: Clozure CL
port 2.2 ported by Mark Tarver

(0-) (load "oo.shen")
putp
getp
defclass-macro
oo.process-slots
instance
oo.type#o-o
oo.attribute-type
class?
oo.create-class
instance
assign
cl-slots
cl-parents
cl-name
make-instance
iget
iput
[]

run time: 0.4719999972730875 secs
loaded

(1-) (track oo.create-class)
oo.create-class

(2-) (step +)
true

(3-) (defclass int (object) val number 0) \\ integer class

 <1> Inputs to oo.create-class 
 int, [object], [[val 0]],  ==>The value #<BASIC-CHARACTER-INPUT-STREAM UTF-8 (TTY/0) #x3020006233FD> is not of the expected type (AND INPUT-STREAM CCL::BINARY-STREAM).

yours, Dr Antti J Ylikoski Helsinki, Finland, the EU

I did not find a way to attach a file, I will insert the Shen code below:

(package oo [defclass defclass-macro assign instance attribute class
              make-instance iget iput object
          cl-slots cl-parents cl-name
          class?
          putp getp ]

(define putp
    Obj Prop Val ->
        (lisp.setf (lisp.get Obj Prop) Val))

(define getp
    Obj Prop ->
        (lisp.get Obj Prop))

\\ (defclass class-name (list of superclasses) (list of slots))

(defmacro defclass-macro
  [defclass Class SuperClasses | Slots] 
  -> (create-class Class SuperClasses (process-slots Class Slots)))

(define process-slots
  Class [Attribute Type Value] -> \\ one slot?
      (do
          (putp Class Attribute Type) \\ stored as properties
          [[Attribute Value]])
  Class [Attribute Type] -> \\ without the value
      (do
          (putp Class Attribute Type) [[Attribute]]) 
  Class [Attribute Type Value , | Slots] -> \\ a list of slots?
      (do
          (putp Class Attribute Type)
          [[Attribute Value] | (process-slots Class Slots)])
  Class [Attribute Type , | Slots] -> \\ list of slots?
      (do
          (putp Class Attribute Type)
          [[Attribute] | (process-slots Class Slots)])
  Class [] -> [[]] \\ no slots: modify nothing
  Class _  -> \\ otherwise: there is a syntax error
      (error "syntax error in class definition of ~A~%" Class))

(declare instance [[class Class] --> [instance Class]])

(datatype o-o

  if (class? Class)
  ______________________
  Class : (class Class);

  if (= (attribute-type Class Attribute) Type)
  __________________________________
  Attribute : (attribute Class Type);

  Instance : (instance Class);
  Value : A;
  Attribute : (attribute Class A);
  _____________________________________________________ 
  (assign Instance Attribute Value) : (instance Class);)

(define attribute-type
  Class Attribute -> (trap-error (getp  Class Attribute) (/. E [])))     

(define class?
  Class -> (cons? (trap-error (getp  Class slots) (/. E false))))  

(define create-class
  Class SuperClasses Slots ->
      (let SuperSlots (mapcan (function instance) SuperClasses)
           ClassSlots (append Slots SuperSlots)
           Create (putp Class slots ClassSlots) \\ property slots: list
       Paren (putp Class parents SuperClasses) \\ super i e parents
       Name (putp Class class-name Class) \\ her name
           Class))

\\ instance creates an instance of the class,
\\ which is a list of lists

(define instance
  Class -> (getp  Class slots))

\\ assign assigns the value of a slot of an instance

(define assign
  [[Attribute | _] | Slots] Attribute Value ->
      [[Attribute Value] | Slots]
  [Slot | Slots] Attribute Value ->
      [Slot | (assign Slots Attribute Value)])

\\ Call: (cl-slots classname)

(define cl-slots
    Class -> (getp Class slots))

(define cl-parents
    Class -> (getp Class parents))

(define cl-name
    Class -> (getp Class class-name))

\\ Call: (set my-instance (make-instance object))
\\ Returns the class object which is the representation of the
\\ class instance

(define make-instance
    Class ->
    (let
        Ignore (putp
               Class
           instanceSlots
           (instance (value Class)))
    Class))

\\ Call: (iget (value my-instance) slot-name)

(define iget
    InstanceName SlotName ->
    (head (tail (head (assoc SlotName
                             (getp  InstanceName instanceSlots))))))

\\ Call: (iput (value my-instance) slot-name value)

(define iput
    InstanceName SlotName Val ->
    (let
        Lst (getp  InstanceName instanceSlots)
    NewLst (assign Lst SlotName Val)
    (putp InstanceName instanceSlots NewLst)))

\*

object is the common superclass of all objects.  The class object is
its own superclass, ie. parent AJY 2018-04-18

*\

(do
    (putp object slots [])
    (putp object parents [object]) \\ super i e parents: her own super
    (putp object class-name object) \\ her name
    [])

)
rkoeninger commented 6 years ago

@bluejay77 I trimmed down your code mainly by removing comments. It's easier to diagnose when we have only the code that causes this particular problem. If the defclass macro is blowing up, then we probably only need defclass-macro, create-class, process-slots and putp to reproduce the error.

Also, I'm not getting the error with the version of shen-cl/sbcl that's current in the master branch. We can try this again once we've merged in the fix for #13 , since this approach to oo uses lisp. native calls.

rkoeninger commented 6 years ago

@tizoc I just tried loading the above code with the latest in master (with #15 merged) and got this:

(0-) (load "oo.shen")
putp
getp
defclass-macro
oo.process-slots
instance
oo.type#o-o
oo.attribute-type
class?
oo.create-class
instance
assign
cl-slots
cl-parents
cl-name
make-instance
iget
iput
The function COMMON-LISP-USER::oo.lisp.get is undefined.

The macro would have converted this to (protect GET) and prevent the parser from trying to qualify with the package name. The package prefix must get added after macros are applied, but before the code gets compiled.

Is this a problem introduced by the change from earlier or is this the expected behavior? Does one have to list every external symbol in the package declaration? I never completely understood the package macro.

tizoc commented 6 years ago

I didn't think about this when making the change, but yes, the behaviour change comes with the modification.

Not sure about what the "correct" behaviour should be, in Shen/Scheme it behaves as you are seeing now, the idea being that the scm. prefix is just a namespace, and not something special, so like with everything else you have to list scm. prefixed functions in the export list if you want to use them inside a package (see https://github.com/tizoc/shen-scheme/blob/master/src/compiler.shen#L8-L10 for an example).

I like how that works, but I understand that it is not very convenient, and breaking the old behaviour is a problem. What I'm thinking now is that Shen/CL could override sysfunc? so that it checks for the lisp. prefix in addition to the list of functions being declared as system functions. That solves the issue you are seeing here while providing a better error message (this is something that in the old version would fail anyway but with a confusing error like [protect UPPERCASENAME] is not a legitimate function name).

I'm going to do that in Shen/Scheme because I just noticed that by not doing so I leave open the option of overriding native functions, and that breaks stuff:

(0-) (define scm.+ X Y  -> (- X Y))
scm.+

(1-) (+ 1 2)
-1

What do you think? sounds good?

rkoeninger commented 6 years ago

What I'm thinking now is that Shen/CL could override sysfunc? so that it checks for the lisp.

I guess that would work in this case.

(I get a little confused about the behavior of the package macro and prefixes here...)

What about non-interop functions? If I have a package p and a package q and I refer to p.f inside of q, would I have to declare p.f in the export list for q? Otherwise, I'd have to refer to it as q.p.f while in q, but just p.f outside of a package? And if f was in the export list for p, where it was defined, it would never need a prefix? Could sysfunc? just always return true for a symbol with a . in the name?

(Deleted some ranting until I better understand the issue)

tizoc commented 6 years ago

You have to declare everything that is not a sysfunc in the export list, otherwise it is going to be prefixed. For names internal to other packages you can just use (internal package-name) to obtain it instead of having to list everything:

(0-) (package test-1 [exported-func] 
       (define internal-func X -> X) 
       (define exported-func X -> X))
test-1.internal-func
exported-func

(1-) (external test-1)
[exported-func]

(2-) (internal test-1)
[test-1.internal-func]

(3-) (package test-2 [exported-func-2 | (internal test-1)]
       (define exported-func-2 X -> (test-1.internal-func X)))
exported-func-2

(4-) (exported-func-2 1)
1

(5-) (internal test-2)
[]

(6-) (external test-2)
[exported-func-2 test-1.internal-func]

Note that internal will not work with shen. prefixed functions (that data is not keep around). It is not great, but it works.

Consider that It is not something we should change anyway, it would just make Shen BSD incompatible with Shen Professional, so just accept it for what it is and don't get stressed over it.

If I were to use Shen for bigger programs I would probably just write my own thing to better organise code instead of depending on package, which is just some useful but rudimentary functionality provided by a few lines of code in the kernel.

rkoeninger commented 6 years ago

@tizoc Seems weird to me, but not a huge deal. I never written enough Shen to need packages.

The lisp. prefix issue I noticed while looking at this unrelated issue, so I think we need to issue a new issue and move this there.

rkoeninger commented 6 years ago

@bluejay77 I forgot for a moment that this issue is actually about the error The value #<BASIC-CHARACTER-INPUT-STREAM UTF-8 (TTY/0) #x3020006233FD> is not of the expected type (AND INPUT-STREAM CCL::BINARY-STREAM).

I haven't been able to reproduce this with ccl, sbcl or clisp using what's currently in the master branch.

Have you seen this more than once? Does it happen reliably? It might be something with your terminal - do you use anything special for your terminal? What OS and OS version are you using?

bluejay77 commented 6 years ago

I have seen the error several times. It happens repeatedly. The terminal is a standard one I think.... Will try to change it to another one, however. I use the Debian Linux, I think v.9.4.0.

AJY

bluejay77 commented 6 years ago

I changed the terminal to another one. The "mystic" error will not occur any more.

Weird. Bug with the Linux Debian? I don't know!

AJY

rkoeninger commented 6 years ago

FYI, I was able to reproduce this on Ubuntu (derived from Debian).

This appears to happen when all of the following conditions are met: