Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.objective-c > #215 > unrolled thread

A question on designated initializers

Started byJon Rossen <jonr17@comcast.net>
First post2015-11-22 13:39 -0800
Last post2015-11-24 18:29 -0800
Articles 12 on this page of 32 — 5 participants

Back to article view | Back to comp.lang.objective-c


Contents

  A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 13:39 -0800
    Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 14:48 -0800
      Re: A question on designated initializers Louis Wu <louiswu@ringworld.net> - 2015-11-22 16:26 -0800
        Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 17:24 -0800
          Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-23 02:39 +0100
    Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-23 01:18 +0100
      Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-22 16:49 -0800
        Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-23 02:02 +0100
          Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-27 17:19 -0800
            Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-28 13:22 +0100
              Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-28 17:37 -0800
                Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-29 03:45 +0100
    Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-22 19:15 -0800
      Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-23 18:44 -0800
        Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-24 04:58 +0100
          Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-24 16:42 -0800
            Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 02:00 +0100
          Re: A question on designated initializers Greg Parker <gparker@apple.com> - 2015-11-25 01:25 -0800
        Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-24 07:38 -0800
          Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-24 15:54 -0800
            Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 01:49 +0100
              Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-24 18:51 -0800
                Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 04:41 +0100
                  Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-25 00:25 -0800
                    Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 14:16 +0100
                      Re: A question on designated initializers Jon Rossen <jonr17@comcast.net> - 2015-11-25 17:30 -0800
                        Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-26 03:03 +0100
                  Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-25 09:08 -0800
                    Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-11-25 18:41 +0100
                      Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-12-02 14:37 -0800
                        Re: A question on designated initializers "Pascal J. Bourguignon" <pjb@informatimago.com> - 2015-12-03 00:58 +0100
            Re: A question on designated initializers Don Bruder <dakidd@sonic.net> - 2015-11-24 18:29 -0800

Page 2 of 2 — ← Prev page 1 [2]


#229

From"Pascal J. Bourguignon" <pjb@informatimago.com>
Date2015-11-25 01:49 +0100
Message-ID<87oaeivr7a.fsf@kuiper.lan.informatimago.com>
In reply to#227
Jon Rossen <jonr17@comcast.net> writes:

> Ok....but backing up to the beginning of your paragraph:
> Hmmm, you lost me when you brought up your 'naked init' and said that
> it 'passes some reasonable defaults into the designated initializer'.
> The naked init in the current class just calls the current class'
> designated initializer and returns it.  How does it pass some
> reasonable defaults *into it*??  

"pass" as in "argument PASSing".  We're assuming the designated
initializer will take at least one argument, since otherwise there's
would be little reason for it to exist (it would just be a renaming of
the init method).  This passed argument is a default value specified by
-init.


> Might you be referring to the naked init that is the *superclass* of
> the current class?  Certainly the super's init does that when you do
> self = [super init].  I just don't understand how the init at the
> current level feeds anything into the designated initializer at that
> same level.

  -(id)init{return [self initWithWidth:1 andHeight:1];}

the defaults are 1 for the width, and 1 for the height.



> Speaking of nitpicks, in your code examples why don't you use
> (instancetype) as your return type?

I don't because I don't believe much in static typing.  I'm more a
dynamic typing guy, so I'm happy with using id.


Also, I'm not in a hurry, I can wait 300 ms more to get the right
results.


>> You'll notice how close to identical the code is for both cases - The
>> critical consideration is that you ALWAYS want your class' "init" to
>> chain back to the root object, whether directly or indirectly.
>
> Not only are they close, aren't they basically *the exact same code*
> structurally?  Meaning apart from the class-specific stuff that would
> be needed (different name of designated initializer, additional
> parameters, etc., etc.), the framework here is exactly the same as it
> was for the subclass (MyClass).  I would *expect* it to be the same
> seeing that it's keeping the init chaining intact.  Am I missing
> something or am I 'getting it'?

I don't agree with Don's code.  

In general the subclass should call:
   [super designatedInitializer:argument]
and not [super init], in its -designatedInitializer: method.

Notably, when the argument is given as a parameter to the subclass
-designatedInitializer:!


-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

[toc] | [prev] | [next] | [standalone]


#232

FromDon Bruder <dakidd@sonic.net>
Date2015-11-24 18:51 -0800
Message-ID<n337jb$6mt$2@dont-email.me>
In reply to#229
In article <87oaeivr7a.fsf@kuiper.lan.informatimago.com>,
 "Pascal J. Bourguignon" <pjb@informatimago.com> wrote:


> I don't agree with Don's code.  
> 
> In general the subclass should call:
>    [super designatedInitializer:argument]
> and not [super init], in its -designatedInitializer: method.
> 
> Notably, when the argument is given as a parameter to the subclass
> -designatedInitializer:!

OK, now *I'M* confused... Lemme go look at the code...
Now that I've gone and looked, I'm gonna update that to "I'm COMPLETELY 
lost!" Please snatch in a copy of the code you're talking about and 
annotate it to tell me specifically what it is you consider wrong with 
it. I can't see anything (which is not to say it's impossible for me to 
be wrong - only that if I am, I'm not seeing how or where based on what 
you said), and I can't parse what you're saying up there in any way that 
seems to make sense.

Never mind snatching it in... I've got it here, and I still can't see 
what might be wrong.

???

> ---cut---
> #import <Cocoa/Cocoa.h>
> 
> @interface MyClass : NSObject 
> {
>    // MyClass specific vars
>    NSDictionary *myClassVars;
> }
> // And some method declarations
> -(MyClass *)designatedInitializer:(id)anyNeededParams;
> -(MyClass *)init;
> // More stuff will likely live here in a useful program.
> @end
> ---cut---
> 
> And in your .m file:
> ---cut---
> #import "MyClass.h"
> @implementation MyClass
> 
> -(MyClass *)designatedInitializer:(id)anyNeededParams
> {
>    self = [super init]; // Invoke NSObject's init
>    
>    // Do MyClass-specific init
> 
>    // and return what self has become.
>    return self;
> }
> 
> -(MyClass *)init
> {
>    // I'll assume defaultParams is set appropriately elsewhere
>    return [self designatedInitializer:defaultParams];
> }
> 
> // Any other methods MyClass needs follow
> @end
> ---cut---

