www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - GUI program on Mac OS in D?

reply Adam D. Ruppe <destructionator gmail.com> writes:
I know we have the extern(Objective-C) stuff from 
https://wiki.dlang.org/DIP43 now, but do we have existing 
bindings anywhere along the lines of the win32 ones we can just 
import and start calling the operating system functions?

Moreover, I'm not a Mac dev; I've never actually done so much of 
a hello world, so have any of you done like a hello world in 
cocoa using D tutorial or example I can copy/paste to get started?
Nov 23 2017
next sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Thursday, 23 November 2017 at 16:06:28 UTC, Adam D. Ruppe 
wrote:
 I know we have the extern(Objective-C) stuff from 
 https://wiki.dlang.org/DIP43 now, but do we have existing 
 bindings anywhere along the lines of the win32 ones we can just 
 import and start calling the operating system functions?

 Moreover, I'm not a Mac dev; I've never actually done so much 
 of a hello world, so have any of you done like a hello world in 
 cocoa using D tutorial or example I can copy/paste to get 
 started?
Perhaps https://github.com/p0nce/DerelictCocoa
Nov 23 2017
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 23 November 2017 at 16:14:50 UTC, Guillaume Piolat 
wrote:
 Perhaps https://github.com/p0nce/DerelictCocoa
Well, that would be one option, though I was hoping to avoid the extern(C) runtime stuff and dynamic loading - ideally, I want something with the extern(Objective-C) stuff for static binding.
Nov 23 2017
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-11-23 17:06, Adam D. Ruppe wrote:
 I know we have the extern(Objective-C) stuff from 
 https://wiki.dlang.org/DIP43 now, but do we have existing bindings 
 anywhere along the lines of the win32 ones we can just import and start 
 calling the operating system functions?
Not as far as I know. Only a small part of what's in DIP43 is merged upstream in DMD, that is calling instance methods. DStep can generate bindings for Objective-C code but it will generate bindings for the full implementation of DIP43, so some things will not work with the official DMD. Back in the days when I announced 64bit version of DIP43 some guy started using it and seems to have a fairly complete set of bindings [1]. But again, those are for the full implementation of DIP43.
 Moreover, I'm not a Mac dev; I've never actually done so much of a hello 
 world, so have any of you done like a hello world in cocoa using D 
 tutorial or example I can copy/paste to get started?
I have a simple example [2] of an application that shows a window with a WebKit view, i.e. and embedded browser. This works with the upstream DMD and LDC compilers. It basically only contains bindings for what I needed for that sample application. As you'll see there you need to use some parts of the Objective-C runtime to create class instances and subclasses. Also some gymnastics are required for class/static methods. Note that this example is not a traditional Mac application, it was designed to not use .nib files (GUI files) and be embedded as a library inside another application. If you want to give this a try, I recommend finding some Objective-C/Swift hello world examples online, combine that with my sample application [2] and the official documentation [3] for interfacing with Objective-C. You can use DStep to generate bindings and do some post-processing to remove/change what doesn't compile today using DMD. If you have any questions, please let me know. [1] https://github.com/DiveFramework/DiveFramework [2] https://github.com/jacob-carlborg/d_webkit_test [3] https://dlang.org/spec/objc_interface.html -- /Jacob Carlborg
Nov 23 2017
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 23 November 2017 at 17:28:43 UTC, Jacob Carlborg 
wrote:
 I have a simple example [2] of an application that shows a 
 window with a WebKit view, i.e. and embedded browser.
Thanks, this gets me started. Do you happen to know if there is anything like "pragma(lib)" for the -framework argument? (I don't use dub, so I took your config there to make my own command line, but it would be nice if I didn't have to specify the framework. I use pragma(lib) on Windows and Linux so infer it automatically.)
 As you'll see there you need to use some parts of the 
 Objective-C runtime to create class instances and subclasses. 
 Also some gymnastics are required for class/static methods.
