www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D on the Objective-C runtime?

reply Jacob Carlborg <doob me.com> writes:
I've been thinking for a while what it would take to get D running on 
the Objective-C runtime, in other words a D object will actually be an 
objc object, kind of like MacRuby but for D. How difficult it would be, 
how much work, what needs to change, both the runtime and the compiler? 
And if it would be worth the trouble.

The reason for this is to make it easier to interface with Mac OS X 
system libraries like Cocoa.


/Jacob Carlborg
Sep 06 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-09-06 06:10:03 -0400, Jacob Carlborg <doob me.com> said:

 I've been thinking for a while what it would take to get D running on 
 the Objective-C runtime, in other words a D object will actually be an 
 objc object, kind of like MacRuby but for D. How difficult it would be, 
 how much work, what needs to change, both the runtime and the compiler? 
 And if it would be worth the trouble.
 
 The reason for this is to make it easier to interface with Mac OS X 
 system libraries like Cocoa.

It certainly could be done, but first you'd need a way to handle the differences between Objective-C and D methods: - Objective-C methods are of the form "setObject:forKey:", which is difficult to map to D. - Objective-C methods do not support overloading. - Objective-C class methods (equivalent to D static member functions) are "virtual", this is used within Cocoa - Objective-C 2.0 allows a default method implementation in protocols (equivalent to D interfaces). - Templates, exceptions? If all you wanted was to make D work using the Objective-C runtime (with overloading), you could apply some special name mangling rules, but that would make it pretty incompatible with anything really in Objective-C. On the other side, you could change the D method syntax to disallow overloading, use that colon-separated-multiple-part syntax, depend on static methods being "virtual" (this pattern is used at some places in Cocoa) and add the capability to interfaces to have default implementations. but then it wouldn't really be D. Another approach is my D/Objective-C bridge: <http://michelf.com/projects/d-objc-bridge/>, which allows you to write a bridged class like below. It needs D1 and is not multithreaded, only can do classes (no protocols, no categories for now), but it works quite well for what it does. class AppController : NSObject { /** Counter for window title in openWindow. */ uint windowCount; this() { super(); } /** Open this application's website. */ void openWebsite(Object sender) { auto a = NSAlert.alert("Cannot open web site.", "OK", null, null, "The D/Objective-C bridge doesn’t have access to NSWorkspace yet, " "so we cannot open a website. Displaying an alert works though. ;-)"); a.runModal; } /** Open a new window and put it on the center of the screen. */ void openWindow(Object sender) { auto window = new NSWindow(NSMakeRect(20, 20, 300, 200), NSTitledWindowMask + NSClosableWindowMask + NSMiniaturizableWindowMask + NSResizableWindowMask, NSBackingStoreType.BUFFERED, false); window.title = "untitled "~ std.string.toString(++windowCount); window.center(); window.makeKeyAndOrderFront(this); } // Objective-C binding for IB actions. mixin IBAction!(openWindow); mixin IBAction!(openWebsite); // Overrides from NSApplication delegate. bool openUntitledFile(NSApplication sender) { openWindow(sender); return true; } bool shouldTerminateAfterLastWindowClosed(NSApplication sender) { return true; } // Objective-C bindings for the above delegate methods. mixin ObjcBindMethod!(openUntitledFile, bool, "applicationOpenUntitledFile:", NSApplication); mixin ObjcBindMethod!(shouldTerminateAfterLastWindowClosed, bool, "applicationShouldTerminateAfterLastWindowClosed:", NSApplication); } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 06 2009
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 9/6/09 12:51, Michel Fortin wrote:
 On 2009-09-06 06:10:03 -0400, Jacob Carlborg <doob me.com> said:

 I've been thinking for a while what it would take to get D running on
 the Objective-C runtime, in other words a D object will actually be an
 objc object, kind of like MacRuby but for D. How difficult it would
 be, how much work, what needs to change, both the runtime and the
 compiler? And if it would be worth the trouble.

 The reason for this is to make it easier to interface with Mac OS X
 system libraries like Cocoa.

