digitalmars.D.learn - GUI program on Mac OS in D?
- Adam D. Ruppe (7/7) Nov 23 2017 I know we have the extern(Objective-C) stuff from
- Guillaume Piolat (3/11) Nov 23 2017 Perhaps https://github.com/p0nce/DerelictCocoa
- Adam D. Ruppe (5/6) Nov 23 2017 Well, that would be one option, though I was hoping to avoid the
- Jacob Carlborg (29/36) Nov 23 2017 Not as far as I know. Only a small part of what's in DIP43 is merged
- Adam D. Ruppe (20/25) Nov 24 2017 Thanks, this gets me started.
- Jacob Carlborg (31/47) Nov 24 2017 I think you should start by deciding if you want to use any .nib files
- mrphobby (10/27) Dec 06 2017 I'm also interested in making native macOS apps. I have a lot of
- Jacob Carlborg (14/21) Dec 07 2017 The latest DMD compiler only supports what's in the official
- mrphobby (4/9) Dec 08 2017 Ok thanks for clearing that up! Your work looks really appealing.
- Guillaume Piolat (5/9) Dec 07 2017 You can easily make a DUB frontend to do that, for example
- Guillaume Piolat (3/5) Dec 07 2017 And it might be cleaner to do this as a post-build step.
- mrphobby (3/9) Dec 08 2017 Thanks, I'll have a look at that.
- mrphobby (10/18) Dec 13 2017 I have been taking a look at your example. Looks pretty neat!
- Jacob Carlborg (20/30) Dec 13 2017 No, that's correct.
- Jacob Carlborg (9/23) Dec 13 2017 I forgot to mention that there have been several discussions around
- mrphobby (12/16) Dec 13 2017 Ok, good to know!
- Jacob Carlborg (18/25) Dec 14 2017 That is to register the methods with the Objective-C runtime. Currently
- mrphobby (11/17) Dec 14 2017 Ok I understand it now, thanks!
- mrphobby (26/34) Dec 14 2017 Also, it feels a bit awkward to implement the callback handling
- Adam D. Ruppe (26/31) Dec 14 2017 I was playing with this myself based on Jacob's code and made it
- Mengu (3/29) Dec 14 2017 please make it public.
- mrphobby (7/33) Dec 14 2017 This looks pretty awesome and very much like something I was
- mrphobby (27/54) Dec 21 2017 Ok, I finally had some time to work this out today. Thanks to the
- Adam D. Ruppe (637/641) Dec 21 2017 oh sorry i forgot to post this sooner here's my code so far.
- mrphobby (4/9) Dec 21 2017 Thanks for sharing! Your solution is more complete for sure. I
- mrphobby (31/33) Feb 05 2018 I've been playing around with this a bit and it works pretty
- Jacob Carlborg (12/45) Feb 05 2018 Note that this is not deterministic. There's not even a guarantee that a...
- mrphobby (8/30) Feb 07 2018 Oh I simply tested this by running millions of allocations and it
- Jacob Carlborg (31/59) Dec 14 2017 That's currently not possible. The "self" and SEL arguments are required...
- mrphobby (5/19) Dec 14 2017 Ok, I see! Sounds like I'll have to wait then. How long do you
- Jacob Carlborg (12/15) Dec 14 2017 It will take more than months to have the complete set of features of
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
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
On Thursday, 23 November 2017 at 16:14:50 UTC, Guillaume Piolat wrote:Perhaps https://github.com/p0nce/DerelictCocoaWell, 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
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
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
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 timeYes, 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
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
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
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
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/DIP43You 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
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-buildAnd it might be cleaner to do this as a post-build step.
Dec 07 2017
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:Thanks, I'll have a look at that.You can easily make a DUB frontend to do that, for example https://github.com/AuburnSounds/Dplug/tree/master/tools/dplug-buildAnd it might be cleaner to do this as a post-build step.
Dec 08 2017
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
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
On 2017-12-13 16:07, Jacob Carlborg wrote:On 2017-12-13 13:18, mrphobby 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. 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 CarlborgWould 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.
Dec 13 2017
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
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
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 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
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 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
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
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
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
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: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/a247deb15d38aea86b3346079f32ce58I 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 :)
Dec 21 2017
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
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
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 2018
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 2018
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.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.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.Ah that's neat!   NSStringRef s = new NSStringRef("Hello");    NSLog(s.str);You can add an "alias this" [1] to avoid calling "str" explicitly.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 2018
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 bodyI'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
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/objcOk, 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
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