Yes, indeed. The old mac code I had here used all the extern(C) calls (it was contributed to me by a forum user, I didn't write it myself, but did look at it), so some of that is actually familiar. So my plan here is to get more of my libs working on Mac: update the old simpledisplay.d port so it runs on the native api again (currently it just uses XQuartz), then make my simpleaudio.d use OpenAL which I hear has been included with the mac os for some time, then maybe even move on to minigui.d and have it use some native controls too, if reasonable. But the first step is just creating a basic window and your code worked, so thanks, I am on the path now...
Nov 24 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-11-24 16:09, Adam D. Ruppe wrote:

 Thanks, this gets me started.
 
 Do you happen to know if there is anything like "pragma(lib)" for the 
 -framework argument? (I don't use dub, so I took your config there to 
 make my own command line, but it would be nice if I didn't have to 
 specify the framework. I use pragma(lib) on Windows and Linux so infer 
 it automatically.)
There's not [1].
 So my plan here is to get more of my libs working on Mac: update the old 
 simpledisplay.d port so it runs on the native api again (currently it 
 just uses XQuartz),
I think you should start by deciding if you want to use any .nib files or not. If you do use .nib files there is quite a lot of code that can be removed from my sample application.
 then make my simpleaudio.d use OpenAL which I hear 
 has been included with the mac os for some time
Yes, it's included. Apple has several audio frameworks [2], where OpenAL is one of them, for different purposes and different levels.
 , then maybe even move on 
 to minigui.d and have it use some native controls too, if reasonable
 But the first step is just creating a basic window and your code worked, 
 so thanks, I am on the path now...
BTW, the following line [3] of the Dub file will embed the Info.plist file in the executable, which can be handy if you don't want to use application bundles. The Info.plist file is not always necessary, I think my sample application will work without it, but for some things is necessary. I also have a Dockerfile [4] with a cross-compiler setup that targets macOS. You should also know that there's a bug in DMD, which I haven't manged to fix, that occurs when returning certain structs from Objective-C methods. I'm pretty sure if works correctly in LDC, since it's using the LLVM backend that already knows about Objective-C. Finally, since you're using D you'll not have ARC (Automatic Reference Counting) which these days are preformed by the Objective-C and Swift compilers. You'll need to resort to traditional release/retain calls where appropriate. I have not included those calls in my sample application. If you decide to use DStep, please file bugs and let me know how it works. It has not been battle tested for Objective-C code. [1] https://issues.dlang.org/show_bug.cgi?id=2968 [2] https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioFrameworks/CoreAudioFrameworks.html [3] https://github.com/jacob-carlborg/d_webkit_test/blob/master/dub.sdl#L12 [4] https://github.com/jacob-carlborg/docker-ldc-darwin/blob/master/Dockerfile -- /Jacob Carlborg
Nov 24 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Friday, 24 November 2017 at 15:56:21 UTC, Jacob Carlborg wrote:
 BTW, the following line [3] of the Dub file will embed the 
 Info.plist file in the executable, which can be handy if you 
 don't want to use application bundles. The Info.plist file is 
 not always necessary, I think my sample application will work 
 without it, but for some things is necessary.

 I also have a Dockerfile [4] with a cross-compiler setup that 
 targets macOS.

 You should also know that there's a bug in DMD, which I haven't 
 manged to fix, that occurs when returning certain structs from 
 Objective-C methods. I'm pretty sure if works correctly in LDC, 
 since it's using the LLVM backend that already knows about 
 Objective-C.

 Finally, since you're using D you'll not have ARC (Automatic 
 Reference Counting) which these days are preformed by the 
 Objective-C and Swift compilers. You'll need to resort to 
 traditional release/retain calls where appropriate. I have not 
 included those calls in my sample application.
I'm also interested in making native macOS apps. I have a lot of experience in Objective-C but I'm new at D. I'm a bit confused at what documentation to look at. In [1] I get the impression that support for creating instances is very rudimentary, but in [2] it looks much better with constructors mapped with selector. What level of support is there in the latest DMD compiler? Also, is there any support for creating macOS application bundles? [1] https://dlang.org/spec/objc_interface.html [2] https://wiki.dlang.org/DIP43
Dec 06 2017
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-12-06 17:50, mrphobby wrote:

 I'm also interested in making native macOS apps. I have a lot of 
 experience in Objective-C but I'm new at D. I'm a bit confused at what 
 documentation to look at. In [1] I get the impression that support for 
 creating instances is very rudimentary, but in [2] it looks much better 
 with constructors mapped with  selector. What level of support is there 
 in the latest DMD compiler?
The latest DMD compiler only supports what's in the official documentation, i.e. [1]. What's documented in DIP43 [2] (except anything marked with "unimplemented") is what's been implemented in one of my forks. I'm working on adding what's in my fork piece by piece to upstream.
 Also, is there any support for creating macOS application bundles?
No, there are currently no plans for that. As far as I understand the Objective-C compiler will not to this either. When using Objective-C I think either Xcode or some other tool is creating the bundle. Note that a bundle is just a directory with a specific structure, which can easily be created without any special tools. [1] https://dlang.org/spec/objc_interface.html [2] https://wiki.dlang.org/DIP43 -- /Jacob Carlborg
Dec 07 2017
parent mrphobby <mrp spinrock.net> writes:
On Thursday, 7 December 2017 at 09:39:45 UTC, Jacob Carlborg 
wrote:
 The latest DMD compiler only supports what's in the official 
 documentation, i.e. [1]. What's documented in DIP43 [2] (except 
 anything marked with "unimplemented") is what's been 
 implemented in one of my forks. I'm working on adding what's in 
 my fork piece by piece to upstream.
Ok thanks for clearing that up! Your work looks really appealing. Hope it gets into the official compiler soon.
Dec 08 2017
prev sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 6 December 2017 at 16:50:10 UTC, mrphobby wrote:
 Also, is there any support for creating macOS application 
 bundles?

 [1] https://dlang.org/spec/objc_interface.html
 [2] https://wiki.dlang.org/DIP43
You can easily make a DUB frontend to do that, for example https://github.com/AuburnSounds/Dplug/tree/master/tools/dplug-build (you'll find some code that generates Mac bundles in there, with pretty minimal Info.plist)
Dec 07 2017
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Thursday, 7 December 2017 at 12:18:21 UTC, Guillaume Piolat 
wrote:
 You can easily make a DUB frontend to do that, for example 
 https://github.com/AuburnSounds/Dplug/tree/master/tools/dplug-build
And it might be cleaner to do this as a post-build step.
Dec 07 2017
parent mrphobby <mrp spinrock.net> writes:
On Thursday, 7 December 2017 at 12:27:36 UTC, Guillaume Piolat 
wrote:
 On Thursday, 7 December 2017 at 12:18:21 UTC, Guillaume Piolat 
 wrote:
 You can easily make a DUB frontend to do that, for example 
 https://github.com/AuburnSounds/Dplug/tree/master/tools/dplug-build
And it might be cleaner to do this as a post-build step.
Thanks, I'll have a look at that.
Dec 08 2017
prev sibling parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 23 November 2017 at 17:28:43 UTC, Jacob Carlborg 
wrote:
 I have a simple example [2] of an application that shows a 
 window with a WebKit view, i.e. and embedded browser. This 
 works with the upstream DMD and LDC compilers. It basically 
 only contains bindings for what I needed for that sample 
 application. As you'll see there you need to use some parts of 
 the Objective-C runtime to create class instances and 
 subclasses. Also some gymnastics are required for class/static 
 methods.
I have been taking a look at your example. Looks pretty neat! Some advanced mixin stuff there that looks pretty useful. However, as far as I can tell there is no handling of retain/release. How would you incorporate this into your mixin system without having to put "release" in all the interface definitions? Would it be possible to somehow hook this up automatically to the D destructor perhaps? Interested in hearing your thoughts on this!
Dec 13 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-12-13 13:18, mrphobby wrote:

 I have been taking a look at your example. Looks pretty neat! Some 
 advanced mixin stuff there that looks pretty useful.
They're pretty basic ;)
 However, as far as 
 I can tell there is no handling of retain/release.
No, that's correct.
 How would you 
 incorporate this into your mixin system without having to put "release" 
 in all the interface definitions?
You can add methods for retain/release in the ClassTrait template [1].
 Would it be possible to somehow hook 
 this up automatically to the D destructor perhaps? Interested in hearing 
 your thoughts on this!
As far as I know, the destructor is only called (automatically by the GC). Since the Objective-C objects are not created using the GC the destructor will never be called. I don't think it's possible to implement reference counting (that would call retain/release) for classes in D, since it's not possible to overload the assignment operator for classes [2] or implement a postblit [3]. The only option, as far as I know, would be to wrap the class in a struct that calls retain/release automatically. But then you need to box/unbox the wrapped class constantly and all the method signatures would probably need to use this wrapper as well. [1] https://github.com/jacob-carlborg/d_webkit_test/blob/master/source/foundation/util.d#L28 [2] https://dlang.org/spec/operatoroverloading.html#assignment [3] https://dlang.org/spec/struct.html#struct-postblit -- /Jacob Carlborg
Dec 13 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-12-13 16:07, Jacob Carlborg wrote:
 On 2017-12-13 13:18, mrphobby wrote:
 Would it be possible to somehow hook this up automatically to the D 
 destructor perhaps? Interested in hearing your thoughts on this!