It certainly could be done, but first you'd need a way to handle the differences between Objective-C and D methods: - Objective-C methods are of the form "setObject:forKey:", which is difficult to map to D.

I was thinking you sill have to create bindings and use objc_msgSend and friends. Or something like "extern (Objc) void foo (int arg1, int arg2);" would automatically be converted to "objc_msgSend(this, sel_registerName("foo:arg2"), arg1, arg2);".
 - Objective-C methods do not support overloading.

"void foo (int arg1, int arg2)" could be transformed to "foo:arg2" or similar.
 - Objective-C class methods (equivalent to D static member functions)
 are "virtual", this is used within Cocoa

This would be a problem.
 - Objective-C 2.0 allows a default method implementation in protocols
 (equivalent to D interfaces).
 - Templates, exceptions?

D would use the the objc exceptions and add new exception classes where necessary. Templates would probably be disallowed.
 If all you wanted was to make D work using the Objective-C runtime (with
 overloading), you could apply some special name mangling rules, but that
 would make it pretty incompatible with anything really in Objective-C.

 On the other side, you could change the D method syntax to disallow
 overloading, use that colon-separated-multiple-part syntax, depend on
 static methods being "virtual" (this pattern is used at some places in
 Cocoa) and add the capability to interfaces to have default
 implementations. but then it wouldn't really be D.

I do not want the colon-separated-multiple-part syntax. I don't want to modify the compiler too much, I sill want it to be D but virtual static methods could be an acceptable modification for example.
 Another approach is my D/Objective-C bridge:
 <http://michelf.com/projects/d-objc-bridge/>, which allows you to write
 a bridged class like below. It needs D1 and is not multithreaded, only
 can do classes (no protocols, no categories for now), but it works quite
 well for what it does.

Yes I know about your D/objc bridge.
 class AppController : NSObject {

 /** Counter for window title in openWindow. */
 uint windowCount;

 this() {
 super();
 }

 /** Open this application's website. */
 void openWebsite(Object sender) {
 auto a = NSAlert.alert("Cannot open web site.", "OK", null, null,
 "The D/Objective-C bridge doesn’t have access to NSWorkspace yet, "
 "so we cannot open a website. Displaying an alert works though. ;-)");
 a.runModal;
 }

 /** Open a new window and put it on the center of the screen. */
 void openWindow(Object sender) {
 auto window = new NSWindow(NSMakeRect(20, 20, 300, 200),
 NSTitledWindowMask + NSClosableWindowMask + NSMiniaturizableWindowMask +
 NSResizableWindowMask,
 NSBackingStoreType.BUFFERED, false);
 window.title = "untitled "~ std.string.toString(++windowCount);
 window.center();
 window.makeKeyAndOrderFront(this);
 }

 // Objective-C binding for IB actions.
 mixin IBAction!(openWindow);
 mixin IBAction!(openWebsite);


 // Overrides from NSApplication delegate.

 bool openUntitledFile(NSApplication sender) {
 openWindow(sender);
 return true;
 }

 bool shouldTerminateAfterLastWindowClosed(NSApplication sender) {
 return true;
 }

 // Objective-C bindings for the above delegate methods.
 mixin ObjcBindMethod!(openUntitledFile, bool,
 "applicationOpenUntitledFile:", NSApplication);
 mixin ObjcBindMethod!(shouldTerminateAfterLastWindowClosed, bool,
 "applicationShouldTerminateAfterLastWindowClosed:", NSApplication);

 }

Sep 06 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-09-06 07:52:27 -0400, Jacob Carlborg <doob me.com> said:

 On 9/6/09 12:51, Michel Fortin wrote:
 On 2009-09-06 06:10:03 -0400, Jacob Carlborg <doob me.com> said:
 
 I've been thinking for a while what it would take to get D running on
 the Objective-C runtime, in other words a D object will actually be an
 objc object, kind of like MacRuby but for D. How difficult it would
 be, how much work, what needs to change, both the runtime and the
 compiler? And if it would be worth the trouble.
 
 The reason for this is to make it easier to interface with Mac OS X
 system libraries like Cocoa.