> ---cut---
> #import "MyClass.h"
> @interface MySublass : MyClass
> {
>    // MySublass specific vars
>    NSDictionary *SubclassVar;
> }
> // And don't forget the method declarations
> -(MyClass *)designatedInitializer:(id)anyNeededParams;
> -(MyClass *)init;
> 
> @end
> ---cut---
> 
> And the .m file
> ---cut---
> #import "MySubclass.h"
> -(MySubclass *)designatedInitializer:(id)anyNeededParams
> {
>    self = [super init]; // Invokes MyClass' init
>    
>    // Do MySubclass-specific init work
> 
>    // and return what self has become.
>    return self;
> }
> 
> -(MySubclass *)init
> {
>    // I'll assume defaultMySubclassParams is set appropriately somewhere
>    return [self designatedInitializer:defaultMySubclassParams];
> }
> 
> // Any other methods MySubclass needs follow
> 
> @end
> ---cut---

-- 
Security provided by Mssrs Smith and/or Wesson. Brought to you by the letter Q

[toc] | [prev] | [next] | [standalone]


#233

From"Pascal J. Bourguignon" <pjb@informatimago.com>
Date2015-11-25 04:41 +0100
Message-ID<87d1uyvj8a.fsf@kuiper.lan.informatimago.com>
In reply to#232
Don Bruder <dakidd@sonic.net> writes:

> In article <87oaeivr7a.fsf@kuiper.lan.informatimago.com>,
>  "Pascal J. Bourguignon" <pjb@informatimago.com> wrote:
>
>
>> I don't agree with Don's code.  
>> 
>> In general the subclass should call:
>>    [super designatedInitializer:argument]
>> and not [super init], in its -designatedInitializer: method.
>> 
>> Notably, when the argument is given as a parameter to the subclass
>> -designatedInitializer:!
>
> OK, now *I'M* confused... Lemme go look at the code...
> Now that I've gone and looked, I'm gonna update that to "I'm COMPLETELY 
> lost!" Please snatch in a copy of the code you're talking about and 
> annotate it to tell me specifically what it is you consider wrong with 
> it. I can't see anything (which is not to say it's impossible for me to 
> be wrong - only that if I am, I'm not seeing how or where based on what 
> you said), and I can't parse what you're saying up there in any way that 
> seems to make sense.
>
> Never mind snatching it in... I've got it here, and I still can't see 
> what might be wrong.
>
> ???
>
>> ---cut---
>> #import <Cocoa/Cocoa.h>
>> 
>> @interface MyClass : NSObject 
>> {
>>    // MyClass specific vars
>>    NSDictionary *myClassVars;
>> }
>> // And some method declarations
>> -(MyClass *)designatedInitializer:(id)anyNeededParams;
>> -(MyClass *)init;
>> // More stuff will likely live here in a useful program.
>> @end
>> ---cut---
>> 
>> And in your .m file:
>> ---cut---
>> #import "MyClass.h"
>> @implementation MyClass
>> 
>> -(MyClass *)designatedInitializer:(id)anyNeededParams
>> {
>>    self = [super init]; // Invoke NSObject's init
>>    
>>    // Do MyClass-specific init
>> 
>>    // and return what self has become.
>>    return self;
>> }
>> 
>> -(MyClass *)init
>> {
>>    // I'll assume defaultParams is set appropriately elsewhere
>>    return [self designatedInitializer:defaultParams];
>> }
>> 
>> // Any other methods MyClass needs follow
>> @end
>> ---cut---
>
>> ---cut---
>> #import "MyClass.h"
>> @interface MySublass : MyClass
>> {
>>    // MySublass specific vars
>>    NSDictionary *SubclassVar;
>> }
>> // And don't forget the method declarations
>> -(MyClass *)designatedInitializer:(id)anyNeededParams;
>> -(MyClass *)init;
>> 
>> @end
>> ---cut---
>> 
>> And the .m file
>> ---cut---
>> #import "MySubclass.h"
>> -(MySubclass *)designatedInitializer:(id)anyNeededParams
>> {
>>    self = [super init]; // Invokes MyClass' init

This.  The designated initializer of the super class (ie. the MyClass
class), is designatedInitializer: ; therefore this is the designated
initializer you must call from the subclass.
Since you call [super init], -[MyClass init] will send the
-designatedInitializer:  message to self, which will call 
-[MySubclass designatedInitializer:] and this will give an infinite
loop.



>>    // Do MySubclass-specific init work
>> 
>>    // and return what self has become.
>>    return self;
>> }
>> 
>> -(MySubclass *)init
>> {
>>    // I'll assume defaultMySubclassParams is set appropriately somewhere
>>    return [self designatedInitializer:defaultMySubclassParams];
>> }
>> 
>> // Any other methods MySubclass needs follow
>> 
>> @end
>> ---cut---

-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

[toc] | [prev] | [next] | [standalone]


#234