As far as I know, the destructor is only called (automatically by the GC). Since the Objective-C objects are not created using the GC the destructor will never be called. I don't think it's possible to implement reference counting (that would call retain/release) for classes in D, since it's not possible to overload the assignment operator for classes [2] or implement a postblit [3]. The only option, as far as I know, would be to wrap the class in a struct that calls retain/release automatically. But then you need to box/unbox the wrapped class constantly and all the method signatures would probably need to use this wrapper as well.
I forgot to mention that there have been several discussions around adding support for reference counted classes. Several of the mentioning interfacing with Objective-C is important/a requirement. https://wiki.dlang.org/Language_design_discussions#Automatic_Reference_Counting_.28ARC.29_as_an_alternative_to_D.27s_Garbage_Collector http://forum.dlang.org/post/n0nnu0$1tth$1 digitalmars.com https://wiki.dlang.org/FatPointer#Interfacing_with_Objective-C -- /Jacob Carlborg
Dec 13 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Wednesday, 13 December 2017 at 15:17:59 UTC, Jacob Carlborg 
wrote:
 I forgot to mention that there have been several discussions 
 around adding support for reference counted classes. Several of 
 the mentioning interfacing with Objective-C is important/a 
 requirement.
Ok, good to know! I have another question about your Webkit test example... I see that you are doing some elaborate setup in order to bind the application delegate methods. Can you explain a bit about why you are doing it in this way instead of using the selector attribute in a class? The thing is that I'm currently attempting to get it to work using the "easy" way using selector but the methods in my AppDelegate class are not called. Not sure why that is, but I probably screwed something up :)
Dec 13 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-12-13 16:59, mrphobby wrote:

 I have another question about your Webkit test example... I see that you 
 are doing some elaborate setup in order to bind the application delegate 
 methods. Can you explain a bit about why you are doing it in this way 
 instead of using the  selector attribute in a class?
That is to register the methods with the Objective-C runtime. Currently the selector attribute can only be used on methods that are already implemented in Objective-C. If a need to implement a new method or override an existing method in a subclass, then it's necessary to manually register that method with the runtime. This is because the full implementation of DIP43 [1] is not done/merged yet. But trust me, this is a lot simpler than without any compiler support at all. Then you would need to know details of the ABI to call Objective-C methods. The methods I've added in the WebKit example are methods that will only be called as callbacks by the Objective-C code. If I want to call them myself I would need the selector attribute as well, in addition to the manual registering.
 The thing is that I'm currently attempting to get it to work using the 
 "easy" way using  selector but the methods in my AppDelegate class are 
 not called. Not sure why that is, but I probably screwed something up :)
Yes, see above. [1] https://wiki.dlang.org/DIP43 -- /Jacob Carlborg
Dec 14 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 14 December 2017 at 10:14:13 UTC, Jacob Carlborg 
wrote:
 That is to register the methods with the Objective-C runtime. 
 Currently the  selector attribute can only be used on methods 
 that are already implemented in Objective-C. If a need to 
 implement a new method or override an existing method in a 
 subclass, then it's necessary to manually register that method 
 with the runtime.
Ok I understand it now, thanks! I'm thinking it would be nice to wrap this setup code into some kind of mixin template so that I could put the required configuration setup in each class. In other languages like Python or C# I would maybe decorate my methods with an attribute and then use reflection to build the proper data structures at runtime. However, I'm completely new to D so it's a bit difficult to see a good solution here. If you have any ideas how to do this I'd appreciate it. Thanks for all help!
Dec 14 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 14 December 2017 at 11:36:46 UTC, mrphobby wrote:
 I'm thinking it would be nice to wrap this setup code into some 
 kind of mixin template so that I could put the required 
 configuration setup in each class. In other languages like 
 Python or C# I would maybe decorate my methods with an 
 attribute and then use reflection to build the proper data 
 structures at runtime. However, I'm completely new to D so it's 
 a bit difficult to see a good solution here. If you have any 
 ideas how to do this I'd appreciate it. Thanks for all help!
Also, it feels a bit awkward to implement the callback handling methods as static methods, with the "self" and SEL arguments. Would have been nice if it was possible to use instance methods. After thinking about it for a while I guess it could work with one static dispatch method that maps selectors to specific instance methods. So when callbacks are made from Objective-C they are made to this one static method, which would then call the right method on the class. I'm still struggling with D syntax, so here's some pseudo code: class AppDelegate { static var methodMap = {} // Maps selector name to methods static void handleCallback(AppDelegate self, SEL sel, ...) { var method = methodMap[sel]; self.call(method, va_list); // Call the method with args (not sure if possible in D) } void applicationDidFinishLaunching(NSNotification notification) { // Normal instance method here } } Now, you would also need a registration step somewhere that sets up the selectors to use, perhaps in a static constructor that is run when AppDelegate class is used for the first time. I hope this makes sense. Just throwing out some ideas :)
Dec 14 2017
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 14 December 2017 at 13:56:28 UTC, mrphobby wrote:
 After thinking about it for a while I guess it could work with 
 one static dispatch method that maps selectors to specific 
 instance methods. So when callbacks are made from Objective-C 
 they are made to this one static method, which would then call 
 the right method on the class.
I was playing with this myself based on Jacob's code and made it look like this: extern (Objective-C) interface ViewController : NSViewController { extern (C) ObjCMethodOverride("loadView") static void loadView(ViewController self, SEL sel) { printf("loadView\n"); } extern (C) ObjCMethodOverride("viewDidLoad") static void viewDidLoad(ViewController self, SEL sel) { printf("viewDidLoad\n"); } ViewController init() selector("init"); mixin RegisterObjCClass; } so the mixin does some registering based on the method override attrs. It is still static with self cuz I actually felt hiding that made things a bit worse (inheritance wouldn't work like you expect), but most the registration stuff is now pulled from the attribute metadata. Of course, my goal here isn't actually to do all of obj-c... just enough to port my simpledisplay.d. So I'm not sure if I'll make this public yet or just leave it as private and/or undocumented inside my library file.
Dec 14 2017
next sibling parent Mengu <mengukagan gmail.com> writes:
On Thursday, 14 December 2017 at 14:07:25 UTC, Adam D. Ruppe 
wrote:
 I was playing with this myself based on Jacob's code and made 
 it look like this:

 extern (Objective-C) interface ViewController : 
 NSViewController {
         extern (C)
          ObjCMethodOverride("loadView")
         static void loadView(ViewController self, SEL sel) {
                 printf("loadView\n");
         }

         extern (C)
          ObjCMethodOverride("viewDidLoad")
         static void viewDidLoad(ViewController self, SEL sel) {
                 printf("viewDidLoad\n");
         }

         ViewController init()  selector("init");
         mixin RegisterObjCClass;
 }



 so the mixin does some registering based on the method override 
 attrs. It is still static with self cuz I actually felt hiding 
 that made things a bit worse (inheritance wouldn't work like 
 you expect), but most the registration stuff is now pulled from 
 the attribute metadata.


 Of course, my goal here isn't actually to do all of obj-c... 
 just enough to port my simpledisplay.d. So I'm not sure if I'll 
 make this public yet or just leave it as private and/or 
 undocumented inside my library file.