It certainly could be done, but first you'd need a way to handle the differences between Objective-C and D methods: - Objective-C methods are of the form "setObject:forKey:", which is difficult to map to D.

I was thinking you sill have to create bindings and use objc_msgSend and friends. Or something like "extern (Objc) void foo (int arg1, int arg2);" would automatically be converted to "objc_msgSend(this, sel_registerName("foo:arg2"), arg1, arg2);".

That doesn't scale very well. Overloading allows both "foo(int arg1, int arg2)" and "foo(int arg1, float arg2)" to exist in the same scope, both would become "foo:arg2:".
 - Objective-C methods do not support overloading.

"void foo (int arg1, int arg2)" could be transformed to "foo:arg2" or similar.

Yeah, but what if you have foo(int a) and foo(float a)? Then you need some kind of name mangling: foo(int a) becomes - fooInt:(int)a foo(float a) becomes - fooFloat:(int)a and now the two can exist at the same time in the same class.
 - Objective-C class methods (equivalent to D static member functions)
 are "virtual", this is used within Cocoa

This would be a problem.

 - Objective-C 2.0 allows a default method implementation in protocols
 (equivalent to D interfaces).
 - Templates, exceptions?

D would use the the objc exceptions and add new exception classes where necessary. Templates would probably be disallowed.

So now the base exception class is NSException?
 If all you wanted was to make D work using the Objective-C runtime (with
 overloading), you could apply some special name mangling rules, but that
 would make it pretty incompatible with anything really in Objective-C.
 
 On the other side, you could change the D method syntax to disallow
 overloading, use that colon-separated-multiple-part syntax, depend on
 static methods being "virtual" (this pattern is used at some places in
 Cocoa) and add the capability to interfaces to have default
 implementations. but then it wouldn't really be D.

I do not want the colon-separated-multiple-part syntax. I don't want to modify the compiler too much, I sill want it to be D but virtual static methods could be an acceptable modification for example.

Hum, I think if someone wanted to have Objective-C compatibility it'd be better to just add a different syntax for declaring Objective-C classes than to try to fit them within D classes, much like with Objective-C++. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 06 2009
parent Jacob Carlborg <doob me.com> writes:
On 9/6/09 14:18, Michel Fortin wrote:
 On 2009-09-06 07:52:27 -0400, Jacob Carlborg <doob me.com> said:

 On 9/6/09 12:51, Michel Fortin wrote:
 On 2009-09-06 06:10:03 -0400, Jacob Carlborg <doob me.com> said:

 I've been thinking for a while what it would take to get D running on
 the Objective-C runtime, in other words a D object will actually be an
 objc object, kind of like MacRuby but for D. How difficult it would
 be, how much work, what needs to change, both the runtime and the
 compiler? And if it would be worth the trouble.

 The reason for this is to make it easier to interface with Mac OS X
 system libraries like Cocoa.

It certainly could be done, but first you'd need a way to handle the differences between Objective-C and D methods: - Objective-C methods are of the form "setObject:forKey:", which is difficult to map to D.

I was thinking you sill have to create bindings and use objc_msgSend and friends. Or something like "extern (Objc) void foo (int arg1, int arg2);" would automatically be converted to "objc_msgSend(this, sel_registerName("foo:arg2"), arg1, arg2);".

That doesn't scale very well. Overloading allows both "foo(int arg1, int arg2)" and "foo(int arg1, float arg2)" to exist in the same scope, both would become "foo:arg2:".
 - Objective-C methods do not support overloading.

"void foo (int arg1, int arg2)" could be transformed to "foo:arg2" or similar.

Yeah, but what if you have foo(int a) and foo(float a)? Then you need some kind of name mangling: foo(int a) becomes - fooInt:(int)a foo(float a) becomes - fooFloat:(int)a and now the two can exist at the same time in the same class.
 - Objective-C class methods (equivalent to D static member functions)
 are "virtual", this is used within Cocoa

