discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Etoile-dev] ANN: New Objective-C Runtime


From: Quentin Mathé
Subject: Re: [Etoile-dev] ANN: New Objective-C Runtime
Date: Sun, 11 Nov 2007 01:42:39 +0100

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.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]