please make it public.
Dec 14 2017
prev sibling parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 14 December 2017 at 14:07:25 UTC, Adam D. Ruppe 
wrote:
 I was playing with this myself based on Jacob's code and made 
 it look like this:

 extern (Objective-C) interface ViewController : 
 NSViewController {
         extern (C)
          ObjCMethodOverride("loadView")
         static void loadView(ViewController self, SEL sel) {
                 printf("loadView\n");
         }

         extern (C)
          ObjCMethodOverride("viewDidLoad")
         static void viewDidLoad(ViewController self, SEL sel) {
                 printf("viewDidLoad\n");
         }

         ViewController init()  selector("init");
         mixin RegisterObjCClass;
 }



 so the mixin does some registering based on the method override 
 attrs. It is still static with self cuz I actually felt hiding 
 that made things a bit worse (inheritance wouldn't work like 
 you expect), but most the registration stuff is now pulled from 
 the attribute metadata.


 Of course, my goal here isn't actually to do all of obj-c... 
 just enough to port my simpledisplay.d. So I'm not sure if I'll 
 make this public yet or just leave it as private and/or 
 undocumented inside my library file.
This looks pretty awesome and very much like something I was looking for. Would really appreciate if you could share your work. Otherwise I'll have to roll up my sleeves and try hacking it on my own :) Thanks for sharing your ideas!
Dec 14 2017
next sibling parent mrphobby <mrp spinrock.net> writes:
On Thursday, 14 December 2017 at 19:10:26 UTC, mrphobby wrote:
 On Thursday, 14 December 2017 at 14:07:25 UTC, Adam D. Ruppe 
 wrote:
 I was playing with this myself based on Jacob's code and made 
 it look like this:

 extern (Objective-C) interface ViewController : 
 NSViewController {
         extern (C)
          ObjCMethodOverride("loadView")
         static void loadView(ViewController self, SEL sel) {
                 printf("loadView\n");
         }

         extern (C)
          ObjCMethodOverride("viewDidLoad")
         static void viewDidLoad(ViewController self, SEL sel) {
                 printf("viewDidLoad\n");
         }

         ViewController init()  selector("init");
         mixin RegisterObjCClass;
 }
This looks pretty awesome and very much like something I was looking for. Would really appreciate if you could share your work. Otherwise I'll have to roll up my sleeves and try hacking it on my own :)
Ok, I finally had some time to work this out today. Thanks to the ideas posted here I was able to wrap something up despite my very limited knowledge of D and its compile time features :) Basically this is what your classes will look like: extern (Objective-C) ObjCSuperClass("NSObject") interface AppDelegate : NSApplicationDelegate { mixin ObjCClass; AppDelegate init() selector("init"); extern (C): ObjCMethod("applicationDidFinishLaunching:") static void applicationDidFinishLaunching(AppDelegate self, SEL sel, NSNotification notification) { writefln("applicationDidFinishLaunching"); } } In this case I needed to add the explicit superclass attribute since NSApplicationDelegate is a protocol and not a class. If your object inherits from an interface representing a regular Objective-C class you don't need this. The actual registration and setup principle is based on Jacobs code and I added stuff to handle the attributes. Obviously you need declarations for Objective-C runtime calls but you can find those in Jacobs example source as well. Anyway, hope this helps. Feel free to fork and improve! https://gist.github.com/mrphobby/a247deb15d38aea86b3346079f32ce58
Dec 21 2017
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 14 December 2017 at 19:10:26 UTC, mrphobby wrote:
 This looks pretty awesome and very much like something I was 
 looking for. Would really appreciate if you could share your 
 work. Otherwise I'll have to roll up my sleeves and try hacking 
 it on my own :)
oh sorry i forgot to post this sooner here's my code so far. when i'm reasonably happy with it, it will be part of my simpledisplay.d. I might leave it undocumented, but if you wanted to dive into my source the final version will be in there somewhere. CODE MODULE --------- import helper_module; import core.stdc.math; import core.stdc.stdio; void main() { auto delegate_ = AppDelegate.alloc.init; assert(delegate_, "AppDelegate null"); NSApp.delegate_ = delegate_; NSApp.setActivationPolicy(NSApplicationActivationPolicy.regular); NSApp.run(); } ObjCParentOverride("NSObject") extern (Objective-C) interface AppDelegate : NSApplicationDelegate { mixin IVar!(NSWindow, "window"); mixin IVar!(ViewController, "controller"); extern (C) ObjCMethodOverride("applicationShouldTerminateAfterLastWindowClosed:") static bool applicationShouldTerminateAfterLastWindowClosed(AppDelegate self, SEL sel, NSNotification notification) { return true; } extern (C) ObjCMethodOverride("applicationDidFinishLaunching:") static void applicationDidFinishLaunching(AppDelegate self, SEL sel, NSNotification notification) { NSApp.menu = mainMenu(); immutable style = NSWindowStyleMask.resizable | NSWindowStyleMask.closable | NSWindowStyleMask.miniaturizable | NSWindowStyleMask.titled; auto window = NSWindow.alloc.initWithContentRect( NSMakeRect(10, 10, 300, 300), style, NSBackingStoreType.buffered, false ); window.title = "D Rox"; auto controller = ViewController.alloc.init; window.contentView = controller.view; window.center(); self.window = window; self.controller = controller; window.makeKeyAndOrderFront(null); NSApp.activateIgnoringOtherApps(true); } // copy these two lines on any class typeof(this) init() selector("init"); mixin RegisterObjCClass; } extern (Objective-C) interface ViewController : NSViewController { extern (C) ObjCMethodOverride("loadView") static void loadView(ViewController self, SEL sel) { printf("loadView\n"); } extern (C) ObjCMethodOverride("viewDidLoad") static void viewDidLoad(ViewController self, SEL sel) { printf("viewDidLoad\n"); } ViewController init() selector("init"); mixin RegisterObjCClass; } NSMenu mainMenu() { auto mainMenu = NSMenu.alloc.init("MainMenu".toNSString); auto title = "Apple"; auto menu = NSMenu.alloc.init(title.toNSString); auto item = mainMenu.addItem(title.toNSString, null, "".toNSString); mainMenu.setSubmenu(menu, item); menu.addItem(NSMenuItem.alloc.init("Quit", "stop:", "q")); return mainMenu; } --------- HELPER MODULE: ----- version(OSX) { /* **************************** */ // Obj-C / Cocoa bindings and helpers /* **************************** */ // Special thanks to Jacob Carlborg // see: http://forum.dlang.org/thread/qzitebxwvavcfamsluji forum.dlang.org /// Add an instance var to an Obj-C subclass mixin template IVar(T, string name) { extern(D) final { mixin(" IVarAttr T " ~ name ~ "() { return this.ivar!(name, T); }"); mixin("void " ~ name ~ "(T v) { this.ivar!(name, T) = v; }"); } } /// Add to your extern(Objective-C) interfaces if you need the parent class to be different /// from what in inherits from struct ObjCParentOverride { string parentClassName; } /// Attach to a method like `extern(C) static R name(typeof(this) self, SEL sel, Args...)` /// to give it a selector to override. struct ObjCMethodOverride { string selector; } /// And mix this in to your subclasses of the extern(Objective-C) interfaces mixin template RegisterObjCClass() { mixin ClassTrait; private static objc_method method(alias imp, string selector, const char* type = null)() { return objc_method(sel_registerName(selector.ptr), type, cast(IMP) &imp); } shared static this() { string name = typeof(this).stringof; string parent = "NSObject"; static if(is(typeof(this) P == super)) { parent = P[0].stringof; } foreach(attr; __traits(getAttributes, typeof(this))) { static if(is(typeof(attr) == ObjCParentOverride)) parent = attr.parentClassName; } objc_method[] methods; objc_ivar[] ivars; foreach(member; __traits(derivedMembers, typeof(this))) { foreach(attr; __traits(getAttributes, __traits(getMember, typeof(this), member))) { static if(is(attr == IVarAttr)) { static if(is(typeof(__traits(getMember, typeof(this), member)) R == return)) { ivars ~= objc_ivar(member, "^v", cast(int) log2(R.sizeof), R.sizeof); } } else static if(is(typeof(attr) == ObjCMethodOverride)) { enum sel = attr.selector; // weird hack here, passing attr.selector directly below caused compile errors :S methods ~= method!(__traits(getMember, typeof(this), member), sel); } } } registerClassInternal(name.ptr, parent.ptr, methods, ivars); } } /// leaks memory NSString toNSString(string str) { return NSString.alloc.initWithBytes( cast(immutable(ubyte)*) str.ptr, str.length, NSStringEncoding.NSUTF8StringEncoding ); } /* Rest is private and/or bindings */ enum IVarAttr; void registerClassInternal(const char* name, const char* superClassName, objc_method[] methods, objc_ivar[] ivars = []) { auto superClass = objc_lookUpClass(superClassName); assert(superClass, "Failed to lookup superclass"); auto cls = objc_allocateClassPair(superClass, name, 0); assert(cls, "Failed to allocate class pair"); foreach (method ; methods) { auto result = cls.class_addMethod( method.method_name, method.method_imp, method.method_types ); assert(result, "Failed to add method"); } foreach (objc_ivar ivar ; ivars) { auto result = cls.class_addIvar( ivar.ivar_name, size_t(ivar.space), cast(byte) ivar.ivar_offset, ivar.ivar_type ); assert(result, "Failed to add instance variable"); } objc_registerClassPair(cls); } struct IvarInternal(const char* name, T) { id self; alias value this; T value() { T value; object_getInstanceVariable(self, name, cast(void**) &value); return value; } void opAssign(T value) { object_setInstanceVariable(self, name, cast(void*) value); } } auto ivar(const char* name, T, Self)(Self self) { return IvarInternal!(name, T)(cast(id) self); } extern (Objective-C) enum NSApplicationActivationPolicy : ptrdiff_t { /* The application is an ordinary app that appears in the Dock and may have a user interface. This is the default for bundled apps, unless overridden in the Info.plist. */ regular, /* The application does not appear in the Dock and does not have a menu bar, but it may be activated programmatically or by clicking on one of its windows. This corresponds to LSUIElement=1 in the Info.plist. */ accessory, /* The application does not appear in the Dock and may not create windows or be activated. This corresponds to LSBackgroundOnly=1 in the Info.plist. This is also the default for unbundled executables that do not have Info.plists. */ prohibited }; extern (Objective-C) interface NSApplication : NSResponder { interface Class { mixin MetaclassTrait; NSApplication shared_() selector("sharedApplication"); } extern (D) static NSApplication shared_() { return Class.classof.shared_(); } NSApplicationDelegate delegate_() selector("delegate"); void delegate_(NSApplicationDelegate) selector("setDelegate:"); bool setActivationPolicy(NSApplicationActivationPolicy activationPolicy) selector("setActivationPolicy:"); // use `int` as workaround for https://github.com/ldc-developers/ldc/issues/2387 void activateIgnoringOtherApps(int flag) selector("activateIgnoringOtherApps:"); void run() selector("run"); } extern (Objective-C) __gshared NSApplication NSApp_; NSApplication NSApp() { if(NSApp_ is null) NSApp_ = NSApplication.shared_; return NSApp_; } extern (Objective-C) interface NSApplicationDelegate { void applicationDidFinishLaunching(NSNotification notification) selector("applicationDidFinishLaunching:"); } extern (Objective-C) interface NSColor { private alias This = typeof(this); interface Class { mixin MetaclassTrait; This alloc() selector("alloc"); NSColor redColor() selector("redColor"); } extern (D) { private static Class classof() { return Class.classof; } static This alloc() { return classof.alloc(); } static NSColor redColor() { return classof.redColor; } } CGColorRef CGColor() selector("CGColor"); } enum NSBackingStoreType : size_t { retained = 0, nonretained = 1, buffered = 2 } extern (Objective-C) interface NSMenu : NSObject { mixin ClassTrait; NSMenu init() selector("init"); NSMenu init(NSString title) selector("initWithTitle:"); void setSubmenu(NSMenu menu, NSMenuItem item) selector("setSubmenu:forItem:"); void addItem(NSMenuItem newItem) selector("addItem:"); NSMenuItem addItem( NSString title, SEL selector, NSString charCode ) selector("addItemWithTitle:action:keyEquivalent:"); } extern (Objective-C) interface NSMenuItem : NSObject { mixin ClassTrait; NSMenuItem init() selector("init"); NSMenuItem init( NSString title, SEL selector, NSString charCode ) selector("initWithTitle:action:keyEquivalent:"); extern (D) final { NSMenuItem init(string title, const(char)* selector, string charCode) { return init(title.toNSString, sel_registerName(selector), charCode.toNSString); } } } extern (Objective-C) interface NSResponder : NSObject { mixin ClassTrait; NSMenu menu() selector("menu"); void menu(NSMenu menu) selector("setMenu:"); } extern (Objective-C) interface NSView { mixin ClassTrait; NSView init() selector("init"); NSView initWithFrame(NSRect frameRect) selector("initWithFrame:"); void addSubview(NSView view) selector("addSubview:"); bool wantsLayer() selector("wantsLayer"); // use `int` as workaround for https://github.com/ldc-developers/ldc/issues/2387 void wantsLayer(int value) selector("setWantsLayer:"); CALayer layer() selector("layer"); void uiDelegate(NSObject) selector("setUIDelegate:"); } extern (Objective-C) interface NSViewController : NSObject { NSView view() selector("view"); void view(NSView view) selector("setView:"); } extern (Objective-C) enum NSWindowStyleMask : size_t { borderless = 0, titled = 1 << 0, closable = 1 << 1, miniaturizable = 1 << 2, resizable = 1 << 3, /* Specifies a window with textured background. Textured windows generally don't draw a top border line under the titlebar/toolbar. To get that line, use the NSUnifiedTitleAndToolbarWindowMask mask. */ texturedBackground = 1 << 8, /* Specifies a window whose titlebar and toolbar have a unified look - that is, a continuous background. Under the titlebar and toolbar a horizontal separator line will appear. */ unifiedTitleAndToolbar = 1 << 12, /* When set, the window will appear full screen. This mask is automatically toggled when toggleFullScreen: is called. */ fullScreen = 1 << 14, /* If set, the contentView will consume the full size of the window; it can be combined with other window style masks, but is only respected for windows with a titlebar. Utilizing this mask opts-in to layer-backing. Utilize the contentLayoutRect or auto-layout contentLayoutGuide to layout views underneath the titlebar/toolbar area. */ fullSizeContentView = 1 << 15, /* The following are only applicable for NSPanel (or a subclass thereof) */ utilityWindow = 1 << 4, docModalWindow = 1 << 6, nonactivatingPanel = 1 << 7, // Specifies that a panel that does not activate the owning application hUDWindow = 1 << 13 // Specifies a heads up display panel } extern (Objective-C) interface NSWindow { mixin ClassTrait; NSWindow init() selector("init"); NSWindow initWithContentRect( NSRect contentRect, NSWindowStyleMask style, NSBackingStoreType bufferingType, bool flag ) selector("initWithContentRect:styleMask:backing:defer:"); void makeKeyAndOrderFront(id sender) selector("makeKeyAndOrderFront:"); NSView contentView() selector("contentView"); void orderFrontRegardless() selector("orderFrontRegardless"); void center() selector("center"); void contentView(NSView view) selector("setContentView:"); NSString title() selector("title"); void title(NSString value) selector("setTitle:"); extern (D) final { void title(string value) { this.title = value.toNSString; } } } struct CGColor; alias CGColorRef = CGColor*; alias CGFloat = double; struct NSPoint { CGFloat x; CGFloat y; } struct NSSize { CGFloat width; CGFloat height; } struct NSRect { NSPoint origin; NSSize size; } pragma(inline, true) NSPoint NSMakePoint(CGFloat x, CGFloat y) { NSPoint p; p.x = x; p.y = y; return p; } pragma(inline, true) NSSize NSMakeSize(CGFloat w, CGFloat h) { NSSize s; s.width = w; s.height = h; return s; } pragma(inline, true) NSRect NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h) { NSRect r; r.origin.x = x; r.origin.y = y; r.size.width = w; r.size.height = h; return r; } extern (Objective-C) interface NSNotification { } extern (Objective-C) interface NSObject { mixin ClassTrait; NSObject init() selector("init"); } extern (Objective-C) interface NSString { mixin ClassTrait; NSString init() selector("init"); NSString initWithBytes( const(ubyte)* bytes, NSUInteger length, NSStringEncoding encoding ) selector("initWithBytes:length:encoding:"); } extern (Objective-C) enum NSStringEncoding : NSUInteger { NSASCIIStringEncoding = 1, /* 0..127 only */ NSNEXTSTEPStringEncoding = 2, NSJapaneseEUCStringEncoding = 3, NSUTF8StringEncoding = 4, NSISOLatin1StringEncoding = 5, NSSymbolStringEncoding = 6, NSNonLossyASCIIStringEncoding = 7, NSShiftJISStringEncoding = 8, /* kCFStringEncodingDOSJapanese */ NSISOLatin2StringEncoding = 9, NSUnicodeStringEncoding = 10, NSWindowsCP1251StringEncoding = 11, /* Cyrillic; same as AdobeStandardCyrillic */ NSWindowsCP1252StringEncoding = 12, /* WinLatin1 */ NSWindowsCP1253StringEncoding = 13, /* Greek */ NSWindowsCP1254StringEncoding = 14, /* Turkish */ NSWindowsCP1250StringEncoding = 15, /* WinLatin2 */ NSISO2022JPStringEncoding = 21, /* ISO 2022 Japanese encoding for e-mail */ NSMacOSRomanStringEncoding = 30, NSUTF16StringEncoding = NSUnicodeStringEncoding, /* An alias for NSUnicodeStringEncoding */ NSUTF16BigEndianStringEncoding = 0x90000100, /* NSUTF16StringEncoding encoding with explicit endianness specified */ NSUTF16LittleEndianStringEncoding = 0x94000100, /* NSUTF16StringEncoding encoding with explicit endianness specified */ NSUTF32StringEncoding = 0x8c000100, NSUTF32BigEndianStringEncoding = 0x98000100, /* NSUTF32StringEncoding encoding with explicit endianness specified */ NSUTF32LittleEndianStringEncoding = 0x9c000100 /* NSUTF32StringEncoding encoding with explicit endianness specified */ } alias NSUInteger = size_t; alias NSInteger = ptrdiff_t; mixin template MetaclassTrait() { import std.meta : Alias; alias Parent = Alias!(__traits(parent, typeof(this))); // extern (C) pragma(mangle, "objc_lookUpClass") // static typeof(this) objc_lookUpClass(const(char)* name); extern (D) private static Class classof() { enum name = __traits(identifier, Parent); auto cls = cast(typeof(this)) objc_lookUpClass(name); assert(cls, "Failed to lookup class: " ~ name); return cls; } } mixin template ClassTrait() { extern(Objective-C) interface Class { mixin MetaclassTrait; Parent alloc() selector("alloc"); } extern (D) private static Class classof() { return Class.classof; } extern (D) static typeof(this) alloc() { return classof.alloc(); } } alias objc_ivar* Ivar; alias objc_method* Method; alias objc_object Protocol; alias char* SEL; alias objc_class* Class; alias objc_object* id; alias extern (C) id function(id, SEL, ...) IMP; version (X86) const int STRUCT_SIZE_LIMIT = 8; else version (PPC) const int STRUCT_SIZE_LIMIT = 4; else version (X86_64) const int STRUCT_SIZE_LIMIT = 16; else version (PPC64) const int STRUCT_SIZE_LIMIT = 16; struct objc_object { Class isa; } struct objc_super { id receiver; Class clazz; // for dwt compatibility alias clazz cls; alias clazz super_class; } struct objc_class { Class isa; Class super_class; const char* name; int versionn; int info; int instance_size; objc_ivar_list* ivars; objc_method_list** methodLists; objc_cache* cache; objc_protocol_list* protocols; } struct objc_ivar { const(char)* ivar_name; const(char)* ivar_type; int ivar_offset; version (X86_64) int space; } struct objc_ivar_list { int ivar_count; version (X86_64) int space; /* variable length structure */ objc_ivar[1] ivar_list; } struct objc_method { SEL method_name; const(char)* method_types; IMP method_imp; } struct objc_method_list { objc_method_list* obsolete; int method_count; version (X86_64) int space; /* variable length structure */ objc_method[1] method_list; } struct objc_cache { uint mask /* total = mask + 1 */; uint occupied; Method[1] buckets; } struct objc_protocol_list { objc_protocol_list* next; long count; Protocol*[1] list; } extern (Objective-C) interface CALayer { CGFloat borderWidth() selector("borderWidth"); void borderWidth(CGFloat value) selector("setBorderWidth:"); CGColorRef borderColor() selector("borderColor"); void borderColor(CGColorRef) selector("setBorderColor:"); } extern (C) { bool class_addIvar (Class cls, const(char)* name, size_t size, byte alignment, const(char)* types); bool class_addMethod (Class cls, SEL name, IMP imp, const(char)* types); bool class_addProtocol(Class cls, Protocol* protocol); IMP class_getMethodImplementation(Class cls, SEL name); const(char)* class_getName(Class cls); Class objc_allocateClassPair (Class superclass, const(char)* name, size_t extraBytes); Class objc_getClass (const(char)* name); Protocol* objc_getProtocol(const(char)* name); Class objc_lookUpClass (const(char)* name); void objc_registerClassPair (Class cls); Class object_getClass (id object); const(char)* object_getClassName (id obj); Class object_setClass (id object, Class cls); Ivar object_getInstanceVariable (id obj, const(char)* name, void** outValue); Ivar object_setInstanceVariable (id obj, const(char)* name, void* value); SEL sel_registerName (const(char)* str); // id objc_msgSend (id theReceiver, SEL theSelector, ...); void objc_msgSend_stret(void* stretAddr, id theReceiver, SEL theSelector, ...); id objc_msgSendSuper (objc_super* superr, SEL op, ...); Method class_getClassMethod (Class aClass, SEL aSelector); Method class_getInstanceMethod (Class aClass, SEL aSelector); Class class_getSuperclass (Class cls); IMP method_setImplementation (Method method, IMP imp); id class_createInstance (Class cls, size_t extraBytes); id objc_getMetaClass (char* name); void objc_msgSendSuper_stret(void* stretAddr, objc_super* superContext, SEL theSelector, ...); void instrumentObjcMessageSends(bool val); version (X86) double objc_msgSend_fpret(id self, SEL op, ...); } } -----
Dec 21 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 21 December 2017 at 15:45:32 UTC, Adam D. Ruppe 
wrote:
 oh sorry i forgot to post this sooner here's my code so far.

 when i'm reasonably happy with it, it will be part of my 
 simpledisplay.d. I might leave it undocumented, but if you 
 wanted to dive into my source the final version will be in 
 there somewhere.
Thanks for sharing! Your solution is more complete for sure. I think I will borrow a few ideas here :)
Dec 21 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 21 December 2017 at 17:56:54 UTC, mrphobby wrote:
 Thanks for sharing! Your solution is more complete for sure. I 
 think I will borrow a few ideas here :)
