[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.