Jonathan S. Shapiro wrote:

Oh boy do I owe Constantine an apology! Just goes to prove that too much
coffee and too little sleep can make you really really stupid! Also
obnoxious. :-)

So first, Constantine is right. We need something like what he is
calling "facets." As I thought about I/O today, I realized (a) why we
need them and (b) that we already have them (sort-of).

For all externally observable purposes, a facet is simply a structure
all of whose member fields are procedures. For example:

(defstruct trivstream
get : (fn () char)
put : (fn (char) ()))


In my proposal there is an additional field.

(defstruct trivstream
  data : pointer-sized-integer
  get : (fn (pointer-size-integer) char)
  put : (fn (pointer-size-integer char) ()))

See below on why.

We can instantiate this using something like the following:

(local ((define repr-state (make-stream-state))
(trivstream (lambda () body-returning char)
(lambda (char) body-consuming-char)))


Closures like it have one of the folloing properties:
- allocate heap memory
- return structure of varying memory layout
- expire after exit from function
As far as I understand BitC goals, neither is good property.
- Memory allocation might be unavailble
- Different memory layouts for the function likely make code less efficient (for example by consulting some additional structure or by causing more code which lead to more cache misses)
- In IO and in exported capabilities for process there are many cases where facet has not to expire after exit from function.


In my proposal it is a bit different. The context is provided explictly rather than implicitly at it is in case with closures. Also facet datatype is small enough to be passed by value rather then by reference.

; any place including static context

(define repr-state (make-stream-state)

(define (encode-ptr repr-state) (make-int-from-pointer  repr-state))
(define (decode-ptr value) (make-int-from-pointer repr-state-type value))

;... somewhre deep in the code ...

(trivstream (encode-ptr repr-state)
(lambda (encoded-data) (define data (decode-ptr encoded-data)) body-returning char)
(lambda (encoded-data char) (define data (decode-ptr encoded-data)) body-consuming-char)))



If this corresponds behaviorally to what Constantine means by facets
(does it?) then I see two remaining issues:

1. Should there be a convenience syntax for this? [I am coming to
dislike LOCAL, but that is a side issue].


As you can see, in my case there is more complex syntax. Also there is unsafe coversion from data pointer to integer and back which I want to hide. Convience sysntax would also allows to check if all methods are implemented and to prove a meaningful error message for it.

2. Should facets differ from structures by creating a vtable-like data
structure, on the theory that the method table might grow large and can
be shared? That is, where the actual object was a struct of the form

(defstruct (facet-rep 'a)
state : 'a methods : (struct-containing-methods 'a))




Formally speacking it is:

(defstruct (facet-rep 'a 'b)
state : 'b methods : (struct-containing-methods 'a))


Note that different implementation of the same facet type will use different 
state. In facet design I'm attempting to make the structure an assignment 
compatible. So instead it is:

(defstruct (facet-rep 'a)
state-ptr : pointer-sized-integer methods : (struct-containing-methods 'a))




the only difference between this and the structure form would be
implicitly performing the insertion of the arguments.

For the moment, I think that the right thing to do is do this using
structures until we have a better sense of what we need.


In case when there is only one function, the facet might trivially optimized by replacing vtable with pointer to this fuction.

Note that due to memory allocation constraints of the language such structure has to be passed by value (flyweight design pattern). I have tried to make the thing uniform. But possibly it does not have to be so. Possibly there should be an annotation that specifies whether facet should reference vtable or embed it. If vtable is embedded, facets of the same type will still be assignment compatible.

BTW Vtables are also good candidates for read-only memory segments. This may simplify some proofs.

Constantine
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to