I've been playing around with this a bit and it works pretty well. One thing that bothers me is the handling of NSString. I came up with the following class to handle strings and make sure they do not leak. But maybe there is a nicer way to handle this in D? class NSStringRef { public: this(string s) { str_ = NSString.alloc.initWithBytes(cast(immutable(ubyte)*) s.ptr, s.length, NSStringEncoding.NSUTF8StringEncoding); } ~this() { str_.release(); } NSString str() property { return str_; } private: NSString str_; } And then you have to use it like this: NSStringRef s = new NSStringRef("Hello"); NSLog(s.str); Ideally I would like to write code more like this (without leaking the NSString): NSLog("Hello".nsstring); Surely this must be possible in D somehow? :)
Feb 05
parent reply Jacob Carlborg <doob me.com> writes:
On 2018-02-05 16:49, mrphobby wrote:

 I've been playing around with this a bit and it works pretty well. One 
 thing that bothers me is the handling of NSString. I came up with the 
 following class to handle strings and make sure they do not leak. But 
 maybe there is a nicer way to handle this in D?
Note that this applies to all classes, not just NSString.
 class NSStringRef {
 public:
      this(string s) {
          str_ = NSString.alloc.initWithBytes(cast(immutable(ubyte)*)
s.ptr,
                                   
          s.length,
 NSStringEncoding.NSUTF8StringEncoding);
      }
 
      ~this() {
          str_.release();
      }
Note that this is not deterministic. There's not even a guarantee that a destructor for a class will be run at all.
      NSString str()  property {
          return str_;
      }
 
 private:
      NSString str_;
 }
 
 And then you have to use it like this:
 
      NSStringRef s = new NSStringRef("Hello");
      NSLog(s.str);
You can add an "alias this" [1] to avoid calling "str" explicitly.
 Ideally I would like to write code more like this (without leaking the 
 NSString):
 
      NSLog("Hello".nsstring);
 
 Surely this must be possible in D somehow? :)
Currently the only correct way would be to wrap the class in a struct. There as been some talk to extend the language to support for reference counted classes [2]. [1] https://dlang.org/spec/class.html#alias-this [2] https://wiki.dlang.org/DIP74 -- /Jacob Carlborg
Feb 05
parent mrphobby <mrp spinrock.net> writes:
On Monday, 5 February 2018 at 19:44:37 UTC, Jacob Carlborg wrote:
 Note that this applies to all classes, not just NSString.
Ah yes, I will make sure it works for all the NSObject types.
 class NSStringRef {
 public:
      this(string s) {
          str_ = 
 NSString.alloc.initWithBytes(cast(immutable(ubyte)*) s.ptr,
                                   
          s.length,
 NSStringEncoding.NSUTF8StringEncoding);
      }
 
      ~this() {
          str_.release();
      }
Note that this is not deterministic. There's not even a guarantee that a destructor for a class will be run at all.
Oh I simply tested this by running millions of allocations and it seemed to work but I will have to use a struct then instead I guess.
      NSStringRef s = new NSStringRef("Hello");
      NSLog(s.str);
You can add an "alias this" [1] to avoid calling "str" explicitly.
Ah that's neat!
 Currently the only correct way would be to wrap the class in a 
 struct. There as been some talk to extend the language to 
 support for reference counted classes [2].
Ok that sounds good. However, I'm mostly interested in how to make it work with the tools that are available now :)
Feb 07
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-12-14 14:56, mrphobby wrote:

 Also, it feels a bit awkward to implement the callback handling methods 
 as static methods, with the "self" and SEL arguments. Would have been 
 nice if it was possible to use instance methods.
That's currently not possible. The "self" and SEL arguments are required because that's how Objective-C methods are implemented under the hood.
 After thinking about it for a while I guess it could work with one 
 static dispatch method that maps selectors to specific instance methods. 
 So when callbacks are made from Objective-C they are made to this one 
 static method, which would then call the right method on the class.
It's not possible to use instance methods because: * Interfaces can only have final instance methods * The function needs to have C linkage, which a D instance method cannot have * It's not possible to use classes because then the compiler would complain about missing methods when Objective-C methods are specified without any body
 I'm still struggling with D syntax, so here's some pseudo code:
 
 class AppDelegate {
     static var methodMap = {}    // Maps selector name to methods
 
     static void handleCallback(AppDelegate self, SEL sel, ...) {
        var method = methodMap[sel];
        self.call(method, va_list);      // Call the method with args 
 (not sure if possible in D)
     }
 
     void applicationDidFinishLaunching(NSNotification notification) {
        // Normal instance method here
     }
 }
 
 Now, you would also need a registration step somewhere that sets up the 
 selectors to use, perhaps in a static constructor that is run when 
 AppDelegate class is used for the first time.
 
 I hope this makes sense. Just throwing out some ideas :)