FromJon Rossen <jonr17@comcast.net>
Date2015-11-25 00:25 -0800
Message-ID<n33r9o$27f$1@news.albasani.net>
In reply to#233
On 11/24/2015 7:41 PM, Pascal J. Bourguignon wrote:
> Don Bruder <dakidd@sonic.net> writes:
>
>> In article <87oaeivr7a.fsf@kuiper.lan.informatimago.com>,
>>   "Pascal J. Bourguignon" <pjb@informatimago.com> wrote:
>>
>>
>>> I don't agree with Don's code.
>>>
>>> In general the subclass should call:
>>>     [super designatedInitializer:argument]
>>> and not [super init], in its -designatedInitializer: method.
>>>
>>> Notably, when the argument is given as a parameter to the subclass
>>> -designatedInitializer:!
>>
>> OK, now *I'M* confused... Lemme go look at the code...
>> Now that I've gone and looked, I'm gonna update that to "I'm COMPLETELY
>> lost!" Please snatch in a copy of the code you're talking about and
>> annotate it to tell me specifically what it is you consider wrong with
>> it. I can't see anything (which is not to say it's impossible for me to
>> be wrong - only that if I am, I'm not seeing how or where based on what
>> you said), and I can't parse what you're saying up there in any way that
>> seems to make sense.
>>
>> Never mind snatching it in... I've got it here, and I still can't see
>> what might be wrong.
>>
>> ???
>>
>>> ---cut---
>>> #import <Cocoa/Cocoa.h>
>>>
>>> @interface MyClass : NSObject
>>> {
>>>     // MyClass specific vars
>>>     NSDictionary *myClassVars;
>>> }
>>> // And some method declarations
>>> -(MyClass *)designatedInitializer:(id)anyNeededParams;
>>> -(MyClass *)init;
>>> // More stuff will likely live here in a useful program.
>>> @end
>>> ---cut---
>>>
>>> And in your .m file:
>>> ---cut---
>>> #import "MyClass.h"
>>> @implementation MyClass
>>>
>>> -(MyClass *)designatedInitializer:(id)anyNeededParams
>>> {
>>>     self = [super init]; // Invoke NSObject's init
>>>
>>>     // Do MyClass-specific init
>>>
>>>     // and return what self has become.
>>>     return self;
>>> }
>>>
>>> -(MyClass *)init
>>> {
>>>     // I'll assume defaultParams is set appropriately elsewhere
>>>     return [self designatedInitializer:defaultParams];
>>> }
>>>
>>> // Any other methods MyClass needs follow
>>> @end
>>> ---cut---
>>
>>> ---cut---
>>> #import "MyClass.h"
>>> @interface MySublass : MyClass
>>> {
>>>     // MySublass specific vars
>>>     NSDictionary *SubclassVar;
>>> }
>>> // And don't forget the method declarations
>>> -(MyClass *)designatedInitializer:(id)anyNeededParams;
>>> -(MyClass *)init;
>>>
>>> @end
>>> ---cut---
>>>
>>> And the .m file
>>> ---cut---
>>> #import "MySubclass.h"
>>> -(MySubclass *)designatedInitializer:(id)anyNeededParams
>>> {
>>>     self = [super init]; // Invokes MyClass' init
>
> This.  The designated initializer of the super class (ie. the MyClass
> class), is designatedInitializer: ; therefore this is the designated
> initializer you must call from the subclass.
> Since you call [super init], -[MyClass init] will send the
> -designatedInitializer:  message to self, which will call
> -[MySubclass designatedInitializer:] and this will give an infinite
> loop.

Pascal, I also noticed that you and Don had different code for the 
designated initializer and forgot to ask about it; thanks for bringing 
it up.

Don uses:  self = [super init];
while you use: self = [super designatedInitializer];

I'm not sure if I'm following your code path here.  If someone uses 
Don's method, [super init] is called, and it returns a 
designatedInitializer message to self.  Then you lose me when you say 
'which will call [MySubClass designatedInitializer]' which as you say 
will give an infinite loop.  I don't understand the call to [MySubClass 
designatedInitializer].

It was my understanding you end up traversing *up* the inheritance 
branch to the root class:  You call super's init, it returns a message 
to self from *super's* designatedIniializer which has a call to *its* 
[super init], which returns a message to self from the designated 
initializer at its level, and the pattern keeps repeating until you get 
up to the end.  Everything that is inherited by the current class gets 
initialized.
Then after self = [super init];
You make sure that  self exists (i.e. initialization was successful): if 
(self)
{ put your init code in the code block of the if statement }

So essentially the first part where you state:  self = [super init] 
serves to go back up the inheritance branch and initialize all the 
inherited stuff.  This is how the stuff is all 'chained' together. while 
the new init code you put in the if() statement is the new, current 
class specific init code specific to the current class.

If my understanding of this is flawed, please let me know where.


>
>
>>>     // Do MySubclass-specific init work
>>>
>>>     // and return what self has become.
>>>     return self;
>>> }
>>>
>>> -(MySubclass *)init
>>> {
>>>     // I'll assume defaultMySubclassParams is set appropriately somewhere
>>>     return [self designatedInitializer:defaultMySubclassParams];
>>> }
>>>
>>> // Any other methods MySubclass needs follow
>>>
>>> @end
>>> ---cut---
>

[toc] | [prev] | [next] | [standalone]


#236

From"Pascal J. Bourguignon" <pjb@informatimago.com>
Date2015-11-25 14:16 +0100
Message-ID<878u5muslu.fsf@kuiper.lan.informatimago.com>
In reply to#234
Jon Rossen <jonr17@comcast.net> writes:

> Pascal, I also noticed that you and Don had different code for the
> designated initializer and forgot to ask about it; thanks for bringing
> it up.
>
> Don uses:  self = [super init];
> while you use: self = [super designatedInitializer];
>
> I'm not sure if I'm following your code path here.  If someone uses
> Don's method, [super init] is called, and it returns a
> designatedInitializer message to self.  Then you lose me when you say
> which will call [MySubClass designatedInitializer]' which as you say
> will give an infinite loop.  I don't understand the call to
> [MySubClass designatedInitializer].


You have to understand the difference between a MESSAGE and a METHOD.

To send a message we indicate:

- a recipient object for that message, (eg. self);
- a selector, (eg. designatedInitializer:);
- arguments, (eg. defaultValue).

Sending a message is therefore written:

   [self designatedInitializer:defaultValue]

The selector is denoted as designatedInitializer:

In code, we'd use the SEL macro:

   SEL(designatedInitializer:)

When sending a message is executed, there is a dispatching to a method.
That is, at run-time, the Objective-C runtime will try to find a method
matching the selector for the recipient object (which can also be a
class, classes are objects). 
Dispatching works like this:

