Nat! bio photo

Nat!

Senior Mull.

Twitter RSS

Github

mulle_objc: inheriting methods from protocols

Continued from mulle-objc: object layout, retain counting, finalize


A protocol in mulle-objc "lives" only in the compiler. Whereas in the legacy runtimes, a protocol existed at runtime as it's own object, in mulle-objc it is just a hash value, whose presence can be queried on the class. At runtime you don't know, what methods are part of a protocol.

As before there is nothing that stops you from creating a class with the same name as a protocol. This is put to good use now.

Inheriting methods from protocols

A class decides at runtime, what to inherit with a ->instance bitfield, that is part of the struct _mulle_objc_class:

Feature Description
MULLE_OBJC_CLASS_DONT_INHERIT_SUPERCLASS for completeness sake, useless
MULLE_OBJC_CLASS_DONT_INHERIT_CATEGORIES be obnoxious and seal your class
MULLE_OBJC_CLASS_INHERIT_PROTOCOLS inherit methods from protocol class, but not it's categories
MULLE_OBJC_CLASS_INHERIT_PROTOCOLS_CATEGORIES inherit methods from categories of protocol class

A class can set these bits during +load or +initialize. I am toying with the idea of making MULLE_OBJC_CLASS_INHERIT_PROTOCOLS the default.

Alternative idea: A class has a method +inheritsProtocol:category: or even +inheritsSelector:protocol:category: and this method is queries, whenever the method cache is filled.

A scheme to have protocols with ivars (sort of)

Create a struct that contains the instance variables, the protocol needs. Define a method in the protocol to get the address of this struct in the instance variable area of an instance.

 1 struct protocol_foo_struct
 2 {
 3  unsigned int  a;
 4  unsigned int  b;
 5 };
 6 
 7 
 8 @protocol Foo
 9 
10 - (void) getFooStructP:(struct protocol_foo_struct **) foo;
11 
12 @optional
13 - (void) setA:(unsigned int) value;
14 
15 @end
16 
17 
18 //
19 // default implementation for Classes adopting Foo
20 //
21 @interface Foo
22 @end
23 
24 
25 @implementation Foo
26 
27 - (void) setA:(unsigned int) value
28 {
29  struct protocol_foo_struct *p;
30 
31  [self getFooStructP:&p];
32  p->a = value;
33 }
34 @end
35 
36 
37 
38 
39 //  a class adopting Foo protocol
40 //
41 @interface Bar < Foo>
42 {
43  long                         whatever;
44    struct protocol_foo_struct   foo;
45 }
46 
47 
48 @implementation Bar
49 
50 + (void) load
51 {
52    _mulle_objc_class_set_inheritance( self, MULLE_OBJC_CLASS_INHERIT_PROTOCOLS);
53 }
54 
55 
56 - (void) getFooStructP:(struct protocol_foo_struct **) foo
57 {
58    *foo = &self->foo;
59 }
60 
61 @end

Together with the extremely fast forwarding that mulle-objc offers through the meta-ABI, this makes multiple-inheritance-like schemes possible and performance wise acceptable.

I might get accused of "ripping off" Swift here, which apparently has something like this now. But when I designed this feature into the runtime some months ago, I didn't know about it.


Continue to mulle-objc: present and absent language features


Post a comment

All comments are held for moderation; basic HTML formatting accepted.

Name:
E-mail: (not published)
Website: