Re: Subclassing NSWindowController in Swift
> On Oct 19, 2014, at 02:14 , Quincey Morris > wrote: > > Ugh! Now you made me create a project to try it. Heh. Let's try this: Swift sucks; it can't make a million dollars appear on my doorstep. > Or maybe someone else has a better solution. Yeah. Load my nib in -loadWindow ;-) -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
On Oct 19, 2014, at 01:28 , Rick Mann wrote: > >> you will need to declare it “convenience”. > > Tried that, too. Ugh! Now you made me create a project to try it. It looks like the problem is that ‘init’ is already a designated initializer, though not of NSWindowController. That means it’s neither inherited (which seems correct), nor overridable as a convenience initializer (which is conceivably a bug, since I don’t see that it can be invoked at all from the subclass of NSWindowController, so it may as well be invisible to it). Therefore, I’d be inclined to solve it by either: — providing a factory method that directly invokes the existing convenience init that takes a “windowNibName” parameter, so that you don’t use the parameterless init at all, or — (if I had other parameters to pass) declare a convenience init that has a different signature: convenience init (somethingElse: SomeType) { self.init(windowNibName: "abc”) … do things with somethingElse … } or do the latter plus a factory method to invoke it. Or maybe someone else has a better solution. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 19, 2014, at 01:27 , Quincey Morris > wrote: > >> On Oct 19, 2014, at 01:20 , Rick Mann wrote: >> >> I don't remember now, but I think it complained that I was overriding an >> inherited method. > > Well, double-checking the syntax earlier in the chapter, you will need to > declare it “convenience”. Tried that, too. -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 19, 2014, at 01:20 , Rick Mann wrote: > > I don't remember now, but I think it complained that I was overriding an > inherited method. Well, double-checking the syntax earlier in the chapter, you will need to declare it “convenience”. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 19, 2014, at 01:19 , Quincey Morris > wrote: > > In short, take the “override” keyword off your declaration, and it should > work exactly as you expected. (!) I don't remember now, but I think it complained that I was overriding an inherited method. -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
On Oct 19, 2014, at 00:56 , Rick Mann wrote: > > The subclass initializer still has to initialize itself. It knows what the > superclass initializer is doing, and it knows what it still needs to do. > That's true even with the rules Swift currently imposes. I don’t actually know what “initialize itself” means. Nor do I see how it “knows” what the superclass is doing, or at least I’m uncertain how this helps. >> In Swift, an external caller cannot initialize a class by calling one of its >> superclass initializers > Of course, not, and I'm not suggesting that at all. FWIW, I’m not sure there’s an “of course” here. In Obj-C, of course it can literally do this. However, going back to your original post, you wrote this: > I tried this: > > 16override > 17init() > 18{ > 19init(windowNibName: "foo", owner: self); > 20} Re-reading the Swift book to research my answers in this thread, I found this: > “If your subclass provides an implementation of all of its > superclass-designated initializers—either by inheriting them as per rule 1, > or […] — then it automatically inherits all of the superclass convenience > initializers.” According to that, your original attempt should have worked, but it didn’t because of a wrinkle: > “[I]f you write a subclass initializer that matches a superclass convenience > initializer, that superclass convenience initializer can never be called > directly by your subclass […]. Therefore, you don not write the override > modifier when providing a matching implementation of a superclass convenience > initializer.” In short, take the “override” keyword off your declaration, and it should work exactly as you expected. (!) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
>> >> (It’s all about the “yes, but”s.) >> >> … calling *up* from a subclass convenience initializer bypasses all of the >> subclass designated initializers (except in the case that the subclass >> overrides some or all of the superclass's, which introduces its own semantic >> ambiguities). That means that the subclass can’t be sure it initialized its >> own properties, since that’s the purview of designated initializers — at >> least not without supplementary rules. That in turn destroys the integrity >> of Swift’s 2-pass initialization process. > > Well, I'm not sure I agree with that. Every initializer in a class should > work correctly. An external caller can initialize a class by calling any of > its init methods, why can't a subclass? > > At the very least, NSWindowController's choice of designated initializer > increases the burden on subclasses. I’ve thought about the initializer rules quite a bit, convinced at each point that they are too onerous .. and almost always find a reason they aren’t. One that troubled me particularly is why a designated initializer can only call up to another designated initializer and not a convenience one. Surely I thought the convenience one in the superclass must call across as the first thing it does, so a designated initializer in the superclass will thus be called .. where’s the problem. The problem is of course that the designated initializer in the superclass called by the convenience method may have been overridden in the subclass, and that’s the one which would then be called, so you end up calling two different designated initializers for the same class, the one you started from, and the one called by the superclass convenience one you overrode. If you force designated initializers to call only superclass designated initializers, you know you are always going ‘up’. Hence the rule. Hence all the rules. You could add more rules. If you have no non-default properties in your subclass and don’t implement any designated initializers (you wouldn’t have to) then it would be safe for a convenience one to call up to a superclass convenience one. But now we have more rules and as soon as you do add a property you need to initialize and thus have to add an initializer, your class won’t compile any more. I think one of the problems is that if NSWindowController had been originally written in Swift, or in fact if Cocoa had been, then its initializers wouldn’t look quite like they do. That’s just some of the friction between the wild west of Cocoa we’ve all been enjoying for years and the new school mistress of Swift who insists on the rules. It does actually make you do things you should always have done, like subclass initWithCoder:. I hope Xcode will get better at templating out classes or adding stub methods for all designated/required initializers at some point (on request) so that the coding burden reduces. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 19, 2014, at 00:54 , Quincey Morris > wrote: > > If, hypothetically, a subclass was allowed to call any initializer in the > superclass, then the result would be an object that was fully (“correctly”) > initialized in terms of the superclass, but that doesn’t mean it’s fully > initialized in terms of the subclass. The subclass initializer still has to initialize itself. It knows what the superclass initializer is doing, and it knows what it still needs to do. That's true even with the rules Swift currently imposes. > In Swift, an external caller cannot initialize a class by calling one of its > superclass initializers — formally. In practice, there are two cases: Of course, not, and I'm not suggesting that at all. -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
On Oct 19, 2014, at 00:24 , Rick Mann wrote: > > Well, I'm not sure I agree with that. Every initializer in a class should > work correctly. If, hypothetically, a subclass was allowed to call any initializer in the superclass, then the result would be an object that was fully (“correctly”) initialized in terms of the superclass, but that doesn’t mean it’s fully initialized in terms of the subclass. This distinction just doesn’t apply to Obj-C. The difference is that in Obj-C you never initialize any instance storage *before* calling “up” (aside from the automatic zeroing of it all). In Swift, you may. > An external caller can initialize a class by calling any of its init methods, > why can't a subclass? In Swift, an external caller cannot initialize a class by calling one of its superclass initializers — formally. In practice, there are two cases: 1. The subclass declares *no* designated initializers, in which case it inherits all of the superclass designated initializers. In this case, external callers still aren’t really calling a superclass initializer, just something that looks like it. 2. The subclass declares its own designated initializers (either overrides or not). In this case, external callers can only call initializers that are declared in the subclass, and nothing is inherited externally. Case #2 formalizes something that is currently unsafe in Obj-C. Case #1 allows many existing Obj-C class patterns to be safely usable in Swift without additional coding. There is no case #3 that partially overlaps #1 and #2, since it would generally be unsafe. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 19, 2014, at 00:19 , Quincey Morris > wrote: > > On Oct 18, 2014, at 23:46 , Rick Mann wrote: >> >> The rules on initializers don't make sense to me, in all honesty. > > Yes, but that tells us more about you than about Swift — specifically, it > tells us that you’re more focused on what would ease your coding task in this > one case than on embracing more formal relationships between initializers. > Understandable, but not really useful to anyone else, if you’ll forgive my > saying so. > >> If you imagine that instantiating the base class by calling any of the >> initializers results in a completely instantiated object, the subclass >> should also be able to call any of the inherited initializers. > > Yes, but … > > (It’s all about the “yes, but”s.) > > … calling *up* from a subclass convenience initializer bypasses all of the > subclass designated initializers (except in the case that the subclass > overrides some or all of the superclass's, which introduces its own semantic > ambiguities). That means that the subclass can’t be sure it initialized its > own properties, since that’s the purview of designated initializers — at > least not without supplementary rules. That in turn destroys the integrity of > Swift’s 2-pass initialization process. Well, I'm not sure I agree with that. Every initializer in a class should work correctly. An external caller can initialize a class by calling any of its init methods, why can't a subclass? At the very least, NSWindowController's choice of designated initializer increases the burden on subclasses. -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
On Oct 18, 2014, at 23:46 , Rick Mann wrote: > > The rules on initializers don't make sense to me, in all honesty. Yes, but that tells us more about you than about Swift — specifically, it tells us that you’re more focused on what would ease your coding task in this one case than on embracing more formal relationships between initializers. Understandable, but not really useful to anyone else, if you’ll forgive my saying so. > If you imagine that instantiating the base class by calling any of the > initializers results in a completely instantiated object, the subclass should > also be able to call any of the inherited initializers. Yes, but … (It’s all about the “yes, but”s.) … calling *up* from a subclass convenience initializer bypasses all of the subclass designated initializers (except in the case that the subclass overrides some or all of the superclass's, which introduces its own semantic ambiguities). That means that the subclass can’t be sure it initialized its own properties, since that’s the purview of designated initializers — at least not without supplementary rules. That in turn destroys the integrity of Swift’s 2-pass initialization process. The reason that the Swift rules make you uncomfortable is that the Obj-C rules for initializers are comfortably loose, to say the least. It’s always an option to go on using Obj-C, of course. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 18, 2014, at 23:38 , Roland King wrote: > > > The very first of those errors looks like you had the code in the wrong > place, ie not within your class. > > Initialization is one of those Swift things which is uber-safe and thus very > structured and hence in practice annoying. > > You can read all the rules in the book but it boils down to everything goes > through the designated initializers at some point. That includes , in this > case, the convenience initializer init( windowNibName, owner ), the > implementation of that eventually calls one of the two designated > initializers, init( window: ) or init( coder: ). Those designated ones are > what you need to customize/orerride in your class to do any extra > initialization required. You can then still call init( windowNibName:, owner: > ) and eventually one of those two designated initializers will get called, > the ones you overrode. > > But, you cry, I only want to do some piece of work if init( windowNibName:, > owner: ) was the initializer called, I want to call super on that and then .. > I dunno .. log the name of the nib or something, but you can’t. You can > re-implement it, if you get all its side effects correct, but you can’t call > the superclass version. Nor do you know, when you finally get called in your > override of the designated initializer, how you got there. > > Oh and yes if you override any of the designated initializers then you have > to override all the required ones at least as you don’t inherit them any > more. Also, if you want to inherit the convenience initializers then you have > to have all the designated ones, so if you’ve overidden one then you have to > do the lot, whether or not they are required. > > confused yet? > > And that ‘not accessing self’ thing. That normally comes up when you need > self to do something to initialize a property, but you can’t because you > can’t call super anything until you have initialized your properties and you > can’t use self until you’ve called super. The usual .. technique .. is to > make that property optional, or implicitly unwrapped optional, set it to nil > so it’s set enough to call super, then you can use self to find what you > REALLY wanted it to be and set it again. :-) The rules on initializers don't make sense to me, in all honesty. If you imagine that instantiating the base class by calling any of the initializers results in a completely instantiated object, the subclass should also be able to call any of the inherited initializers. But whatevs, I'm on to storyboards now. -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On 19 Oct 2014, at 11:42 am, Rick Mann wrote: > > >> On Oct 18, 2014, at 20:33 , Graham Cox wrote: >> >> According to the latest documentation pack that arrived on Thursday, Swift >> has: >> >> convenience init(windowNibName windowNibName: String, >> owner owner: AnyObject) >> >> So just use this. Like C++, Swift has overloaded method names, so 'init' can >> take various parameter combinations. > > I tried this: > > 16override > 17init() > 18{ > 19init(windowNibName: "foo", owner: self); > 20} > 21 > > But I get: > > /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:7: > Initializers may only be declared within a type > /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:23: > Expected parameter type following ':' > /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:23: > Expected ',' separator > /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:21:1: > 'required' initializer 'init(coder:)' must be provided by subclass of > 'NSWindowController' > > If I instead call super.init(...), I get: > > /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:3: Must > call a designated initializer of the superclass 'NSWindowController' The very first of those errors looks like you had the code in the wrong place, ie not within your class. Initialization is one of those Swift things which is uber-safe and thus very structured and hence in practice annoying. You can read all the rules in the book but it boils down to everything goes through the designated initializers at some point. That includes , in this case, the convenience initializer init( windowNibName, owner ), the implementation of that eventually calls one of the two designated initializers, init( window: ) or init( coder: ). Those designated ones are what you need to customize/orerride in your class to do any extra initialization required. You can then still call init( windowNibName:, owner: ) and eventually one of those two designated initializers will get called, the ones you overrode. But, you cry, I only want to do some piece of work if init( windowNibName:, owner: ) was the initializer called, I want to call super on that and then .. I dunno .. log the name of the nib or something, but you can’t. You can re-implement it, if you get all its side effects correct, but you can’t call the superclass version. Nor do you know, when you finally get called in your override of the designated initializer, how you got there. Oh and yes if you override any of the designated initializers then you have to override all the required ones at least as you don’t inherit them any more. Also, if you want to inherit the convenience initializers then you have to have all the designated ones, so if you’ve overidden one then you have to do the lot, whether or not they are required. confused yet? And that ‘not accessing self’ thing. That normally comes up when you need self to do something to initialize a property, but you can’t because you can’t call super anything until you have initialized your properties and you can’t use self until you’ve called super. The usual .. technique .. is to make that property optional, or implicitly unwrapped optional, set it to nil so it’s set enough to call super, then you can use self to find what you REALLY wanted it to be and set it again. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
> On Oct 18, 2014, at 20:33 , Graham Cox wrote: > > According to the latest documentation pack that arrived on Thursday, Swift > has: > > convenience init(windowNibName windowNibName: String, > owner owner: AnyObject) > > So just use this. Like C++, Swift has overloaded method names, so 'init' can > take various parameter combinations. I tried this: 16 override 17 init() 18 { 19 init(windowNibName: "foo", owner: self); 20 } 21 But I get: /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:7: Initializers may only be declared within a type /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:23: Expected parameter type following ':' /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:23: Expected ',' separator /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:21:1: 'required' initializer 'init(coder:)' must be provided by subclass of 'NSWindowController' If I instead call super.init(...), I get: /Users/rmann/Projects/XCAM/repo/XNC/trunk/XNC/CommConfig.swift:19:3: Must call a designated initializer of the superclass 'NSWindowController' > Also, in general I think what you're saying about designated initializers is > incorrect - the designated initializer MUST be called, but not necessarily by > you. All it means is that the other init... methods must call it. The > guideline about it being the one with the most parameters is not a rule - > typically that's true but it's not a requirement and for many classes, > definitely not true. In this case, it might've solved the problem (except that I can't refer to self yet). > > > --Graham > > > > > > On 19 Oct 2014, at 2:08 pm, Rick Mann wrote: > >> In Obj-C, I typically subclass NSWindowController and override -init to call >> -initWithNibName:. I do this so the caller doesn't have to worry about how >> to make one of these window controllers: >> >> @implementation MyWindowController >> >> - (id) init >> { >> self = [super initWithWindowNibName: "MyWindow" owner: self] >> ... >> return self; >> } >> >> I can't figure out how to do the same in Swift. NSWindowController makes >> initWithWindow() the only designated initializer, which I must call, which >> makes it seem like I can't use any of the convenience methods. Apple's own >> guidance on designated inititalizers is that they should be the ones that >> take the most parameters. >> >> So, I can load the nib myself, and make the window, and pass that up, but >> this seems broken. Is it? > > > ___ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/rmann%40latencyzero.com > > This email sent to rm...@latencyzero.com -- Rick Mann rm...@latencyzero.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Subclassing NSWindowController in Swift
Hi Rick, According to the latest documentation pack that arrived on Thursday, Swift has: convenience init(windowNibName windowNibName: String, owner owner: AnyObject) So just use this. Like C++, Swift has overloaded method names, so 'init' can take various parameter combinations. Also, in general I think what you're saying about designated initializers is incorrect - the designated initializer MUST be called, but not necessarily by you. All it means is that the other init... methods must call it. The guideline about it being the one with the most parameters is not a rule - typically that's true but it's not a requirement and for many classes, definitely not true. --Graham On 19 Oct 2014, at 2:08 pm, Rick Mann wrote: > In Obj-C, I typically subclass NSWindowController and override -init to call > -initWithNibName:. I do this so the caller doesn't have to worry about how to > make one of these window controllers: > > @implementation MyWindowController > > - (id) init > { >self = [super initWithWindowNibName: "MyWindow" owner: self] >... >return self; > } > > I can't figure out how to do the same in Swift. NSWindowController makes > initWithWindow() the only designated initializer, which I must call, which > makes it seem like I can't use any of the convenience methods. Apple's own > guidance on designated inititalizers is that they should be the ones that > take the most parameters. > > So, I can load the nib myself, and make the window, and pass that up, but > this seems broken. Is it? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com