- find the class of the object (if it's a class, find the metaclass);

- search a method for the selector in that class.

- if there is no method for the selector in that class, then search in
  the superclass, and so on.


When we send a message to super, we start the search directly from the
superclass, instead of starting from the class.

So when a method is found, such as -[SomeClass designatedInitializer:]
then it is called.  A method is basically a C function with two
additionnal parameters (a selector _cmd, and the recipient self).

Notice that methods are denoted by:

- a sign - for instance methods (stored in the class), + for class
  methods (stored in the metaclass).
- a class name,
- a designator.

  -[SomeClass designatedInitializer:]


So you can have two methods:

  -[MyClass designatedInitializer:]
  -[MySubClass designatedInitializer:]

and when you send a designatedInitializer: message:

   [self designatedInitializer:42]

one or the other method may be called first, depending on the class of
self.  

The class of self is not necessarily the class of the method being
executed!

Usually, the class of self is a SUBCLASS of the class of the method
being executed.



The problem with Don's code is that there are four methods:

  -[MyClass init]
      [self designatedInitializer:default]

  -[MyClass designatedInitializer:]
      …

  -[MySubClass init]
      [super init]

  -[MySubClass designatedInitializer:]
      [super designatedInitializer:default]


[MySubclass alloc] returns an instance of MySubClass.
The only instance we'll have is of the class MySubClass.

Sending the message [[MySubclass alloc] init]

sends the init message to an instance of the class MySubClass.

So we call the method -[MySubClass init], passing the instance of the
class MySubClass.

which sends the message init to super, that is, to the same instance of
the class MySubClass, but searching the method -init starting from the
superclass. 

So we call the method -[MyClass init], passing the instance of the
class MySubClass.

This sends the designatedInitializer: message to this instance of the
class MySubClass.

So we search a -designatedInitializer: method starting from the class
MySubClass, and we find -[MySubClass designatedInitializer:]

This sends the message [super init], so we search an -init method from
the superclass and find -[MyClass init], passing the instance of the
class MySubClass.

This sends the designatedInitializer: message to this instance of the
class MySubClass.

So we search a -designatedInitializer: method starting from the class
MySubClass, and we find -[MySubClass designatedInitializer:]

This sends the message [super init], so we search an -init method from
the superclass and find -[MyClass init], passing the instance of the
class MySubClass.

This sends the designatedInitializer: message to this instance of the
class MySubClass.

So we search a -designatedInitializer: method starting from the class
MySubClass, and we find -[MySubClass designatedInitializer:]

This sends the message [super init], so we search an -init method from
the superclass and find -[MyClass init], passing the instance of the
class MySubClass.

This sends the designatedInitializer: message to this instance of the
class MySubClass.

So we search a -designatedInitializer: method starting from the class
MySubClass, and we find -[MySubClass designatedInitializer:]

This sends the message [super init], so we search an -init method from
the superclass and find -[MyClass init],

etc.




The whole point of OOP and inheritance, is to be able send a message to
an object without knowing at compilation time what class or subclass
this object will be.  So the actual method called when we send this
message, is determined at run-time, and may be a method of a subclass
that wasn't even imagined when we wrote this message sending.

When we have:

    @implementation MyClass
    -(id)init{
       return [self designatedInitializer:42]; 
    }
    @end

the only raison-d'être of this method, is to call the method of the
subclass of MyClass of which self is an instance.

Because we know, when we write MyClass, that we don't know what the
future has in stock for us.  We know that the customer will come with
some crazy requirements, which makes -[MyClass designatedInitializer:]
completely inadapted and outdated.

Therefore when the crazy customer comes with his crazy requirements, we
will write a subclass that will do the right thing, by implementing a
-[CrazyCustomerSubclass designatedInitializer:] method, knowing that the
rest of the MyClass code will still work, because everytime it has to
rely on some specific behavior, it will send a message to the object
that will be dispatched to the right method according to the class of
that object.

-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

[toc] | [prev] | [next] | [standalone]


#239

FromJon Rossen <jonr17@comcast.net>
Date2015-11-25 17:30 -0800
Message-ID<n35nc1$48e$1@news.albasani.net>
In reply to#236
Pascal,

I'm starting to get hopelessly confused.
The following are parts of your response that I think address where I 
was (or still am) confused


> - if there is no method for the selector in that class, then search in
>    the superclass, and so on.

Right, I'm generally already familiar with the search pattern here.


> When we send a message to super, we start the search directly from the
> superclass, instead of starting from the class.

Ok, I think this may be were my problem has been.  You are saying here 
that if you send a message to super, then the *super class* is where the 
search begins, *not* from the current class.  This seems to put a 
different spin on what you said just above, where the search starts in 
the current class.



> So when a method is found, such as -[SomeClass designatedInitializer:]
> then it is called.  A method is basically a C function with two
> additionnal parameters (a selector _cmd, and the recipient self).
>
> Notice that methods are denoted by:
>
> - a sign - for instance methods (stored in the class), + for class
>    methods (stored in the metaclass).
> - a class name,
> - a designator.
>
>    -[SomeClass designatedInitializer:]
>
>
> So you can have two methods:
>
>    -[MyClass designatedInitializer:]
>    -[MySubClass designatedInitializer:]

Ok, got it.  Just a nitpick...these are instance methods, not class 
methods so technically shouldn't this example be something like:
[myClassObject designatedInitializer]
[mySubclassObject designatedInitializer]

...or does the '-' you have as a prefix serve to state this and the 
examples (names used) are supposed to be taken abstractly?


> and when you send a designatedInitializer: message:
>
>     [self designatedInitializer:42]
>
> one or the other method may be called first, depending on the class of
> self.

The version that is called first is the version that is in self's class. 
  Please tell me that what I have said is correct, or else I'm going to 
kill myself after I destroy my computer.  :-)


> The class of self is not necessarily the class of the method being
> executed!

This statement seems at odds at the one right above that I commented on. 
  What are you saying here?  You seem to be saying that the class of 
self may not be the class of the method being executed.  But I think I 
know why you are saying this.  You seem to be implying something here 
but you are not explicitly giving a specific scenario.

Is this statement related to the fact that the search for the method 
executed first could be in *super's* class?  This is what you touched on 
a few comments above.  In other words in that scenario (if I'm 
understanding that correctly), a different method than the one in self's 
class would be executed.  Is this what you are saying here?


> Usually, the class of self is a SUBCLASS of the class of the method
> being executed.

Ok, this is the scenario that is at the heart of what I was saying just 
directly above, or at least trying to.





