[gambit-list] How to handle and access and interact with object members host code

Marc Feeley feeley at iro.umontreal.ca
Tue Dec 8 17:00:55 EST 2015


In the code I sent, you can use strings, symbols or keywords interchangeably for naming classes and methods.  It is just a matter of style.

Your suggestion to add a dot at the end of the variable containing an object is cute.  It can be a reminder that a variable contains an object of the host language.  Moreover you can avoid the quoting of the method names by using variables, so you could do:

(define Date 'Date)
(define getTime 'getTime)

(define o. (new Date))

(println (o. getTime))

Marc


> On Dec 8, 2015, at 3:07 AM, ben yakawp <ben.lists at yakawp.com> wrote:
> 
>> (define o (new 'Date "March 11, 1985"))
>> (println (o getTime:))
> 
> 
> that looks clear and beautiful, thank you.
> 
> Questions
> - is there a reason why you use a quoted symbol for the constructor and
> keywords for the method calls? I like it but I wonder if there are other
> reasons then aesthetic considerations.
> 
> - the other thing I was wondering. I think its common that the first
> object in unquoted s-expression is an operator. In the case of "(obj
> method args)" the rules are little confusing because the expression only
> makes sense if you have the contextual knowledge of at least the second
> object (method). Maybe a solution could be to write something like 
>    (println (o. getTime:))
> With the help of the dot it is immediately clear that the operator is in
> fact an object.
> 
> 
> 
> 
> 
> 
> 
> On Mon, Dec 7, 2015, at 10:09 PM, Marc Feeley wrote:
>> Yes the idea is to mimic the OO style.  Here’s some tested code:
>> 
>> (##declare (extended-bindings) (not safe))
>> 
>> (##inline-host-declaration "
>> 
>> function getGlobal(name) {
>>  return this[name];
>> }
>> 
>> ")
>> 
>> (define (new constructor . args)
>>  (let ((obj (create-object constructor args)))
>>    (lambda (method . args)
>>      (call-method obj method args))))
>> 
>> (define (create-object constructor args)
>>  (if (##null? args)
>>      (##inline-host-expression
>>       "new (getGlobal(@1 at .toString()))()"
>>       constructor)
>>      (let ((arg1 (##car args))
>>            (args (##cdr args)))
>>        (if (##null? args)
>>            (##inline-host-expression
>>             "new (getGlobal(@1 at .toString()))(g_scm2host(@2@))"
>>             constructor
>>             arg1)
>>            (let ((arg2 (##car args))
>>                  (args (##cdr args)))
>>              (if (##null? args)
>>                  (##inline-host-expression
>>                   "new
>>                   (getGlobal(@1 at .toString()))(g_scm2host(@2@),g_scm2host(@3@))"
>>                   constructor
>>                   arg1
>>                   arg2)
>>                  (let ((arg3 (##car args))
>>                        (args (##cdr args)))
>>                    (if (##null? args)
>>                        (##inline-host-expression
>>                         "new
>>                         (getGlobal(@1 at .toString()))(g_scm2host(@2@),g_scm2host(@3@),g_scm2host(@4@))"
>>                         constructor
>>                         arg1
>>                         arg2
>>                         arg3)
>>                        (error "too many arguments to
>>                        constructor")))))))))
>> 
>> (define (call-method obj method args)
>>  (if (##null? args)
>>      (##inline-host-expression
>>       "g_host2scm(@1@[@2 at .toString()].call(@1@))"
>>       obj
>>       method)
>>      (let ((arg1 (##car args))
>>            (args (##cdr args)))
>>        (if (##null? args)
>>            (##inline-host-expression
>>             "g_host2scm(@1@[@2 at .toString()].call(@1@,g_scm2host(@2@)))"
>>             obj
>>             method
>>             arg1)
>>            (let ((arg2 (##car args))
>>                  (args (##cdr args)))
>>              (if (##null? args)
>>                  (##inline-host-expression
>>                   "g_host2scm(@1@[@2 at .toString()].call(@1@,g_scm2host(@2@),g_scm2host(@3@)))"
>>                   obj
>>                   method
>>                   arg1
>>                   arg2)
>>                  (let ((arg3 (##car args))
>>                        (args (##cdr args)))
>>                    (if (##null? args)
>>                        (##inline-host-expression
>>                         "g_host2scm(@1@[@2 at .toString()].call(@1@,g_scm2host(@2@),g_scm2host(@3@),g_scm2host(@4@)))"
>>                         obj
>>                         method
>>                         arg1
>>                         arg2)
>>                        (error "too many arguments to method")))))))))
>> 
>> (define o (new 'Date "March 11, 1985"))
>> 
>> (println (o getTime:))
>> 
>> (println (o toString:))
>> 
>> 
>> Marc
>> 
>>> On Dec 7, 2015, at 3:17 PM, ben yakawp <ben.lists at yakawp.com> wrote:
>>> 
>>> thanks, 
>>> so the trick is to mimic the oo style in Gambit. 
>>> 
>>> 
>>> 7 (define (new-Date o)
>>> 8   (let ((obj (##inline-host-expression "new Date()")))
>>> 10   (lambda (f)
>>> 11     (f obj))))
>>> 14 
>>> 15 (define date (new-Date "Date"))
>>> 16 
>>> 17 (print (date .getTime))
>>> 
>>> 
>>> What do you think of this notation?
>>> 
>>> 
>>> 
>>> On Mon, Dec 7, 2015, at 06:00 PM, Marc Feeley wrote:
>>>> Here’s a simple example creating a JavaScript Date object and extracting
>>>> the number of milliseconds since January 1, 1970:
>>>> 
>>>> (define (new-Date)
>>>> (##inline-host-expression "new Date()"))
>>>> 
>>>> (define (.getTime obj)
>>>> (##inline-host-expression "@1 at .getTime()" obj))
>>>> 
>>>> (define o (new-Date))
>>>> 
>>>> (println (.getTime o))
>>>> 
>>>> This is possible because host objects can be used as Scheme objects (they
>>>> are opaque, but you can return them from functions, pass them as function
>>>> parameters and store them in data-structures).
>>>> 
>>>> Does that clarify things?
>>>> 
>>>> BTW, the above code can be improved quite a bit to make it more general. 
>>>> I’m just giving this example to show it is simple to interface to host
>>>> objects.
>>>> 
>>>> Marc
>>>> 
>>>> 
>>>>> On Dec 7, 2015, at 11:44 AM, ben yakawp <ben.lists at yakawp.com> wrote:
>>>>> 
>>>>> Just to be a little more precise. Expressing OO style in Scheme was not
>>>>> my primary concern here. The problem I see is that the all of the host
>>>>> languages (except the original C backend) access their library functions
>>>>> through an OO interface. It's not like the library approach in scheme
>>>>> were you can directly use a function after you imported it.
>>>>> 
>>>>> That means if you want to use a function from a host language you first
>>>>> have to create an object. But now what is this object in Scheme and what
>>>>> can it do? In the best case, it would check the member calls at compile
>>>>> time. In the worst case it add runtime cost in the backend.
>>>>> 
>>>>> But thats just stuff I was thinking about. 
>>>>> 
>>>>> What I wanted to know in the first place is how I should accessing
>>>>> backing library functions / ffing that are "hidden" behind OO apis. 
>>>>> How is this done?
>>>>> 
>>>>> 
>>>>> On Mon, Dec 7, 2015, at 05:13 PM, Marc Feeley wrote:
>>>>>> At the Scheme level, you can express the OO style in various ways.  Here
>>>>>> are 2 that come to mind:
>>>>>> 
>>>>>> 1) Your “new” operator could return a closure which receives as a first
>>>>>> parameter the name of the method to be called.  So you could:
>>>>>> 
>>>>>> (define o (new Lib))
>>>>>> (o print: "hello")
>>>>>> 
>>>>>> or
>>>>>> 
>>>>>> (define .print '.print)
>>>>>> (o .print "hello")
>>>>>> 
>>>>>> 2) You could make .print a function that receives as a first parameter
>>>>>> the object on which the method applies.  For example:
>>>>>> 
>>>>>> (define .print (lambda (self text) …))
>>>>>> (define o (new Lib))
>>>>>> (.print o "hello")
>>>>>> 
>>>>>> You can of course use macros to automate these styles.
>>>>>> 
>>>>>> Marc
>>>>>> 
>>>>>>> On Dec 7, 2015, at 8:31 AM, ben yakawp <ben.lists at yakawp.com> wrote:
>>>>>>> 
>>>>>>> hi
>>>>>>> Sorry if this too obvious, but I don't understand how gambit handles
>>>>>>> objects from the hosts backend.
>>>>>>> 
>>>>>>> 
>>>>>>> For example: if one would like to construct a 'Node' library for the JS
>>>>>>> backend, how would you do that? The whole node api seems to be object
>>>>>>> oriented.  But also the Python standard libaries (batteries) are layed
>>>>>>> out class based. You had to do something like
>>>>>>> 
>>>>>>> (define o (new Lib))
>>>>>>> (o.print "hello")
>>>>>>> 
>>>>>>> This looks wrong. What am I missing?
>>>>>>> 
>>>>>>> Regards
>>>>>>> ben
>>>>>>> _______________________________________________
>>>>>>> Gambit-list mailing list
>>>>>>> Gambit-list at iro.umontreal.ca
>>>>>>> https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
>>>>>> 
>>>> 
>>> _______________________________________________
>>> Gambit-list mailing list
>>> Gambit-list at iro.umontreal.ca
>>> https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
>> 
> _______________________________________________
> Gambit-list mailing list
> Gambit-list at iro.umontreal.ca
> https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list




More information about the Gambit-list mailing list