No, that would not work. Several years ago I created an Objective-C bridge [1], which allowed a syntax similar to above: class AppController : NSObject { void foo() {} mixin ObjcBindMethod!foo; } The bridge basically wrapped an Objective-C object inside a D object, resulted in two objects for each object instead of one. That bridge turned out to be a failure, vary complicated, huge amount of template instantiations and bloat from a lot of virtual methods that could not be removed. A simple test application with a window and a button resulted in a 60 MB executable. DIP43 is the next step in the evolution after the bridge and it's a much better approach. When DIP43 is done, or at least has made some more progress it will be much simpler. Please keep in mind that all this is work in progress, that's why it is as complicated now as it is. [1] http://dsource.org/projects/dstep/browser/dstep/objc -- /Jacob Carlborg
Dec 14 2017
parent reply mrphobby <mrp spinrock.net> writes:
On Thursday, 14 December 2017 at 16:12:30 UTC, Jacob Carlborg 
wrote:
 No, that would not work. Several years ago I created an The 
 bridge basically wrapped an Objective-C object inside a D 
 object, resulted in two objects for each object instead of one. 
 That bridge turned out to be a failure, vary complicated, huge 
 amount of template instantiations and bloat from a lot of 
 virtual methods that could not be removed. A simple test 
 application with a window and a button resulted in a 60 MB 
 executable.

 DIP43 is the next step in the evolution after the bridge and 
 it's a much better approach. When DIP43 is done, or at least 
 has made some more progress it will be much simpler.

 Please keep in mind that all this is work in progress, that's 
 why it is as complicated now as it is.

 [1] http://dsource.org/projects/dstep/browser/dstep/objc
Ok, I see! Sounds like I'll have to wait then. How long do you think it will take until DIP43 is available for use? Is it months or years we are talking about here?
Dec 14 2017
parent Jacob Carlborg <doob me.com> writes:
On 2017-12-14 20:06, mrphobby wrote:

 Ok, I see! Sounds like I'll have to wait then. How long do you think it 
 will take until DIP43 is available for use? Is it months or years we are 
 talking about here?
It will take more than months to have the complete set of features of DIP43 available, but many of them are convince features. There are two important features missing: implementing classes and static/class methods. I don't recall right now how much work it was to implement them but I hope it wouldn't take more than a couple of months. Keep in mind that a lot of time is usually spent on reviewing the changes as well before they are merged. Also, this is currently not anything that is prioritized for me, I have other things that I need to complete before I can continue on this. -- /Jacob Carlborg
Dec 14 2017