>
> The problem with Don's code is that there are four methods:
>
>    -[MyClass init]
>        [self designatedInitializer:default]
>
>    -[MyClass designatedInitializer:]
>        …
>
>    -[MySubClass init]
>        [super init]
>
>    -[MySubClass designatedInitializer:]
>        [super designatedInitializer:default]
>
>
> [MySubclass alloc] returns an instance of MySubClass.
> The only instance we'll have is of the class MySubClass.
>
> Sending the message [[MySubclass alloc] init]
>
> sends the init message to an instance of the class MySubClass.
>
> So we call the method -[MySubClass init], passing the instance of the
> class MySubClass.
>
> which sends the message init to super, that is, to the same instance of
> the class MySubClass, but searching the method -init starting from the
> superclass.
>
> So we call the method -[MyClass init], passing the instance of the
> class MySubClass.
>
> This sends the designatedInitializer: message to this instance of the
> class MySubClass.
>
> So we search a -designatedInitializer: method starting from the class
> MySubClass, and we find -[MySubClass designatedInitializer:]
>
> This sends the message [super init], so we search an -init method from
> the superclass and find -[MyClass init], passing the instance of the
> class MySubClass.
>
> This sends the designatedInitializer: message to this instance of the
> class MySubClass.
>
> So we search a -designatedInitializer: method starting from the class
> MySubClass, and we find -[MySubClass designatedInitializer:]
>
> This sends the message [super init], so we search an -init method from
> the superclass and find -[MyClass init], passing the instance of the
> class MySubClass.
>
> This sends the designatedInitializer: message to this instance of the
> class MySubClass.
>
> So we search a -designatedInitializer: method starting from the class
> MySubClass, and we find -[MySubClass designatedInitializer:]
>
> This sends the message [super init], so we search an -init method from
> the superclass and find -[MyClass init], passing the instance of the
> class MySubClass.
>
> This sends the designatedInitializer: message to this instance of the
> class MySubClass.
>
> So we search a -designatedInitializer: method starting from the class
> MySubClass, and we find -[MySubClass designatedInitializer:]
>
> This sends the message [super init], so we search an -init method from
> the superclass and find -[MyClass init],
>
> etc.
>
>
>
>
> The whole point of OOP and inheritance, is to be able send a message to
> an object without knowing at compilation time what class or subclass
> this object will be.  So the actual method called when we send this
> message, is determined at run-time, and may be a method of a subclass
> that wasn't even imagined when we wrote this message sending.
>
> When we have:
>
>      @implementation MyClass
>      -(id)init{
>         return [self designatedInitializer:42];
>      }
>      @end
>
> the only raison-d'être of this method, is to call the method of the
> subclass of MyClass of which self is an instance.
>
> Because we know, when we write MyClass, that we don't know what the
> future has in stock for us.  We know that the customer will come with
> some crazy requirements, which makes -[MyClass designatedInitializer:]
> completely inadapted and outdated.
>
> Therefore when the crazy customer comes with his crazy requirements, we
> will write a subclass that will do the right thing, by implementing a
> -[CrazyCustomerSubclass designatedInitializer:] method, knowing that the
> rest of the MyClass code will still work, because everytime it has to
> rely on some specific behavior, it will send a message to the object
> that will be dispatched to the right method according to the class of
> that object.
>

[toc] | [prev] | [next] | [standalone]


#240

From"Pascal J. Bourguignon" <pjb@informatimago.com>
Date2015-11-26 03:03 +0100
Message-ID<87r3jdtt2p.fsf@kuiper.lan.informatimago.com>
In reply to#239
Jon Rossen <jonr17@comcast.net> writes:

>> So you can have two methods:
>>
>>    -[MyClass designatedInitializer:]
>>    -[MySubClass designatedInitializer:]
>
> Ok, got it.  Just a nitpick...these are instance methods, not class
> methods so technically shouldn't this example be something like:
> [myClassObject designatedInitializer]
> [mySubclassObject designatedInitializer]


No. The point is that both methods can be called for the same object!

    -[MyClass designatedInitializer:]
    -[MySubClass designatedInitializer:]

For example:

    @implementation MySubClass
    -(id)init {
        // you can write:
        self=[self  designatedInitializer:42];
        // or you can write:
        self=[super designatedInitializer:42];
        return self;
    }
    @end

If you send the message to self, then it's the method:

    -[MySubClass designatedInitializer:]

that is called, and if you send the message to super, then
it's the method:

    -[MyClass designatedInitializer:]

that is called.


> ...or does the '-' you have as a prefix serve to state this and the
> examples (names used) are supposed to be taken abstractly?

Yes, the notation -[MyClass designatedInitializer:]
or:               +[NSObject alloc]
is not source code.  They are the name of actual methods.



>> and when you send a designatedInitializer: message:
>>
>>     [self designatedInitializer:42]
>>
>> one or the other method may be called first, depending on the class of
>> self.
>
> The version that is called first is the version that is in self's
> class. Please tell me that what I have said is correct, or else I'm
> going to kill myself after I destroy my computer.  :-)

If the class of self has such an instance method, yes.

If self is an instance of a sub sub class that doesn't define a method
for the selector -designatedInitializer: then it will be the method in
the next superclass, ie. MySubClass.


>> The class of self is not necessarily the class of the method being
>> executed!
>
> This statement seems at odds at the one right above that I commented
> on. What are you saying here?  You seem to be saying that the class of
> self may not be the class of the method being executed.  

Yes, this is what I'm saying.

> But I think I
> know why you are saying this.  You seem to be implying something here
> but you are not explicitly giving a specific scenario.

Indeed.  You need to imagine new examples.

Again, I assume that you wrote code, and that you inserted printing of
the class of the instance in the various methods.

Add lines such as:

    @implementation MyClass
    -… {
        …
        NSLog(@"in method %@ of class %@, class of self = %@",  
              NSStringFromSelector(_cmd),
              @"MyClass",
              [self className]);
       …
    }
    @end


    @implementation MySubClass
    -… {
        …
        NSLog(@"in method %@ of class %@, class of self = %@",  
              NSStringFromSelector(_cmd),
              @"MySubClass", // *** <- in subclass
              [self className]);
       …
    }
    @end

in each method and send a message and see


> Is this statement related to the fact that the search for the method
> executed first could be in *super's* class?  

Nope. The recipient is self, so the search starts in self's class.


