Hi David,

Le 8 nov. 07 à 16:03, David Chisnall a écrit :

> Hi Everyone,
>
> I've spent the last two days locked in my room doing some therapeutic
> coding[1], and the result is a new Objective-C runtime (rejection is
> obviously good for my productivity; I should apply for more jobs).

:-)

>  A
> quick summary of features:
>
> - Two layer model, with Self-like object model at the core and classes
> built on top.
> - Very small code base (roughly 10% of the size of the GNU runtime)
> - Support for @synchronized on all objects / classes.
> - Support for concrete protocols / mixins.
> - Support for prototype-based object orientation (can be mixed with
> class-based; classes really are just another kind of object in this
> runtime)
> - Support for safe method caching (including polymorphic inline
> caching) with low overhead.
> - Support for fast accessor methods (we can implement properties that
> are much faster than Apple's)

As we already discussed it, I really like the whole design except the  
fact protocols are only available at class level.
I may submit a patch later to implement them at object level. Class  
would override protocol handling to handle the case where you pass a  
protocol which is a class and not an object. In this former case, the  
handling would be extended to deal with instance and class methods at  
the same time rather than only instance methods.

> The code is currently in a branch in the Étoilé repository:
>
> svn://svn.gna.org/svn/etoile/branches/libobjc_tr/
>
> Comments welcome, bug fixes very welcome.

I may have overlooked something, but after reading objc_object.h and  
message sending mechanism, I fail to understand how Io messaging model  
can be fully supported by libobjc_tr.

#define MSG_SEND(ret, obj, sel_name, sel_types, ...)\
                do\
                {\
                        static SEL selector = lookup_typed_selector(sel_name, 
sel_types);\
                        struct objc_slot * slot = slot_lookup(object, foo_sel);\
                        CALL_SLOT(ret, slot, obj, selector, __VA_ARGS__);\
                } while(0)

Passing only obj (receiver), sel (selector) and arguments seems too  
much limited since you cannot know anything about where the message is  
sent either in the lookup function or in the call function.
I suggest a different implementation at the end of this mail. But  
before that, I'm going to explain what is libojc_tr problem in my  
opinion if you want to support Io messaging or other uncommon  
messaging styles


Inside a each block/method, Io provides access to the sender and the  
receiver context in addition to self. There is a call object that you  
can access. Here is the core API of Call prototype:
- sender // the context/namespace where the message sending was executed
- message // the invocation object
- activated // the method/block object
- slotContext // the context/namespace where the message was received  
(for example the parent/proto which implements the method if the  
receiver doesn't)
- target // the receiver aka self

/* do means: execute  code in the context of the receiver  
(ParentObject here)
    Namespace are then implicitely defined by where you code gets  
executed */
ParentObject := Object clone do(
        myMethod1 := method(
                "Method located in parent" println
        )
        myMethod2 := method(
                call slotContext myMethod1 println
        )
        myMethod3 := method(
                self myMethod1 println
        )
)

childObject := ParentObject clone do(
        myMethod1 := method(
                "Method located in child" println
        )
}

childObject myMethod2 // prints "Method located in parent"
childObject myMethod3 // prints "Method located in child"

Can you support modifying method lookup/send based on the context in  
this way with libobjc_tr?
Some languages may decide that 'myMethod1 println' means 'call  
slotContext myMethod1 println' and self must be used explicitly to  
send a message to the receiver.

The idea behind slotContext is explained in details here: <>
As I explain it below I think what is detailed in the previous link  
can be seen in a less prototype-centric way.

The problem here is the support of both sender and slotContext.  
Personally I find this terminology a bit confusing. May be we can talk  
of send context and receive context.
In a more general way, I think message lookup and dispatching based on  
the context should be supported. In this perspective, the context is  
the union of the send context and the receive context. It makes  
possible to change the behavior/state of an object depending on:
- the sender or where the sender is located
- where the receiver is located
This should allow to support any kind of messaging style (including  
those not yet invented
  well at least I hope ;-)).

The receive context can be implemented by an ivar in the root object  
of languages targeting the runtime. However the send context cannot be  
supported cleanly without the runtime help. A first approach is to  
pass the sender and supports slotContext by adding an ivar/slot on the  
root object in the language. But a better solution could be to have a  
context object argument that language may choose to use or not. Such  
context object could then be subclassed to package additional context  
infos. A call object like in Io could then be dynamically built from  
the invocation/message and this context object. It would support a  
protocol similar to:
- sendContext (aka sender)
- receiveContext (either the receiver or another object)
- callStack
- may be few other stuff

In summary, languages can uses the context argument to pass any infos  
they need in order to implement exotic message dispatching. Not sure  
it's really interesting but a language could also extend context  
object to make a difference between sendContext and sender. For  
example, sendContext could be a method and sender the object owning  
the method. Somewhat as if sendContext was a post office and sender  
the person who uses the post office to send a letter.

Here is an example of what you can do by taking in account the context:

/* Let's say the receiver is a file object. This method then tells  
whether the receiver can be read
    depending on both the receiver location and the sender location.  
Returned value can be
    different if you call this method from two objects, each one  
located in a distinct namespace/path. */
- (BOOL) isReadable
{
        /* path represents a namespace */
        if ([[receiveContext path] isEqual: @"/public"])
        {
                return YES;
        }
        else if ([[sendContext path] isEqual: @"/somewhere/admin"])
        {
                return YES;
        }
        else /* In all other cases, for example [[sendContext path] isEqual:  
@"/somewhere/normalUser"] */
        {
                return NO;
        }
}

Now here is my proposal for message sending, something along these  
lines giving you access to the context in both lookup and call:

#define MSG_SEND(ret, obj, context, sel_name, sel_types, ...)\
                do\
                {\
                        static SEL selector = lookup_typed_selector(sel_name, 
sel_types);\
                        struct objc_slot * slot = slot_lookup(object, context, 
foo_sel);\
                        CALL_SLOT(ret, slot, obj, context, selector, 
__VA_ARGS__);\
                } while(0)

If the problem I have outlined really exists, what do you think?

Cheers,
Quentin.


_______________________________________________
Etoile-dev mailing list
[email protected]
https://mail.gna.org/listinfo/etoile-dev

Reply via email to