• A question on designated initializers

    From Jon Rossen@21:1/5 to All on Sun Nov 22 13:39:23 2015
    I have a rather beginner's basic type of question on designated
    initializers. The book that I'm using uses an extremely simple (and
    trivial) example (which is usually the case) which leaves me with about
    as many questions as answers.

    Here's the simple example from the book using a Rectangle class which is
    a child class of NSObject.

    Here's some of the pertinent info from Rectangle.h; I won't bother
    including stuff that's not directly related to the example:

    Rectangle.h

    @property int width, height;

    -(void) setWidth: (int) w andHeight: (int) h;
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    -(instancetype) init;


    Ok, here are just the new, custom init methods from Rectangle.m

    Rectangle.m

    //Designated initializer
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    {
    self = [super init];
    if (self)
    [self setWidth:w andHeight:h];

    return self;
    }

    //The override of super's designated initializer
    -(instancetype) init
    {
    return [self initWithWidth:0 andHeight:0];
    }


    Ok, I get what's going on here: You create a new designated initializer
    which handles a lot of the ivars that you feel are important. You have
    to include a call super's designated intializer and assign it to self,
    then the 'if' test, then your initialization code. You then override
    super's designated initializer (in this case it's NSObject's init) and
    return a call to your designated initializer. I get how the hierarchy
    is supposed to work.

    But how is this helpful? In my mind it's not helpful for a few
    different reasons. Reason 1: In the override to init you've hardwired
    the width and height to be 0. That's what NSObject's init would do, so
    it's not doing anything new or better. Reason 2: Even if you put
    different values in there say, 1 and 2 or whatever values you thought
    you might need a newly created Rectangle object to have, they are still hardwired values, buried inside the newly created init method. How is
    this helpful at all? You may want to have a bunch of rectangles of all different dimensions. At that point you'd have to change their
    dimensions with the proper accessor method. If so, why even both with
    this newly created init when you can just use NSObject's init and use
    the accessor method to tweak the height and width you want each
    Rectangle object to be?

    Am I correct that the trivial nature of this example sort of gets in the
    way of truly understanding the benefit or need of all of this?
    thanks,
    jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Jon Rossen on Sun Nov 22 14:48:44 2015
    On 11/22/2015 1:39 PM, Jon Rossen wrote:
    I have a rather beginner's basic type of question on designated
    initializers. The book that I'm using uses an extremely simple (and
    trivial) example (which is usually the case) which leaves me with about
    as many questions as answers.

    Here's the simple example from the book using a Rectangle class which is
    a child class of NSObject.

    Here's some of the pertinent info from Rectangle.h; I won't bother
    including stuff that's not directly related to the example:

    Rectangle.h

    @property int width, height;

    -(void) setWidth: (int) w andHeight: (int) h;
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    -(instancetype) init;


    Ok, here are just the new, custom init methods from Rectangle.m

    Rectangle.m

    //Designated initializer
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    {
    self = [super init];
    if (self)
    [self setWidth:w andHeight:h];

    return self;
    }

    //The override of super's designated initializer
    -(instancetype) init
    {
    return [self initWithWidth:0 andHeight:0];
    }


    Ok, I get what's going on here: You create a new designated initializer which handles a lot of the ivars that you feel are important. You have
    to include a call super's designated intializer and assign it to self,
    then the 'if' test, then your initialization code. You then override
    super's designated initializer (in this case it's NSObject's init) and
    return a call to your designated initializer. I get how the hierarchy
    is supposed to work.

    But how is this helpful? In my mind it's not helpful for a few
    different reasons. Reason 1: In the override to init you've hardwired
    the width and height to be 0. That's what NSObject's init would do, so
    it's not doing anything new or better. Reason 2: Even if you put
    different values in there say, 1 and 2 or whatever values you thought
    you might need a newly created Rectangle object to have, they are still hardwired values, buried inside the newly created init method. How is
    this helpful at all? You may want to have a bunch of rectangles of all different dimensions. At that point you'd have to change their
    dimensions with the proper accessor method. If so, why even both with
    this newly created init when you can just use NSObject's init and use
    the accessor method to tweak the height and width you want each
    Rectangle object to be?

    Am I correct that the trivial nature of this example sort of gets in the
    way of truly understanding the benefit or need of all of this?
    thanks,
    jonR


    DOH!!! It's amazing how asking a question sometimes helps you
    understand an issue even before you get a response from someone. After
    posting the question, I looked at the code again and came to a
    conclusion that will either refine the question or answer it. From what
    I can see, my question about the use value of the newly written init for
    the Fraction class is off-base because it really doesn't offer anything
    for the Fraction class, and is not *meant* to offer anything directly.
    It's use value is for any subclasses that Fraction may have. For
    example, if Fraction's subclass needs to create it's own designated initializer, it will contain a call to super's init (self = [super
    init], and for Fraction's subclass, init will be the Fraction class
    version of init, which returns a call to Fraction's designated
    initializer. So, in this sense, the override of init aids in the 'chain reaction' so to speak of how all these things work together in getting
    all the ivars initialized properly. Am i on the right track here?
    thx, jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Mon Nov 23 01:18:57 2015
    Jon Rossen <jonr17@comcast.net> writes:

    Am I correct that the trivial nature of this example sort of gets in
    the way of truly understanding the benefit or need of all of this?

    An initializer method may do a little more than just setting ivars.

    Basically, what it has to do, is to establish the class invariant for
    the instance. This class invariant is not necessarily set by
    -[NSObject init].


    Now, when you specify for a class a new designated initializer, this
    creates a new initializer for all its subclasses. That is, a client of
    the class or any of the subclasses, may and you can assume, will use any
    of those initializers.

    Therefore, if you have a new designated initializer, it might set up the
    class invariant, while the other initializers in the super class might
    not (probably won't). This is the reason why you need to define
    overridden initializers for the non-designated initializer too.



    For example, you might have a serialization/deserialization library
    (eg. -[NSBundle loadNibNamed:]); there's no mechanism designed to
    specify the designated initializer (and it's arguments and valid values)
    to recreate the deserialized objects. Instead, the library will just
    do: [[class alloc] init] calling the default initializer, and then it
    will set the saved ivars directly.


    Now, indeed, in this small example, we can assume that -[NSObject init]
    ensures the Rectangle class invariant (which we may assume to be (0<=width)&&(0<=height)), and calling -[Rectangle init] does nothing
    more than -[NSObject init], and therefore as you write, this example
    sort of gets in the way of truly understanding the benefit or need of
    all of this?

    Let's say that a Rectangle shall not be a line or a point:

    -(bool)invariant{
    return((0<width)&&(0<height));
    }

    Then:

    //Designated initializer
    -(id)initWithWidth: (int) w andHeight: (int) h;
    {
    self = [super init];
    if(self){ // always use braces!
    // https://nakedsecurity.sophos.com/2014/02/24/anatomy-of-a-goto-fail-apples-ssl-bug-explained-plus-an-unofficial-patch/
    [braces setWidth:max(1,w) andHeight:max(1,h)];
    }
    assert([self invariant]);
    return self;
    }


    //The override of super's designated initializer
    -(id)init{
    // smallest rectangle.
    return [self initWithWidth:1 andHeight:1];
    }


    Then it will be obvious that -[NSObject init] doesn't
    ensure [self invariant], and that -[Rectangle init] is needed.


    --
    __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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Louis Wu@21:1/5 to Jon Rossen on Sun Nov 22 16:26:46 2015
    In article <n2tgoe$59u$1@news.albasani.net>,
    Jon Rossen <jonr17@comcast.net> wrote:

    [snipt]

    Ok, here are just the new, custom init methods from Rectangle.m

    Rectangle.m

    //Designated initializer
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    {
    self = [super init];
    if (self)
    [self setWidth:w andHeight:h];

    return self;
    }

    //The override of super's designated initializer
    -(instancetype) init
    {
    return [self initWithWidth:0 andHeight:0];
    }


    Ok, I get what's going on here: You create a new designated initializer which handles a lot of the ivars that you feel are important. You have
    to include a call super's designated intializer and assign it to self,
    then the 'if' test, then your initialization code. You then override super's designated initializer (in this case it's NSObject's init) and return a call to your designated initializer. I get how the hierarchy
    is supposed to work.


    You SHOULD use the designated initializer for creating objects of the
    class because it was set up to ensure that the object is initialized in
    a safe and consistent manner.

    However, since your new class may be initialized by some other means,
    the basic form of the init should be overridden to make sure that the designated initializer is used to create the object.

    Suppose, for instance that you need to create Rectangle instances by
    using only the class name using ...

    NSObject *myRect = [[NSClassFromString(@"Rectangle") alloc] init];

    Ensuring that the init method (which you overrode) calls the designated initializer will make sure that this behaviour "just works".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Mon Nov 23 02:02:20 2015
    Jon Rossen <jonr17@comcast.net> writes:

    Thanks for the explanations and to be honest I don't fully understand
    all of what you have said, but I understand it enough for it to make
    sense. However, I realize I need to understand class invariants which
    is a new concept to me. I think that is the primary component or
    background for me that is lacking and when I get a better
    understanding I'll fully understand your explanation.

    Have a look at:

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


    --
    __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 Autodesk CEO

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Pascal J. Bourguignon on Sun Nov 22 16:49:03 2015
    On 11/22/2015 4:18 PM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:

    Am I correct that the trivial nature of this example sort of gets in
    the way of truly understanding the benefit or need of all of this?

    An initializer method may do a little more than just setting ivars.

    Basically, what it has to do, is to establish the class invariant for
    the instance. This class invariant is not necessarily set by
    -[NSObject init].


    Now, when you specify for a class a new designated initializer, this
    creates a new initializer for all its subclasses. That is, a client of
    the class or any of the subclasses, may and you can assume, will use any
    of those initializers.

    Therefore, if you have a new designated initializer, it might set up the class invariant, while the other initializers in the super class might
    not (probably won't). This is the reason why you need to define
    overridden initializers for the non-designated initializer too.



    For example, you might have a serialization/deserialization library
    (eg. -[NSBundle loadNibNamed:]); there's no mechanism designed to
    specify the designated initializer (and it's arguments and valid values)
    to recreate the deserialized objects. Instead, the library will just
    do: [[class alloc] init] calling the default initializer, and then it
    will set the saved ivars directly.


    Now, indeed, in this small example, we can assume that -[NSObject init] ensures the Rectangle class invariant (which we may assume to be (0<=width)&&(0<=height)), and calling -[Rectangle init] does nothing
    more than -[NSObject init], and therefore as you write, this example
    sort of gets in the way of truly understanding the benefit or need of
    all of this?

    Let's say that a Rectangle shall not be a line or a point:

    -(bool)invariant{
    return((0<width)&&(0<height));
    }

    Then:

    //Designated initializer
    -(id)initWithWidth: (int) w andHeight: (int) h;
    {
    self = [super init];
    if(self){ // always use braces!
    // https://nakedsecurity.sophos.com/2014/02/24/anatomy-of-a-goto-fail-apples-ssl-bug-explained-plus-an-unofficial-patch/
    [braces setWidth:max(1,w) andHeight:max(1,h)];
    }
    assert([self invariant]);
    return self;
    }


    //The override of super's designated initializer
    -(id)init{
    // smallest rectangle.
    return [self initWithWidth:1 andHeight:1];
    }


    Then it will be obvious that -[NSObject init] doesn't
    ensure [self invariant], and that -[Rectangle init] is needed.



    Pascal,

    Thanks for the explanations and to be honest I don't fully understand
    all of what you have said, but I understand it enough for it to make
    sense. However, I realize I need to understand class invariants which
    is a new concept to me. I think that is the primary component or
    background for me that is lacking and when I get a better understanding
    I'll fully understand your explanation.
    Cheers,
    jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to All on Sun Nov 22 17:24:51 2015
    You SHOULD use the designated initializer for creating objects of the
    class because it was set up to ensure that the object is initialized in
    a safe and consistent manner.

    However, since your new class may be initialized by some other means,
    the basic form of the init should be overridden to make sure that the designated initializer is used to create the object.



    Suppose, for instance that you need to create Rectangle instances by
    using only the class name using ...

    NSObject *myRect = [[NSClassFromString(@"Rectangle") alloc] init];

    Ensuring that the init method (which you overrode) calls the designated initializer will make sure that this behaviour "just works".

    Thanks for the response!

    I do not understand this example using NSClassFromString that you have provided. In my original post, when I said this was a beginner's
    question, I sort of meant it. :-) When using your example:
    NSObject *myRect = [[NSClassFromString(@"Rectangle") alloc] init]; an
    instance of the Rectangle class is not created. Was there a typo? Did
    you mean to state: Rectangle *myRect....??

    Also, why is the importance of having overridden init specifically
    illustrated by this example using NSClassFromString? Again, I'm
    assuming that my lack of understanding of the simple example you have
    chosen is the reason why I am not understanding your point.

    -jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Mon Nov 23 02:39:00 2015
    Jon Rossen <jonr17@comcast.net> writes:

    You SHOULD use the designated initializer for creating objects of the
    class because it was set up to ensure that the object is initialized in
    a safe and consistent manner.

    However, since your new class may be initialized by some other means,
    the basic form of the init should be overridden to make sure that the
    designated initializer is used to create the object.



    Suppose, for instance that you need to create Rectangle instances by
    using only the class name using ...

    NSObject *myRect = [[NSClassFromString(@"Rectangle") alloc] init];

    Ensuring that the init method (which you overrode) calls the designated
    initializer will make sure that this behaviour "just works".

    Thanks for the response!

    I do not understand this example using NSClassFromString that you have provided. In my original post, when I said this was a beginner's
    question, I sort of meant it. :-) When using your example:
    NSObject *myRect = [[NSClassFromString(@"Rectangle") alloc] init]; an instance of the Rectangle class is not created.

    Yes it is.

    [NSClassFromString(@"Rectangle") alloc]

    is the same as:

    [Rectangle alloc]

    But we could have:

    NSString* className=[file readLine];
    NSObject* object=[[NSClassFromString(className) alloc] init];

    and obtain an object of a class unknown at compilation time.


    Was there a typo? Did
    you mean to state: Rectangle *myRect....??

    Rectangle being a subclass of NSObject, it's basically the same.

    Objective-C is a dynamically typed programming language: there's a
    run-time type associated with the value of the object, independent on
    the C type associated to the variable.

    For objects, you could as well always use the id type for all objects.

    The only advantage of using a specific (super)class to define the type
    of variables holding objects, is that it allows the compiler to issue
    warning about the messages sent to the objects bound to that variable.



    Also, why is the importance of having overridden init specifically illustrated by this example using NSClassFromString?

    Again, the example is insufficient, since a literal class name was
    given. But the example shows that this class name can be determined at run-time (it is little probable that the compiler would optimize out the
    call to NSClassFromString).


    Again, I'm assuming that my lack of understanding of the simple
    example you have chosen is the reason why I am not understanding your
    point.

    Definitely.

    You should remember that Objective-C, the object parts, are very
    dynamic: everything can be done at run-time. You can create new classes
    at run-time, you can define new methods at run-time, you can instanciate
    those classes, and you can send messages at run-time, that weren't
    defined at compilation time and that the compiler knows nothing about.

    The only thing that is a little harder to do in C at run-time, is to
    actually compile a new method body. But using LLVM or dynamic loading
    of libraries (that you may have compiled at run-time invoking an
    external C compiler), you could also define new method bodies at
    run-time.

    Now, clearly, this is more difficult to do that in Objective-C than in Smalltalk or Lisp (and Apple forbids it on iOS). But this is still what Objective-C is, and this is the big difference between Objective-C and
    C++.



    --
    __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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Don Bruder on Mon Nov 23 18:44:37 2015
    On 11/22/2015 7:15 PM, Don Bruder wrote:
    In article <n2tcmc$t64$1@news.albasani.net>,
    Jon Rossen <jonr17@comcast.net> wrote:

    But how is this helpful? In my mind it's not helpful for a few
    different reasons. Reason 1: In the override to init you've hardwired
    the width and height to be 0. That's what NSObject's init would do, so
    it's not doing anything new or better. Reason 2: Even if you put
    different values in there say, 1 and 2 or whatever values you thought
    you might need a newly created Rectangle object to have, they are still
    hardwired values, buried inside the newly created init method. How is
    this helpful at all? You may want to have a bunch of rectangles of all
    different dimensions. At that point you'd have to change their
    dimensions with the proper accessor method. If so, why even both with
    this newly created init when you can just use NSObject's init and use
    the accessor method to tweak the height and width you want each
    Rectangle object to be?

    Am I correct that the trivial nature of this example sort of gets in the
    way of truly understanding the benefit or need of all of this?
    thanks,
    jonR

    In a nutshell, the "designated initializer" is *THE* initializer for a
    class that handles *ALL* possibilities for initialization that are
    available - Everything else is convenience methods.

    Ferinstance:

    Assume you've got a class with 5 instance variables, A, B, C, D, and E

    Your "designated initializer" should then look something like this:

    -(MyClass *)initWithA:(id)a andB:(id)b andC:(id)c andD:(id)d andE:(id)e
    {
    // I'm ignoring the various checking and calls to super's init for
    // brevity, since you seem to understand the chaining mechanism.
    // Now stuff the a,b,c,d, and e instance variables with the appropriate
    // values that were passed in - either by direct assignment, or via
    // accessor methods, as you please - then return self.
    }

    Now, assuming there's some reason you only need to init an instance
    with, ferinstance, a, while all the other instance vars can be left at default values, you could write:

    -(MyClass *)initWithJustA:(id)a
    { // (beware line-wrapping for post...)
    return [InitWithA:a andB:defaultBValue andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    Likewise, if you need to init A and B, but C, D, and E can be left at default, you'd write:

    -(MyClass *)initWithA:(id)a andB:(id)b
    { // (beware line-wrapping for post...)
    return [initWithA:a andB:b andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    and so on for each combination of initializations that make sense for
    your code.

    And finally, for an instance of the class that can be left with all of
    the vars at default values, you could write:

    -(MyClass *)init
    {
    return [InitWithA:defaultAValue andB:defaultBValue andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    Notice how the "plain" init calls the designated initializer with
    default values for each and every instance variable?

    Further note that in the "not designated" initializers, you *DON'T* do
    the [super init] checks and calls - You've written the "designated" initializer so that it handles doing that. So long as you call the
    designated initializer to do the actual initialization, that stuff gets handled "automagically"

    The whole point of the "designated initializer" is that an instance of a class - any class - is expected to be "ready to use" immediately after
    being initialized. Using a designated initializer makes certain that any setup an instance needs done gets done, with nothing being forgotten.

    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?

    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?
    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. Would this be considered bad form to do this? Or would the best
    course of action would be to write a new designated initializer and not
    do an override?
    Last one, slightly unrelated to 2a and 2b but still about relationships
    between classes and sub-classes:
    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.

    thanks, jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Don Bruder@21:1/5 to Jon Rossen on Sun Nov 22 19:15:37 2015
    In article <n2tcmc$t64$1@news.albasani.net>,
    Jon Rossen <jonr17@comcast.net> wrote:

    I have a rather beginner's basic type of question on designated
    initializers. The book that I'm using uses an extremely simple (and
    trivial) example (which is usually the case) which leaves me with about
    as many questions as answers.

    Here's the simple example from the book using a Rectangle class which is
    a child class of NSObject.

    Here's some of the pertinent info from Rectangle.h; I won't bother
    including stuff that's not directly related to the example:

    Rectangle.h

    @property int width, height;

    -(void) setWidth: (int) w andHeight: (int) h;
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    -(instancetype) init;


    Ok, here are just the new, custom init methods from Rectangle.m

    Rectangle.m

    //Designated initializer
    -(instancetype) initWithWidth: (int) w andHeight: (int) h;
    {
    self = [super init];
    if (self)
    [self setWidth:w andHeight:h];

    return self;
    }

    //The override of super's designated initializer
    -(instancetype) init
    {
    return [self initWithWidth:0 andHeight:0];
    }


    Ok, I get what's going on here: You create a new designated initializer which handles a lot of the ivars that you feel are important. You have
    to include a call super's designated intializer and assign it to self,
    then the 'if' test, then your initialization code. You then override
    super's designated initializer (in this case it's NSObject's init) and
    return a call to your designated initializer. I get how the hierarchy
    is supposed to work.

    But how is this helpful? In my mind it's not helpful for a few
    different reasons. Reason 1: In the override to init you've hardwired
    the width and height to be 0. That's what NSObject's init would do, so
    it's not doing anything new or better. Reason 2: Even if you put
    different values in there say, 1 and 2 or whatever values you thought
    you might need a newly created Rectangle object to have, they are still hardwired values, buried inside the newly created init method. How is
    this helpful at all? You may want to have a bunch of rectangles of all different dimensions. At that point you'd have to change their
    dimensions with the proper accessor method. If so, why even both with
    this newly created init when you can just use NSObject's init and use
    the accessor method to tweak the height and width you want each
    Rectangle object to be?

    Am I correct that the trivial nature of this example sort of gets in the
    way of truly understanding the benefit or need of all of this?
    thanks,
    jonR

    In a nutshell, the "designated initializer" is *THE* initializer for a
    class that handles *ALL* possibilities for initialization that are
    available - Everything else is convenience methods.

    Ferinstance:

    Assume you've got a class with 5 instance variables, A, B, C, D, and E

    Your "designated initializer" should then look something like this:

    -(MyClass *)initWithA:(id)a andB:(id)b andC:(id)c andD:(id)d andE:(id)e
    {
    // I'm ignoring the various checking and calls to super's init for
    // brevity, since you seem to understand the chaining mechanism.
    // Now stuff the a,b,c,d, and e instance variables with the appropriate
    // values that were passed in - either by direct assignment, or via
    // accessor methods, as you please - then return self.
    }

    Now, assuming there's some reason you only need to init an instance
    with, ferinstance, a, while all the other instance vars can be left at
    default values, you could write:

    -(MyClass *)initWithJustA:(id)a
    { // (beware line-wrapping for post...)
    return [InitWithA:a andB:defaultBValue andC:defaultCValue
    andD:defaultDValue andE:defaultEValue];
    }

    Likewise, if you need to init A and B, but C, D, and E can be left at
    default, you'd write:

    -(MyClass *)initWithA:(id)a andB:(id)b
    { // (beware line-wrapping for post...)
    return [initWithA:a andB:b andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    and so on for each combination of initializations that make sense for
    your code.

    And finally, for an instance of the class that can be left with all of
    the vars at default values, you could write:

    -(MyClass *)init
    {
    return [InitWithA:defaultAValue andB:defaultBValue andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    Notice how the "plain" init calls the designated initializer with
    default values for each and every instance variable?

    Further note that in the "not designated" initializers, you *DON'T* do
    the [super init] checks and calls - You've written the "designated"
    initializer so that it handles doing that. So long as you call the
    designated initializer to do the actual initialization, that stuff gets
    handled "automagically"

    The whole point of the "designated initializer" is that an instance of a
    class - any class - is expected to be "ready to use" immediately after
    being initialized. Using a designated initializer makes certain that any
    setup an instance needs done gets done, with nothing being forgotten.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Tue Nov 24 04:58:16 2015
    Jon Rossen <jonr17@comcast.net> writes:

    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?

    The important criteria is whether the superclass -init establishes the
    class invariant or not.


    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?

    You can change the designated initializer for each sub*class.
    But since this is not a property checked by the compiler, it would be
    very hard for the programmer to track which is the designated
    initializer of the current sub*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. Would this be considered bad form to do this? Or would
    the best course of action would be to write a new designated
    initializer and not do an override?

    There's never a "need" for a specific designated initializer. You can
    always either establish the invariant in the -init method (by setting
    good default ivars), or extend the invariant to allow for
    "half-initilized" instances.

    @interface Rectangle
    {
    int width;
    int height;
    }
    -(BOOL)isValid;
    -(BOOL)invariant;
    -(void)setWidth:(int)aWidth;
    -(void)setHeight:(int)aHeight;
    @end

    // half-initialized instances:

    @implementation Rectangle
    -(BOOL)isValid{return((0<width)&&(0<height));}
    -(BOOL)invariant{return(![self isValid] || ((0<width)&&(0<height)));}
    -(void)setWidth:(int)aWidth{width=aWidth;} // post: ![self isValid] || [self invariant]
    -(void)setHeight:(int)aHeight{height=aHeight;}; // post: ![self isValid] || [self invariant]
    @end

    [[[Rectangle alloc]init]invariant] --> YES
    [[[Rectangle alloc]init]isValid] --> NO

    // default-initialized instances:

    @implementation Rectangle
    -(id)init{if((self=[super init])){width=1;height=1;}return(self);}
    -(BOOL)isValid{return YES;}
    -(BOOL)invariant{return((0<width)&&(0<height));}
    -(void)setWidth:(int)aWidth{if(0<aWidth){width=aWidth;}}
    // pre: [self invariant] && good=(0<aWidth)
    // post: [self invariant] && (good => width==aWidth)
    -(void)setHeight:(int)aHeight{if(0<aHeight){height=aHeight;}}
    // pre: [self invariant] && good=(0<aHeight)
    // post: [self invariant] && (good => height==aHeight)
    @end

    [[[Rectangle alloc]init]invariant] --> YES
    [[[Rectangle alloc]init]isValid] --> YES


    Last one, slightly unrelated to 2a and 2b but still about
    relationships between classes and sub-classes:
    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.

    No. If you don't change the designated initializer, then the superclass
    -init that sends the designated initializer message will invoke the
    designated initializer method of the current class. You only need to
    write a new -init if it has to do something different to ensure the
    class invariant.


    enum {red,green,blue};
    @interface ColoredRectangle
    {
    int color;
    }
    @end

    @implementation ColoredRectangle

    -(id)initWithWidth:(int)w andHeight:(int)h{
    if((self=[super initWithWidth:w andHeight:h])){
    color=red;
    }
    return self;
    }

    -(BOOL)invariant{
    return [super invariant]
    && ((color==red)||(color=green)||(color==blue));}

    @end

    [[[ColoredRectangle alloc]init]invariant] --> YES

    [[ColoredRectangle alloc]init]
    calls -[Rectangle init]
    which sends -initWithWidht:andHeight: to self
    which calls -[ColoredRectangle initWithWidht:andHeight:]
    which sends -initWithWidht:andHeight: to super
    which calls -[Rectangle initWithWidht:andHeight:]
    which sends -init to super
    which calls -[NSObject init]

    --
    __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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Pascal J. Bourguignon on Tue Nov 24 16:42:05 2015
    On 11/23/2015 7:58 PM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:

    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?

    The important criteria is whether the superclass -init establishes the
    class invariant or not.

    Ok, got it, thanks.


    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?

    You can change the designated initializer for each sub*class.
    But since this is not a property checked by the compiler, it would be
    very hard for the programmer to track which is the designated
    initializer of the current sub*class.

    Ok.

    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. Would this be considered bad form to do this? Or would
    the best course of action would be to write a new designated
    initializer and not do an override?

    There's never a "need" for a specific designated initializer. You can
    always either establish the invariant in the -init method (by setting
    good default ivars), or extend the invariant to allow for
    "half-initilized" instances.

    @interface Rectangle
    {
    int width;
    int height;
    }
    -(BOOL)isValid;
    -(BOOL)invariant;
    -(void)setWidth:(int)aWidth;
    -(void)setHeight:(int)aHeight;
    @end

    // half-initialized instances:

    @implementation Rectangle
    -(BOOL)isValid{return((0<width)&&(0<height));}
    -(BOOL)invariant{return(![self isValid] || ((0<width)&&(0<height)));}
    -(void)setWidth:(int)aWidth{width=aWidth;} // post: ![self isValid] || [self invariant]
    -(void)setHeight:(int)aHeight{height=aHeight;}; // post: ![self isValid] || [self invariant]
    @end

    [[[Rectangle alloc]init]invariant] --> YES
    [[[Rectangle alloc]init]isValid] --> NO

    // default-initialized instances:

    @implementation Rectangle
    -(id)init{if((self=[super init])){width=1;height=1;}return(self);}
    -(BOOL)isValid{return YES;}
    -(BOOL)invariant{return((0<width)&&(0<height));}
    -(void)setWidth:(int)aWidth{if(0<aWidth){width=aWidth;}}
    // pre: [self invariant] && good=(0<aWidth)
    // post: [self invariant] && (good => width==aWidth)
    -(void)setHeight:(int)aHeight{if(0<aHeight){height=aHeight;}}
    // pre: [self invariant] && good=(0<aHeight)
    // post: [self invariant] && (good => height==aHeight)
    @end

    [[[Rectangle alloc]init]invariant] --> YES
    [[[Rectangle alloc]init]isValid] --> YES

    Ok, it's going to take me a while to digest this.


    Last one, slightly unrelated to 2a and 2b but still about
    relationships between classes and sub-classes:
    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.

    No. If you don't change the designated initializer, then the superclass -init that sends the designated initializer message will invoke the designated initializer method of the current class. You only need to
    write a new -init if it has to do something different to ensure the
    class invariant.

    I'm not sure whether I wasn't clear in how I posed the question and you
    are misunderstanding me, or I'm not understanding your answer. I asked
    if you had to rewrite init where there is a new designated initializer,
    meaning that you *HAD* to re-write init. Conversely, when I posed the question, my assumption was that if there was NOT a new designated
    initializer then init would not have to be rewritten...which is what you
    seem to be saying here. So, I'm not sure why you started your answer
    with a 'No': It either could be that I wasn't clear in my question OR
    you did understand the question and I'm not understanding a fine point
    you are making.


    enum {red,green,blue};
    @interface ColoredRectangle
    {
    int color;
    }
    @end

    @implementation ColoredRectangle

    -(id)initWithWidth:(int)w andHeight:(int)h{
    if((self=[super initWithWidth:w andHeight:h])){
    color=red;
    }
    return self;
    }

    -(BOOL)invariant{
    return [super invariant]
    && ((color==red)||(color=green)||(color==blue));}

    @end

    [[[ColoredRectangle alloc]init]invariant] --> YES

    [[ColoredRectangle alloc]init]
    calls -[Rectangle init]
    which sends -initWithWidht:andHeight: to self
    which calls -[ColoredRectangle initWithWidht:andHeight:]
    which sends -initWithWidht:andHeight: to super
    which calls -[Rectangle initWithWidht:andHeight:]
    which sends -init to super
    which calls -[NSObject init]

    This makes sense, at least the way the method calls work with each
    other. Did you show this *just* to show the chain of events? Or, did
    you mean it to represent a workflow, in how these methods would be used?
    That's the part that doesn't make sense (using init). You are starting
    off by calling init, (which calls Rectangle's init) and sets of this
    chain of events. However, you've lost your opportunity to directly use
    the designated initializer and pass arguments to it. Wouldn't you just
    use the designated initializer in the sub-class (ColoredRectangle) just
    as it would be used in the parent class (Rectangle)?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to All on Tue Nov 24 15:54:38 2015
    < 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.


    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. :-)

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


    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?


    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'?


    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.

    Basically, yes. See the snippets above.

    Yep, my above two comments discusses this.

    thanks for your response.
    -jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Don Bruder@21:1/5 to Jon Rossen on Tue Nov 24 07:38:30 2015
    In article <n30iuo$c4b$1@news.albasani.net>,
    Jon Rossen <jonr17@comcast.net> wrote:

    On 11/22/2015 7:15 PM, Don Bruder wrote:
    In article <n2tcmc$t64$1@news.albasani.net>,
    Jon Rossen <jonr17@comcast.net> wrote:

    But how is this helpful? In my mind it's not helpful for a few
    different reasons. Reason 1: In the override to init you've hardwired
    the width and height to be 0. That's what NSObject's init would do, so
    it's not doing anything new or better. Reason 2: Even if you put
    different values in there say, 1 and 2 or whatever values you thought
    you might need a newly created Rectangle object to have, they are still
    hardwired values, buried inside the newly created init method. How is
    this helpful at all? You may want to have a bunch of rectangles of all
    different dimensions. At that point you'd have to change their
    dimensions with the proper accessor method. If so, why even both with
    this newly created init when you can just use NSObject's init and use
    the accessor method to tweak the height and width you want each
    Rectangle object to be?

    Am I correct that the trivial nature of this example sort of gets in the >> way of truly understanding the benefit or need of all of this?
    thanks,
    jonR

    In a nutshell, the "designated initializer" is *THE* initializer for a class that handles *ALL* possibilities for initialization that are available - Everything else is convenience methods.

    Ferinstance:

    Assume you've got a class with 5 instance variables, A, B, C, D, and E

    Your "designated initializer" should then look something like this:

    -(MyClass *)initWithA:(id)a andB:(id)b andC:(id)c andD:(id)d andE:(id)e
    {
    // I'm ignoring the various checking and calls to super's init for
    // brevity, since you seem to understand the chaining mechanism.
    // Now stuff the a,b,c,d, and e instance variables with the appropriate
    // values that were passed in - either by direct assignment, or via
    // accessor methods, as you please - then return self.
    }

    Now, assuming there's some reason you only need to init an instance
    with, ferinstance, a, while all the other instance vars can be left at default values, you could write:

    -(MyClass *)initWithJustA:(id)a
    { // (beware line-wrapping for post...)
    return [InitWithA:a andB:defaultBValue andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    Likewise, if you need to init A and B, but C, D, and E can be left at default, you'd write:

    -(MyClass *)initWithA:(id)a andB:(id)b
    { // (beware line-wrapping for post...)
    return [initWithA:a andB:b andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    and so on for each combination of initializations that make sense for
    your code.

    And finally, for an instance of the class that can be left with all of
    the vars at default values, you could write:

    -(MyClass *)init
    {
    return [InitWithA:defaultAValue andB:defaultBValue andC:defaultCValue andD:defaultDValue andE:defaultEValue];
    }

    Notice how the "plain" init calls the designated initializer with
    default values for each and every instance variable?

    Further note that in the "not designated" initializers, you *DON'T* do
    the [super init] checks and calls - You've written the "designated" initializer so that it handles doing that. So long as you call the designated initializer to do the actual initialization, that stuff gets handled "automagically"

    The whole point of the "designated initializer" is that an instance of a class - any class - is expected to be "ready to use" immediately after being initialized. Using a designated initializer makes certain that any setup an instance needs done gets done, with nothing being forgotten.

    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)


    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? :) )

    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.

    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.

    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.

    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.

    Basically, yes. See the snippets above.

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Wed Nov 25 01:49:13 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Don Bruder@21:1/5 to Pascal J. Bourguignon on Tue Nov 24 18:51:37 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Wed Nov 25 02:00:37 2015
    Jon Rossen <jonr17@comcast.net> writes:

    On 11/23/2015 7:58 PM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:
    Last one, slightly unrelated to 2a and 2b but still about
    relationships between classes and sub-classes:
    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.

    No. If you don't change the designated initializer, then the superclass
    -init that sends the designated initializer message will invoke the
    designated initializer method of the current class. You only need to
    write a new -init if it has to do something different to ensure the
    class invariant.

    I'm not sure whether I wasn't clear in how I posed the question and
    you are misunderstanding me, or I'm not understanding your answer. I
    asked if you had to rewrite init where there is a new designated
    initializer, meaning that you *HAD* to re-write init. Conversely,
    when I posed the question, my assumption was that if there was NOT a
    new designated initializer then init would not have to be
    rewritten...which is what you seem to be saying here. So, I'm not
    sure why you started your answer with a 'No': It either could be that
    I wasn't clear in my question OR you did understand the question and
    I'm not understanding a fine point you are making.

    Yes, I may have misunderstood.

    Indeed, there are two cases:

    - the new class defines a new designated initializer
    (then it must override all the other initializers so they all call the
    new designated initializer),

    - the new class doesn't define a new designated initializer
    (then it must only override the designated initializer, and can rely
    on the superclasses to forward the other initializers to the
    designated initializer).


    However, in the later case, you might still want to override the other initializers, so that you may call the designated initializer with
    default values specific to the new class.


    [[ColoredRectangle alloc]init]
    calls -[Rectangle init]
    which sends -initWithWidht:andHeight: to self
    which calls -[ColoredRectangle initWithWidht:andHeight:]
    which sends -initWithWidht:andHeight: to super
    which calls -[Rectangle initWithWidht:andHeight:]
    which sends -init to super
    which calls -[NSObject init]

    This makes sense, at least the way the method calls work with each
    other. Did you show this *just* to show the chain of events? Or, did
    you mean it to represent a workflow, in how these methods would be
    used? That's the part that doesn't make sense (using init). You are starting off by calling init, (which calls Rectangle's init) and sets
    of this chain of events. However, you've lost your opportunity to
    directly use the designated initializer and pass arguments to it.
    Wouldn't you just use the designated initializer in the sub-class (ColoredRectangle) just as it would be used in the parent class
    (Rectangle)?

    Of course. If you want to make a new colored rectangle with a different
    initial size, you will call the designated initializer.

    [[ColoredRectangle alloc]initWithWidht:42 andHeight:33]
    which sends -initWithWidht:andHeight: to self
    which calls -[ColoredRectangle initWithWidth:andHeight:]
    which sends -initWithWidth:andHeight: to super
    which calls -[Rectangle initWithWidth:andHeight:]
    which sends -init to super
    which calls -[NSObject init]

    (But in actual code, you would probably make a new designated
    initializer for a colored rectangle:

    @implementation ColorRectangle

    // new designated initializer:
    -(id)initWithWidth:(int)w andHeight:(int)h andColor:(int)c {
    if((self=[super initWithWidht:w andHeight:h])){
    color=c;
    }
    return self;
    }

    //inherited initializers:
    -(id)initWithWidth:(int)w andHeight:(int)h {
    return [self initWithWidth:w andHeight:h andColor:red];
    }

    // for init, you can rely on -[Rectangle init]
    // to call -initWithWidth:andHeight:.

    @end

    )
    --
    __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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Don Bruder@21:1/5 to Jon Rossen on Tue Nov 24 18:29:47 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Pascal J. Bourguignon on Wed Nov 25 00:25:25 2015
    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---


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Parker@21:1/5 to Pascal J. Bourguignon on Wed Nov 25 01:25:04 2015
    "Pascal J. Bourguignon" <pjb@informatimago.com> writes:

    Jon Rossen <jonr17@comcast.net> writes:

    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?

    You can change the designated initializer for each sub*class.
    But since this is not a property checked by the compiler, it would be
    very hard for the programmer to track which is the designated
    initializer of the current sub*class.

    Recent versions of clang support compile-time enforcement of the
    designated initializer pattern in initializer calls and overrides.
    Look up __attribute__((objc_designated_initializer)) and its Cocoa
    equivalent NS_DESIGNATED_INITIALIZER.


    --
    Greg Parker gparker@apple.com Runtime Wrangler

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Don Bruder on Wed Nov 25 04:41:25 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Don Bruder on Wed Nov 25 18:41:26 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Don Bruder@21:1/5 to Pascal J. Bourguignon on Wed Nov 25 09:08:24 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Wed Nov 25 14:16:29 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Thu Nov 26 03:03:58 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to different spin on what you on Wed Nov 25 17:30:38 2015
    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.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Pascal J. Bourguignon on Fri Nov 27 17:19:28 2015
    On 11/22/2015 5:02 PM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:

    Thanks for the explanations and to be honest I don't fully understand
    all of what you have said, but I understand it enough for it to make
    sense. However, I realize I need to understand class invariants which
    is a new concept to me. I think that is the primary component or
    background for me that is lacking and when I get a better
    understanding I'll fully understand your explanation.

    Have a look at:

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



    Geez, interesting but did you really think someone who calls himself a
    relative beginner that stated he needed help understanding class
    invariants could learn about them by reading this? You almost need to
    know all about class invariants *first* in order to understand this
    Wikipedia article. Around the time I would start to sort things out I'd
    get another obscure set of factoids and jargon thrown at me that would
    create a new set of uncertainty and eventually I spiraled down the
    rabbit hole of confusion scratching my head and saying WTF! :-) I'm
    sure with a few Google searches I may come up with some other stuff to
    read and perhaps with all of them it will start to become clear. Thanks
    for at least taking the time to try and get me on the correct path.
    -jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jon Rossen@21:1/5 to Pascal J. Bourguignon on Sat Nov 28 17:37:45 2015
    On 11/28/2015 4:22 AM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:

    On 11/22/2015 5:02 PM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:

    Thanks for the explanations and to be honest I don't fully understand
    all of what you have said, but I understand it enough for it to make
    sense. However, I realize I need to understand class invariants which >>>> is a new concept to me. I think that is the primary component or
    background for me that is lacking and when I get a better
    understanding I'll fully understand your explanation.

    Have a look at:

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



    Geez, interesting but did you really think someone who calls himself a
    relative beginner that stated he needed help understanding class
    invariants could learn about them by reading this?

    Of course not. This is just a pointer to search for further references.
    The newbie shall find a book or some on-line course about the subject.

    You almost need to know all about class invariants *first* in order to
    understand this Wikipedia article. Around the time I would start to
    sort things out I'd get another obscure set of factoids and jargon
    thrown at me that would create a new set of uncertainty and eventually
    I spiraled down the rabbit hole of confusion scratching my head and
    saying WTF! :-) I'm sure with a few Google searches I may come up
    with some other stuff to read and perhaps with all of them it will
    start to become clear. Thanks for at least taking the time to try and
    get me on the correct path.

    Also I would tend to assume a CS formation for newbie programmers.
    Granted this is probably an error, and also it looks like a lot of universities or programming schools fail to teach anything to students
    worth the money they paiy for it, but I fail to see how one could gain the ability of programming without having it.

    Also, specifically about invariants, pre-/post-conditions, and in
    general Hoare logic and program proofs, this is not something specific to OOP. It should have been learned along with the procedural programming languages. Actually, OO introduces indeed some complexities, of which
    the Lyskov's substitution principle is the least, and (purely) functional programming also does better with a different variant, given that it
    avoids mutation. Lyskov's substitution principle is but a trivial application of Hoare logic in the context of inheritance.

    There was one simple example given that discussed a Rectangle class that
    had a Square sub-class. Obviously, in Geometry a square is a rectangle
    but a rectangle is not a square. The programming issue that was brought
    up was basically an outgrowth of this subset/superset relationship
    involving the setters needed to set the dimension of the objects. For rectangles you'd need height and width but for squares you really only
    need one, and furthermore having two for the square would not really be
    correct contextually. These seem like expected inherent differences in
    these two classes, but I was getting mixed up following the article and
    whether it was suggesting that this condition between these two classes
    were following LSP or 'breaking' it. Basically I got lost trying to
    fully understand how this example was being used. Perhaps I'll reread
    that specific section and you as Professor Bourguignon can fill me in
    with answers if I can figure out how to craft some specific questions. :-) thx, jonR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Sat Nov 28 13:22:58 2015
    Jon Rossen <jonr17@comcast.net> writes:

    On 11/22/2015 5:02 PM, Pascal J. Bourguignon wrote:
    Jon Rossen <jonr17@comcast.net> writes:

    Thanks for the explanations and to be honest I don't fully understand
    all of what you have said, but I understand it enough for it to make
    sense. However, I realize I need to understand class invariants which
    is a new concept to me. I think that is the primary component or
    background for me that is lacking and when I get a better
    understanding I'll fully understand your explanation.

    Have a look at:

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



    Geez, interesting but did you really think someone who calls himself a relative beginner that stated he needed help understanding class
    invariants could learn about them by reading this?

    Of course not. This is just a pointer to search for further references.
    The newbie shall find a book or some on-line course about the subject.

    You almost need to know all about class invariants *first* in order to understand this Wikipedia article. Around the time I would start to
    sort things out I'd get another obscure set of factoids and jargon
    thrown at me that would create a new set of uncertainty and eventually
    I spiraled down the rabbit hole of confusion scratching my head and
    saying WTF! :-) I'm sure with a few Google searches I may come up
    with some other stuff to read and perhaps with all of them it will
    start to become clear. Thanks for at least taking the time to try and
    get me on the correct path.

    Also I would tend to assume a CS formation for newbie programmers.
    Granted this is probably an error, and also it looks like a lot of
    universities or programming schools fail to teach anything to students
    worth the money they paiy for it, but I fail to see how one could gain the ability of programming without having it.

    Also, specifically about invariants, pre-/post-conditions, and in
    general Hoare logic and program proofs, this is not something specific to
    OOP. It should have been learned along with the procedural programming languages. Actually, OO introduces indeed some complexities, of which
    the Lyskov's substitution principle is the least, and (purely) functional programming also does better with a different variant, given that it
    avoids mutation. Lyskov's substitution principle is but a trivial
    application of Hoare logic in the context of inheritance.

    --
    __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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Jon Rossen on Sun Nov 29 03:45:31 2015
    Jon Rossen <jonr17@comcast.net> writes:

    There was one simple example given that discussed a Rectangle class
    that had a Square sub-class. Obviously, in Geometry a square is a
    rectangle but a rectangle is not a square. The programming issue that
    was brought up was basically an outgrowth of this subset/superset relationship involving the setters needed to set the dimension of the objects. For rectangles you'd need height and width but for squares
    you really only need one, and furthermore having two for the square
    would not really be correct contextually. These seem like expected
    inherent differences in these two classes, but I was getting mixed up following the article and whether it was suggesting that this
    condition between these two classes were following LSP or 'breaking'
    it. Basically I got lost trying to fully understand how this example
    was being used. Perhaps I'll reread that specific section and you as Professor Bourguignon can fill me in with answers if I can figure out
    how to craft some specific questions. :-)

    It all depends on the set of invariants and pre-/post- conditions you
    choose.

    Basically, when you don't specify them, then you have:

    invariant = true
    all pre-condition = true
    all post-condition = true

    and since true => true, anything goes in subclasses.

    But also, all bugs are features, of course.

    If you have:

    -(int)width;
    -(void)setWidth:(int)aWidth;

    then you have nothing.

    Ie. you cannot say anything about: ([r setWidth:42],[r width])


    If you have:

    @interface Rectangle

    -(int)width;

    -(void)setWidth:(int)aWidth;
    // pre: h==[self height]
    // post: aWidth==[self width] && h==[self height]

    @end

    and similar for heigth, then you won't be able to have Square with the invariant [square width]==[square height] as a subclass of Rectangle.


    But if you have:

    @interface Rectangle

    -(bool)invariant { return YES; }

    -(int)width;

    -(void)setWidth:(int)aWidth;
    // pre: true
    // post: aWidth==[self width]

    @end


    then you can have Square as a subclass of Rectangle, with:

    @interface Square

    -(bool)invariant { return [self width]==[self height]; }

    -(void)setWidth:(int)aWidth;
    // pre: true
    // post: aWidth==[self width] && aWidth==[self height]

    @end

    because:

    true ==> true
    and:
    (aWidth==[self width] && aWidth==[self height]) ==> aWidth==[self width]

    therefore the pre-condition of -[Rectangle setWidth:]
    ==> the pre-condition of -[Square setWidth:]

    and the post-condition of -[Square setWidth:]
    the post-condition of -[Rectangle setWidth:]

    and -[Square invariant]
    -[Rectangle invariant]


    so Liskov's substitution principle will let you substitue any Rectangle instance by a Square instance anywhere.

    (Because basically, you are not expecting that [self width]!=[self
    height], you are just expecting TRUE (ie. anything)).




    Notice that there are two sources of difficulty here:

    1- mutation.
    2- lack of multiple-inheritance.



    Consider the graph:

    https://en.wikipedia.org/wiki/Parallelogram#/media/File:Symmetries_of_square.svg

    it actually gives an inheriting graph (with the superclasses down),
    where some subclasses inherit from multiple superclasses (thus
    representing an intersection of the set of values of the superclasses).

    Trapezoid isSubclassOf: IrregularQuadrilateral
    IsoceleTrapezoid isSubclassOf: Trapezoid
    Parallelogram isSubclassOf: IrregularQuadrilateral
    Kite isSubclassOf: IrregularQuadrilateral

    Rhombus isSubclassOf: Parallelogram and: Kite
    Rectangle isSubclassOf: Parallelogram and: IsoceleTrapezoid

    Square isSubclassOf: Parallelogram and: Rectangle and: Rhombus


    If we consider only Square and Rectangle,
    we could have:

    @interface Rectangle
    -(id)initWithWidth:(int)w andHeight:(int)h; //designated initialiser;
    -(bool)invariant{return [self width]>0 && [self height]>0;}
    -(int)width;
    -(int)height;
    // no setters, no mutation
    @end

    @interface Square
    -(id)initWithSide:(int)side; //designated initialiser;
    -(bool)invariant{return [super invariant] && [self width]==[self height];}
    -(int)width;
    -(int)height;
    // no setters, no mutation
    @end

    @implementation Rectangle
    -(id)clusterInitWithWidth:(int)w andHeight:(int)h{
    if((self=[super init])){
    width=w;
    height=h;
    }
    return self;
    }
    -(id)initWithWidth:(int)w andHeight:(int)h{
    w=max(1,w);
    h=max(1,h);
    if(w==h){
    [self dealloc];
    self=[[Square alloc]initWithSide:w];
    }else{
    self=[self clusterInitWithWidth:w andHeight:h];
    }
    return self;
    }
    @end

    @implementation Square
    -(id)initWithSide:(int)s
    return [self clusterInitWithWidth:s andHeight:s];
    }
    @end


    So now, when you do:

    [Rectangle initWithWidth:3 andHeight:3]

    you get actually an instance of Square, which is a subclass of
    Rectangle, so all the method of Rectangle still apply (thanks to
    Liskov's Substitution Principle).

    (Notice that in Foundation and AppKit, there are several such instances
    of class clusters, where allocating a superclass actually gives you an
    instance of a specific subclass)

    But since in Objective-C we lack multiple-inheritance, this using
    immutable classes goes only so far, since we couldn't make Square also a subclass of Rhombus and Parallelogram.


    Types are often considered as mathematical sets of values.

    On the other hand, classes, while having a potential set of instances,
    define more a representation than a set of values.

    For example, we could have two unrelated classes:

    @interface Rectangle
    -(id)initWithWidth:(int)w andHeight:(int)h;
    -(int)width;
    -(int)height;
    @end

    @interface Square
    -(id)initWithSide:(int)s;
    -(int)side;
    @end


    id r=[[Rectangle alloc]initWithWidth:3 andHeight:3];
    id s=[[Square alloc]initWithSide:3];

    What is r?

    You'll say it's an instance of Rectangle,
    but it's also the representation of a square of side 3.

    Just like s, is an instance of Square, and the representation of the
    same square of side 3.

    So we have two representations of a square of side 3.

    Mathematically, there would be a single type, a single set of a square
    of side 3, with this unique element, but in OO, we have defined two
    different classes and two different instances representating this same
    value.

    So one should not confuse types and classes, and the set operations that
    are mathematically valid on types, are not directly applicable to
    classes and their instances.


    Having two unrelated classes for Square and Rectangle can be as
    problematic has having one class being a subclass of the other or
    vice-versa. You have to choose what representations are the best for
    the problem at hand, by specifying the invariants, pre-/post- conditions
    that makes you program simple and clear, and therefore the class
    hierarchy that works best for the current problem.

    For example, if you have to deal with polygons and their mathematical properties, it might be better to have a general Polygon class, allowing
    for any number of points at any coordinates, and instead of representing
    the mathematical sets Square Rectangle, Rhombus, Parallelograms,
    Triangle, Hexagon, etc, you could define:

    @interface Polygon
    -(id)initWithPoints:(NSArray*)points;
    -(bool)invariant{return [point count]>=3;}
    -(bool)isRectangle;
    -(bool)isRhombus;
    -(bool)isParallelogram;
    -(bool)isSquare{return [self isParallelogram]
    && [self isRectangle]
    && [self isRhombus];}

    -(float)baseAngle;

    @end

    So the definition of Square as the intersection of Rectangle
    Parallelogram and Rhombus translates clearly as a conjuction in the
    predicate -isSquare.

    And this model would allow mutation, since you could easily "move" a
    single point of the parallelogram (or add or remove points), and the
    predicates would "reclassify" it.

    --
    __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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Don Bruder@21:1/5 to Pascal J. Bourguignon on Wed Dec 2 14:37:47 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Pascal J. Bourguignon@21:1/5 to Don Bruder on Thu Dec 3 00:58:45 2015
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)