> This is what you touched on a few comments above.  In other words in
> that scenario (if I'm understanding that correctly), a different
> method than the one in self's class would be executed.  Is this what
> you are saying here?

No. I'm saying that self could be an instance of a different class than
the class of the method where self is used.  That is, it could be an
instance of a subclass, or even possibly of an entirely different class.


This is why in the initializer you assign self.  The superclass
initializer may actually unallocate self, and allocate a new instance of
a completely different class (as long as that instances of this
different class can receive the same set of messages).

When you have class clusters, you will have normally a subclass so it
won't be "strange".  But there are other tricks, such as having proxy
objects.  Then the class of the object is not even a subclass, but an
entirely different class.  But you can ignore this for the moment, since
the proxy object will respond to the same messages as a normal object.

-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

[toc] | [prev] | [next] | [standalone]


#237

FromDon Bruder <dakidd@sonic.net>
Date2015-11-25 09:08 -0800
Message-ID<n34ppq$km8$1@dont-email.me>
In reply to#233
In article <87d1uyvj8a.fsf@kuiper.lan.informatimago.com>,
 "Pascal J. Bourguignon" <pjb@informatimago.com> wrote:

> Don Bruder <dakidd@sonic.net> writes:
> 
> > In article <87oaeivr7a.fsf@kuiper.lan.informatimago.com>,
> >  "Pascal J. Bourguignon" <pjb@informatimago.com> wrote:
> >
> >
> >> I don't agree with Don's code.  
> >> 
> >> In general the subclass should call:
> >>    [super designatedInitializer:argument]
> >> and not [super init], in its -designatedInitializer: method.
> >> 
> >> Notably, when the argument is given as a parameter to the subclass
> >> -designatedInitializer:!
> >
> > OK, now *I'M* confused... Lemme go look at the code...
> > Now that I've gone and looked, I'm gonna update that to "I'm COMPLETELY 
> > lost!" Please snatch in a copy of the code you're talking about and 
> > annotate it to tell me specifically what it is you consider wrong with 
> > it. I can't see anything (which is not to say it's impossible for me to 
> > be wrong - only that if I am, I'm not seeing how or where based on what 
> > you said), and I can't parse what you're saying up there in any way that 
> > seems to make sense.
> >
> > Never mind snatching it in... I've got it here, and I still can't see 
> > what might be wrong.
> >
> > ???
> >
> >> ---cut---
> >> #import <Cocoa/Cocoa.h>
> >> 
> >> @interface MyClass : NSObject 
> >> {
> >>    // MyClass specific vars
> >>    NSDictionary *myClassVars;
> >> }
> >> // And some method declarations
> >> -(MyClass *)designatedInitializer:(id)anyNeededParams;
> >> -(MyClass *)init;
> >> // More stuff will likely live here in a useful program.
> >> @end
> >> ---cut---
> >> 
> >> And in your .m file:
> >> ---cut---
> >> #import "MyClass.h"
> >> @implementation MyClass
> >> 
> >> -(MyClass *)designatedInitializer:(id)anyNeededParams
> >> {
> >>    self = [super init]; // Invoke NSObject's init
> >>    
> >>    // Do MyClass-specific init
> >> 
> >>    // and return what self has become.
> >>    return self;
> >> }
> >> 
> >> -(MyClass *)init
> >> {
> >>    // I'll assume defaultParams is set appropriately elsewhere
> >>    return [self designatedInitializer:defaultParams];
> >> }
> >> 
> >> // Any other methods MyClass needs follow
> >> @end
> >> ---cut---
> >
> >> ---cut---
> >> #import "MyClass.h"
> >> @interface MySublass : MyClass
> >> {
> >>    // MySublass specific vars
> >>    NSDictionary *SubclassVar;
> >> }
> >> // And don't forget the method declarations
> >> -(MyClass *)designatedInitializer:(id)anyNeededParams;
> >> -(MyClass *)init;
> >> 
> >> @end
> >> ---cut---
> >> 
> >> And the .m file
> >> ---cut---
> >> #import "MySubclass.h"
> >> -(MySubclass *)designatedInitializer:(id)anyNeededParams
> >> {
> >>    self = [super init]; // Invokes MyClass' init
> 
> This.  The designated initializer of the super class (ie. the MyClass
> class), is designatedInitializer: ; therefore this is the designated
> initializer you must call from the subclass.
> Since you call [super init], -[MyClass init] will send the
> -designatedInitializer:  message to self, which will call 
> -[MySubclass designatedInitializer:] and this will give an infinite
> loop.

You'll pardon my skepticism, I hope - I'm an empiricist at heart...

Gonna do some playing and see what I can come up with, but at this 
stage, what you're saying is so *TOTALLY* counterintuitive I can't even 
start to accept it. Everything I've ever grasped about 
inheritance/subclassing tells me that I'm not supposed to "need" to know 
the internals of the class I'm deriving from - it's a black box. So long 
as you do thus and so, your subclass will work. "Thus and so" in this 
case meaning "Make damn sure you chain back to the root object by 
calling your superclass' init method or all hell's gonna break loose". 

I'll get back to this after I've done some tinkering...

-- 
Security provided by Mssrs Smith and/or Wesson. Brought to you by the letter Q

[toc] | [prev] | [next] | [standalone]


#238

From"Pascal J. Bourguignon" <pjb@informatimago.com>
Date2015-11-25 18:41 +0100
Message-ID<874mgaugc9.fsf@kuiper.lan.informatimago.com>
In reply to#237
Don Bruder <dakidd@sonic.net> writes:

> You'll pardon my skepticism, I hope - I'm an empiricist at heart...

I assumed so much, and therefore I assumed you already ran the code, and
saw the infinite loop for yourself!


> Gonna do some playing and see what I can come up with, but at this 
> stage, what you're saying is so *TOTALLY* counterintuitive I can't even 
> start to accept it. Everything I've ever grasped about 
> inheritance/subclassing tells me that I'm not supposed to "need" to know 
> the internals of the class I'm deriving from - it's a black box. So long 
> as you do thus and so, your subclass will work. "Thus and so" in this 
> case meaning "Make damn sure you chain back to the root object by 
> calling your superclass' init method or all hell's gonna break loose". 

Well, either your class is "documented", with a class invariant
and a set of pre- and post- conditions for each method, or you have to
know the internals.

Since you never find those invariants and sets of pre- and
post-conditions documented, you never know, and always have to know the
internals, which indeed, is a very bad situation.


-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

[toc] | [prev] | [next] | [standalone]


#245

FromDon Bruder <dakidd@sonic.net>
Date2015-12-02 14:37 -0800
Message-ID<n3nrna$f6$1@dont-email.me>
In reply to#238
In article <874mgaugc9.fsf@kuiper.lan.informatimago.com>,
 "Pascal J. Bourguignon" <pjb@informatimago.com> wrote:

> Don Bruder <dakidd@sonic.net> writes:
> 
> > You'll pardon my skepticism, I hope - I'm an empiricist at heart...
> 
> I assumed so much, and therefore I assumed you already ran the code, and
> saw the infinite loop for yourself!

Been gone longer than planned, but back to the home machine now...

Nope, at that point, hadn't tried running it. Have now. And am 
gobsmacked! Also educated - This explains a situation I had a few years 
back when I tried to subclass from one of the "NSXxxx" classes that come 
with cocoa - I got *EXACTLY* the same behavior back then as what I saw 
when I tried running the code we've been talking about, and never did 
bother to chase down the how/why. Ended up just tacking a category on 
the class rather than doing an actual subclass, and things worked just 
fine.

> 
> 
> > Gonna do some playing and see what I can come up with, but at this 
> > stage, what you're saying is so *TOTALLY* counterintuitive I can't even 
> > start to accept it. Everything I've ever grasped about 
> > inheritance/subclassing tells me that I'm not supposed to "need" to know 
> > the internals of the class I'm deriving from - it's a black box. So long 
> > as you do thus and so, your subclass will work. "Thus and so" in this 
> > case meaning "Make damn sure you chain back to the root object by 
> > calling your superclass' init method or all hell's gonna break loose". 
> 
> Well, either your class is "documented", with a class invariant
> and a set of pre- and post- conditions for each method, or you have to
> know the internals.
> 
> Since you never find those invariants and sets of pre- and
> post-conditions documented, you never know, and always have to know the
> internals, which indeed, is a very bad situation.

Yeah... it does a serious number on the whole "A class stands alone, you 
can treat it as a black box" concept that was (until now...) my 
understanding of one of the main points of OOP. 

So now, I'm gonna have to get my head around how to cope with this 
"breakage"...

-- 
Security provided by Mssrs Smith and/or Wesson. Brought to you by the letter Q

[toc] | [prev] | [next] | [standalone]


#246

From"Pascal J. Bourguignon" <pjb@informatimago.com>
Date2015-12-03 00:58 +0100
Message-ID<87610gqu6i.fsf@kuiper.lan.informatimago.com>
In reply to#245
Don Bruder <dakidd@sonic.net> writes:

>> Well, either your class is "documented", with a class invariant
>> and a set of pre- and post- conditions for each method, or you have to
>> know the internals.
>> 
>> Since you never find those invariants and sets of pre- and
>> post-conditions documented, you never know, and always have to know the
>> internals, which indeed, is a very bad situation.
>
> Yeah... it does a serious number on the whole "A class stands alone, you 
> can treat it as a black box" concept that was (until now...) my 
> understanding of one of the main points of OOP. 


Well, the system of class invariant and pre-/post-conditions is what
defines the black box.  What it says, is that if you ensure that the
pre-conditions are met, then when you send a message, the post-condition
will be ensure by the black box.  Usually, the post-condition is a
useful value or side effect, and the specification of the pre- and
post-condition establish contract that clearly indicates the
responsibilities of the black box and the user of the black box.


> So now, I'm gonna have to get my head around how to cope with this 
> "breakage"...

Of course, if you have constraining pre-conditions, as long as they are
well documented, the function caller or message sender will be able to
ensure that the pre-condition is met, and everything will work nicely.

Alternatively, if your pre-conditions are true, then the caller or
sender will be able to interact with your objects in any way it wants,
and everything should work nicely.

The problem is when there are pre-conditions that are not documented.
In that case, indeed the black box notion breaks, because you cannot use
it anymore without looking what's inside the box, how the class is
implemented, and then making assumption about what you can do with it or
not.  The assumptions are valid while you use the exact same white box,
but if you replace it with another implementation (or a black-box
subclass), then your assumptions might reveal inadequate and your
software will break.


Notice that documentations of frameworks (sets of classes) are usually
not that formal; they don't explicitely write down the
pre-/post-conditions for each methods; some general indications are
given in English, and you may infer some pre-/post-conditions and class
invariant, but you may also err, and this is what makes it rather
difficult to use those frameworks.

So you should not necessarily follow those examples…

https://en.wikipedia.org/wiki/Design_by_contract

-- 
__Pascal Bourguignon__                 http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

[toc] | [prev] | [next] | [standalone]


#231

FromDon Bruder <dakidd@sonic.net>
Date2015-11-24 18:29 -0800
Message-ID<n336ad$6mt$1@dont-email.me>
In reply to#227
In article <n32tc0$hik$1@news.albasani.net>,
 Jon Rossen <jonr17@comcast.net> wrote:

> < A bunch of previous stuff cut out...new comments inline below>
> thx -jonR
> 
> >> Don, Thanks so much for your response with all of this info; I really
> >> appreciate it.  It is the perfect combination of theory and practical
> >> info.  You are right, I sort of understand the chaining mechanism in how
> >> things unfold in the class hierarchy.  The construct that you
> >> illustrated here with the default values used by the 'convenience' init
> >> methods is something I came across earlier today coincidentally, but
> >> your explanation was much more specific, to the point and not obfuscated
> >> by vague implications.  I have a few more questions:
> >>
> >> 1. Just a workflow question:  Re: the 'convenience' init methods that
> >> may be helpful to get objects accompany the designated one:  Is it
> >> typical for a developer when building a class to add the 'convenience'
> >> init methods later on or sort of on an 'as needed' basis depending?  I'm
> >> not asking this as to what's good or bad, but am assuming it just
> >> depends on the situation and in your experience how does this usually
> >> play out?
> >
> > I can't speak for anyone but myself, so YMMV...
> > Personally, I code a "designated" initializer that takes appropriate
> > inputs and uses them to handle *EVERYTHING*, to start with, then a
> > "naked init" ("-(MyClass *)init") method that passes some reasonable
> > defaults into the designated initializer. Often, but nowhere near
> > always, that's all that's needed. (Or more accurately, it's *ALWAYS* all
> > that's *NEEDED*, but it's only occasionally all that's *WANTED*, if you
> > understand the distinction) If, as the project progresses, and I notice
> > a need for them, I might add more convenience initializers. The decision
> > to add more convenience initializers or not is totally dependent on the
> > needs of the specific project - In one project, I might code the
> > designated initializer, the cover for "init", and several variations, as
> > needed. In another, I might not code anything except the designated
> > initializer, and a cover for "plain" init so that any subclasses I (or
> > someone else...) might cook up later will chain back up the line
> > properly when hit with a "[super init]". Either way, if somebody
> > subclasses from your class, they come in with the expectation that doing
> > "[super init]" will do the right thing (by calling the root object's
> > init method - perhaps directly, or perhaps through a very long and
> > complex chain of calls, but it'll happen eventually)
> 
> Ok....but backing up to the beginning of your paragraph:
> Hmmm, you lost me when you brought up your 'naked init' and said that it 
> 'passes some reasonable defaults into the designated initializer'.  The 
> naked init in the current class just calls the current class' designated 
> initializer and returns it.  How does it pass some reasonable defaults 
> *into it*??  Might you be referring to the naked init that is the 
> *superclass* of the current class?  Certainly the super's init does that 
> when you do self = [super init].  I just don't understand how the init 
> at the current level feeds anything into the designated initializer at 
> that same level.

(I'm going to proceed assuming we're both talking about the code snips 
that are down below, not anything that might have been mentioned in the 
pruned material) 

When the naked init makes the call to the DI, it passes an NSDictionary 
of default values (which I assume gets set up elsewhere)

> 
> 
> >> 2. Ok, hopefully this question won't open up a can of worms.  What about
> >> sub-classes?  I guess this is a two part question:
> >>    a) If there's a sub-class that doesn't particularly need it's own
> >> class designated initializer, it could just use it's super's designated
> >> initializer, correct?  If so, is this a common design pattern?
> >
> > At least in theory, yes, that's correct. As for how common it is...
> > <shrug> No clue - I've never actually taken the time to think about it.
> >
> > (minor nitpick: "it's" is a contraction meaning "it is" - You're looking
> > for the possessive form: "its" - "that which belongs to it". Ain't it
> > wonderful how consistent the english language is? :) )
> 
> Yeah, yeah, I know all of that; it was purely a typo due to being tired. 
>   When I get tired I have a tendency to spell fenetically :-) and little 
> details drop off by the wayside.  But great nitpick...I'd give it a 9 
> out of 10 at least.  :-)