This would be a problem.

 - Objective-C 2.0 allows a default method implementation in protocols
 (equivalent to D interfaces).
 - Templates, exceptions?

D would use the the objc exceptions and add new exception classes where necessary. Templates would probably be disallowed.

So now the base exception class is NSException?
 If all you wanted was to make D work using the Objective-C runtime (with
 overloading), you could apply some special name mangling rules, but that
 would make it pretty incompatible with anything really in Objective-C.

 On the other side, you could change the D method syntax to disallow
 overloading, use that colon-separated-multiple-part syntax, depend on
 static methods being "virtual" (this pattern is used at some places in
 Cocoa) and add the capability to interfaces to have default
 implementations. but then it wouldn't really be D.

I do not want the colon-separated-multiple-part syntax. I don't want to modify the compiler too much, I sill want it to be D but virtual static methods could be an acceptable modification for example.

Hum, I think if someone wanted to have Objective-C compatibility it'd be better to just add a different syntax for declaring Objective-C classes than to try to fit them within D classes, much like with Objective-C++.

Yeah, perhaps you're right, I was just thinking out loud.
Sep 06 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Michel Fortin wrote:
 Another approach is my D/Objective-C bridge: 
 <http://michelf.com/projects/d-objc-bridge/>, which allows you to write 
 a bridged class like below. It needs D1 and is not multithreaded, only 
 can do classes (no protocols, no categories for now), but it works quite 
 well for what it does.

     /** Open a new window and put it on the center of the screen. */
     void openWindow(Object sender) {
     }
 
     // Objective-C binding for IB actions.
     mixin IBAction!(openWindow);
     mixin IBAction!(openWebsite);

Off topic, but this would be a good place for user-defined attributes. Then you could write something like: IBAction void openWindow(Object sender) {}
Sep 06 2009
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-09-06 08:32:43 -0400, Christopher Wright <dhasenan gmail.com> said:

 Off topic, but this would be a good place for user-defined attributes. 
 Then you could write something like:
 
  IBAction void openWindow(Object sender) {}

Indeed... although IBAction isn't so bad as a mixin, it gets much worse with ObjcMethod where it is necessary to list all the argument types to allow resolving overloaded functions: void doOneAndTwo(int i, int j) {} mixin ObjcMethod(void, doOneAndTwo, "doOne:andTwo:", int, int); Compare to what could be done with a parametrized attribute: ObjcMethod("doOne:andTwo:") void doOneAndTwo(int i, int j); That'd would be a lot more convenient, especially with interfaces for which none of the mixin above can work (they insert some static struct member to store the "attributes"). -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 06 2009
parent Jacob Carlborg <doob me.com> writes:
On 9/6/09 15:12, Michel Fortin wrote:
 On 2009-09-06 08:32:43 -0400, Christopher Wright <dhasenan gmail.com> said:

 Off topic, but this would be a good place for user-defined attributes.
 Then you could write something like:

  IBAction void openWindow(Object sender) {}

Indeed... although IBAction isn't so bad as a mixin, it gets much worse with ObjcMethod where it is necessary to list all the argument types to allow resolving overloaded functions: void doOneAndTwo(int i, int j) {} mixin ObjcMethod(void, doOneAndTwo, "doOne:andTwo:", int, int);

That is actually not necessary. It would be sufficient with a template taking an alias to the method (most of the times). Then you can build a selector string out of the method name and the parameter names. To get the types of the method you can use traits templates/functions available both in phobos and tango. You would probably also need a template taking an alias and a selector string when the above doesn't work. This would work best with new methods when you can control the method and parameter names and not with existing methods.
 Compare to what could be done with a parametrized attribute:

  ObjcMethod("doOne:andTwo:") void doOneAndTwo(int i, int j);

 That'd would be a lot more convenient, especially with interfaces for
 which none of the mixin above can work (they insert some static struct
 member to store the "attributes").

Sep 06 2009