The finest (and possibly most maddening!) example of apostrophe abuse 
I've ever encountered was a roadside stand with a sign I used to have to 
drive by at least twice daily - Half a sheet of plywood painted sky blue 
then in wonderful, almost calligraphy-like script, hand painted in 
screaming brilliant red, so it gave the illusion of "vibrating":
 FRESH
 EGG'S
4-SALE!


AUGH!!!!!! <facepalm - really really hard!>
  
> 
> Speaking of nitpicks, in your code examples why don't you use 
> (instancetype) as your return type?

Uh... 'Cuz I'm not returning an instance type, I'm returning an instance 
of a class?

> 
> >
> >> b) If the sub-class *does* need a designated initializer, I suppose it
> >> could do an override of the super's version and that would be ok.
> >> However, I would think that any additional initialization would have to
> >> be done via assessor methods as the method names would have to be the
> >> same.
> >
> > Sounds right... I THINK - Assuming you're asking what I think you are.
> 
> OK.
> 
> > If you're expecting to be subclassing off your subclass, then write your
> > "first level" subclass - let's call it MyClass - like so:
> > (I'm assuming you're on a Mac, so you'll probably be subclassing it from
> > NSObject)
> 
> 
> >
> > Your .h file has (at least - perhaps MUCH more) in it:
> > ---cut---
> > #import <Cocoa/Cocoa.h>
> >
> > @interface MyClass : NSObject
> > {
> >     // MyClass specific vars
> >     NSDictionary *myClassVars;
> > }
> > // And some method declarations
> > -(MyClass *)designatedInitializer:(id)anyNeededParams;
> > -(MyClass *)init;
> > // More stuff will likely live here in a useful program.
> > @end
> > ---cut---
> >
> > And in your .m file:
> > ---cut---
> > #import "MyClass.h"
> > @implementation MyClass
> >
> > -(MyClass *)designatedInitializer:(id)anyNeededParams
> > {
> >     self = [super init]; // Invoke NSObject's init
> >
> >     // Do MyClass-specific init
> >
> >     // and return what self has become.
> >     return self;
> > }
> >
> > -(MyClass *)init
> > {
> >     // I'll assume defaultParams is set appropriately elsewhere
> >     return [self designatedInitializer:defaultParams];
> > }
> >
> > // Any other methods MyClass needs follow
> > @end
> > ---cut---
> >
> > Notice that all init does is call the instance's designated initializer
> > with default params. Which in turn calls [super init] (NSObject's, in
> > this case)  before using the parameters it gets passed. You get the rest
> > of your MyClass going, ship the project, and make a few bucks.
> 
> Right.  This code example is pretty much the same example you showed me 
> the other day, and BTW, is consistent with my understanding of how to do 
> this.  So, there's nothing new here with respect to the other day's 
> example, right?

Other than being "more refined", no, not really - hang with me till 
after the next blob... 

> 
> >
> > Time passes, and a project you just got handed wants something very
> > nearly identical to MyClass, but with a couple little additions and
> > tweaks. You decide to subclass from MyClass to make a new class of
> > object -  The MySubclass
> >
> > You toss together a quick .h file:
> > ---cut---
> > #import "MyClass.h"
> > @interface MySublass : MyClass
> > {
> >     // MySublass specific vars
> >     NSDictionary *SubclassVar;
> > }
> > // And don't forget the method declarations
> > -(MyClass *)designatedInitializer:(id)anyNeededParams;
> > -(MyClass *)init;
> >
> > @end
> > ---cut---
> >
> > And the .m file
> > ---cut---
> > #import "MySubclass.h"
> > -(MySubclass *)designatedInitializer:(id)anyNeededParams
> > {
> >     self = [super init]; // Invokes MyClass' init
> >
> >     // Do MySubclass-specific init work
> >
> >     // and return what self has become.
> >     return self;
> > }
> >
> > -(MySubclass *)init
> > {
> >     // I'll assume defaultMySubclassParams is set appropriately somewhere
> >     return [self designatedInitializer:defaultMySubclassParams];
> > }
> >
> > // Any other methods MySubclass needs follow
> >
> > @end
> > ---cut---
> >
> > You'll notice how close to identical the code is for both cases - The
> > critical consideration is that you ALWAYS want your class' "init" to
> > chain back to the root object, whether directly or indirectly.
> 
> Not only are they close, aren't they basically *the exact same code* 
> structurally?  Meaning apart from the class-specific stuff that would be 
> needed (different name of designated initializer, additional parameters, 
> etc., etc.), the framework here is exactly the same as it was for the 
> subclass (MyClass).  I would *expect* it to be the same seeing that it's 
> keeping the init chaining intact.  Am I missing something or am I 
> 'getting it'?

You're getting it. Sorry if I seemed like I was beating you over the 
head with it - I caught a case of "If I actually THINK about how to tie 
my shoelaces instead of just letting my fingers take care of tying them 
for me "automagically", I'll do nothing but tie 'em in knots" syndrome, 
and the reply is partly me "untying" the knots I got myself into! When I 
got done, I decided it was worth going ahead and posting anyway in case 
somebody else might stumble on it and find it useful, tweaked a couple 
of typos, and hit send.
> 
> >
> >> c) At each step down the hierarchy through sub-classes, the 'plain' init
> >> would have to be overridden and it would have to return the current
> >> class' designated initializer, correct?  In other words, you'd have to
> >> re-write init for each sub-class where there is a new designated
> >> initializer.

Quickie comment here as I see some confusion in your reply to Pascal - 
When the plain init method is called, the caller doesn't get the current 
class' designated initializer - it gets THE RESULT OF CALLING the 
current class' designated initializer - an initialized and ready-to-use 
instance of a subclass that inherits from the current class.

> >
> > Basically, yes. See the snippets above.
> 
> Yep, my above two comments discusses this.
> 
> thanks for your response.
> -jonR

-- 
Security provided by Mssrs Smith and/or Wesson. Brought to you by the letter Q

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.objective-c


csiph-web