@properties and Information Hiding

  • Hello,

    It was interesting to read how the new @properties feature of
    Objective-C 2.0 are justified in terms of encapsulation.  Of course,
    one of the other major principles of object-oriented programming is
    information hiding, that is, only exposing (making public) the parts
    of an object which are necessary for interaction with it.  At first
    look, it seems that properties make it much easier to break this
    principle.  (Note that I am not saying that it does break it, just
    that it makes it easier to.)

    Along these lines, I am looking for advise on how to implement a
    pattern that I am sure many people use: having a private setter and a
    public getter.  Before properties, I'd implement the two methods in
    the implementation part and only declare the getter in the interface
    part.  But now, in the 2.0 world, how can I leverage the magic of
    synthesis to implement such a pattern?

    Thanks in advance!

    Karl
  • You can declare a property readonly in your interface, and then re-
    declare it as readwrite in a private category or class extension.
    Here's what the Objective-C 2.0 docs say:
    > You can re-declare a property in a subclass, but (with one
    > exception) you must repeat its attributes in whole in the
    > subclasses. The same holds true for a property declared in a
    > category or protocol—while the property may be redeclared in a
    > category or protocol, the property’s attributes must be repeated in
    > whole.
    >
    > The one exception is readonly vs. readwrite. A property declared as
    > readonly can be redeclared as readwrite in a category, protocol or
    > subclass—see “Subclassing with Properties.” In the case of a
    > category redeclaration, that the property was redeclared prior any
    > @synthesize statement will cause the setter to be synthesized.
    >

    The only problem with this is that you can't re-declare any of the
    other declaration attributes. This means that if you want to use the
    "retain" or "copy" style of accessor, rather than the default
    "assign", you have to declare this in the interface. This annoys me -
    it obviously doesn't make a lot of sense to declare a property as
    (readonly, copy) in the interface, but as far as I can tell that's
    exactly what you have to do.

    Milo
  • On Nov 1, 2007, at 9:07 AM, Karl Goiser wrote:

    > Along these lines, I am looking for advise on how to implement a
    > pattern that I am sure many people use: having a private setter and
    > a public getter.  Before properties, I'd implement the two methods
    > in the implementation part and only declare the getter in the
    > interface part.  But now, in the 2.0 world, how can I leverage the
    > magic of synthesis to implement such a pattern?

    p. 50 of the Objective-C 2.0 pdf:

    "This enables two common implementation patterns; mutable
    subclass of an immutable class (NSString, NSArray, and NSDictionary
    are all examples) and a
    property that has public API that is readonly but a private readwrite
    implementation internal to
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    the class."

    Raffael Cavallaro, Ph.D.
    <raffaelcavallaro...>
  • --- Karl Goiser <KGoiser...> wrote:

    > It was interesting to read how the new @properties
    > feature of
    > Objective-C 2.0 are justified in terms of
    > encapsulation.  Of course,
    > one of the other major principles of object-oriented
    > programming is
    > information hiding, that is, only exposing (making
    > public) the parts
    > of an object which are necessary for interaction
    > with it.  At first
    > look, it seems that properties make it much easier
    > to break this
    > principle.

    How do you mean? I really don't see it, unless you
    mean "It's easier to write a class in general, and
    thus by extension it's easier to write a class with
    poor encapsulation." I don't think the requirement of
    declaring accessors as methods did very much to
    safeguard implementation details.

    > Along these lines, I am looking for advise on how to
    > implement a
    > pattern that I am sure many people use: having a
    > private setter and a
    > public getter.  Before properties, I'd implement the
    > two methods in
    > the implementation part and only declare the getter
    > in the interface
    > part.  But now, in the 2.0 world, how can I leverage
    > the magic of
    > synthesis to implement such a pattern?

    I don't think you can synthesize it. I'd just declare
    the property read-only and do it the same way you've
    always done it for the private setter.

    Cheers,
    Chuck

    __________________________________________________
    Do You Yahoo!?
    Tired of spam?  Yahoo! Mail has the best spam protection around
    http://mail.yahoo.com
  • --- Milo Bird <milobird...> wrote:

    > The only problem with this is that you can't
    > re-declare any of the
    > other declaration attributes. This means that if you
    > want to use the
    > "retain" or "copy" style of accessor, rather than
    > the default
    > "assign", you have to declare this in the interface.

    Oh, is that the trick? That's some useful information.
    I knew I'd tried this before, thinking it should work,
    but I'd gotten a compiler warning about redefining the
    property. It must not have occurred to me to put the
    copy part in the readonly definition. Thanks for that!

    Cheers,
    Chuck

    __________________________________________________
    Do You Yahoo!?
    Tired of spam?  Yahoo! Mail has the best spam protection around
    http://mail.yahoo.com
  • Thanks for the replies, everybody!

    I was afraid that that might be the recommendation!

    So, let's make a comparison using class extensions (this seems to me
    to be the most applicable because it allows the compiler to do more
    checking which is good):

    Before:

    <interface file>
    @interface MyClass : NSObject {
        NSString *value;
    }
    - (NSString *) value;
    @end

    <implementation file>
    @implementation MyClass

    - (NSString *) value {return value};

    - (void) setValue: (NSString *) stringParameter {
        [stringParameter retain];
        [value release];
        value = stringParameter;
    }

    @end

    After:

    <interface file>
    @interface MyClass : NSObject {
        NSString *value;
    }
    @property(readonly, retain) NSString *value;
    @end

    <implementation file>
    @interface MyClass ()
    @property(readwrite, retain) NSString *value;
    @end

    @implementation MyClass
    @synthesize value;

    @end

    Is this how I should implement public getters and private setters?

    If so, this hardly seems like an advantage.  Sure, the number of lines
    has decreased, but that is mostly in terms of white space, and only
    marginally - and traded off with hiding the implementation of the
    actual methods.  Also, there were three places where I have to worry
    about the instance variable (in the class declaration, getter method
    declaration and method implementations), now there are four (in the
    class declaration, getter method declaration, class extension and
    synthesize statement). which won't make maintenance any easier.

    I'm sorry, I don't want to turn this into a language war (and incur
    the wrath of the list gods), I just would like to know what's the best
    way to implement this pattern in my Cocoa code...

    Thanks,

    Karl

    On 02/11/2007, at 2:00 AM, Raffael Cavallaro wrote:

    >
    > On Nov 1, 2007, at 9:07 AM, Karl Goiser wrote:
    >
    >> Along these lines, I am looking for advise on how to implement a
    >> pattern that I am sure many people use: having a private setter and
    >> a public getter.  Before properties, I'd implement the two methods
    >> in the implementation part and only declare the getter in the
    >> interface part.  But now, in the 2.0 world, how can I leverage the
    >> magic of synthesis to implement such a pattern?
    >
    > p. 50 of the Objective-C 2.0 pdf:
    >
    > "This enables two common implementation patterns; mutable
    > subclass of an immutable class (NSString, NSArray, and NSDictionary
    > are all examples) and a
    > property that has public API that is readonly but a private
    > readwrite implementation internal to
    > ^
    > ^
    > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    > the class."
  • Hm, using the properties, you only worry about the ivar in the class
    declaration and the synthesize declaration... One less than before.
    The other appearances of "value" are for the property itself
    independently of the effective property's implementation (in this
    case, using an ivar)

    For the sake of the demonstration, try changing the ivar name to
    "theValue" in both cases.

    --
    Julien

    Sent from my iPod

    On 1 nov. 07, at 23:57, Karl Goiser <KGoiser...> wrote:

    > Thanks for the replies, everybody!
    >
    > I was afraid that that might be the recommendation!
    >
    > So, let's make a comparison using class extensions (this seems to me
    > to be the most applicable because it allows the compiler to do more
    > checking which is good):
    >
    > Before:
    >
    > <interface file>
    > @interface MyClass : NSObject {
    > NSString *value;
    > }
    > - (NSString *) value;
    > @end
    >
    > <implementation file>
    > @implementation MyClass
    >
    > - (NSString *) value {return value};
    >
    > - (void) setValue: (NSString *) stringParameter {
    > [stringParameter retain];
    > [value release];
    > value = stringParameter;
    > }
    >
    > @end
    >
    > After:
    >
    > <interface file>
    > @interface MyClass : NSObject {
    > NSString *value;
    > }
    > @property(readonly, retain) NSString *value;
    > @end
    >
    > <implementation file>
    > @interface MyClass ()
    > @property(readwrite, retain) NSString *value;
    > @end
    >
    > @implementation MyClass
    > @synthesize value;
    >
    > @end
    >
    >
    > Is this how I should implement public getters and private setters?
    >
    > If so, this hardly seems like an advantage.  Sure, the number of
    > lines has decreased, but that is mostly in terms of white space, and
    > only marginally - and traded off with hiding the implementation of
    > the actual methods.  Also, there were three places where I have to
    > worry about the instance variable (in the class declaration, getter
    > method declaration and method implementations), now there are four
    > (in the class declaration, getter method declaration, class
    > extension and synthesize statement). which won't make maintenance
    > any easier.
    >
    > I'm sorry, I don't want to turn this into a language war (and incur
    > the wrath of the list gods), I just would like to know what's the
    > best way to implement this pattern in my Cocoa code...
    >
    >
    > Thanks,
    >
    > Karl
    >
    >
    > On 02/11/2007, at 2:00 AM, Raffael Cavallaro wrote:
    >
    >>
    >> On Nov 1, 2007, at 9:07 AM, Karl Goiser wrote:
    >>
    >>> Along these lines, I am looking for advise on how to implement a
    >>> pattern that I am sure many people use: having a private setter
    >>> and a public getter.  Before properties, I'd implement the two
    >>> methods in the implementation part and only declare the getter in
    >>> the interface part.  But now, in the 2.0 world, how can I leverage
    >>> the magic of synthesis to implement such a pattern?
    >>
    >> p. 50 of the Objective-C 2.0 pdf:
    >>
    >> "This enables two common implementation patterns; mutable
    >> subclass of an immutable class (NSString, NSArray, and NSDictionary
    >> are all examples) and a
    >> property that has public API that is readonly but a private
    >> readwrite implementation internal to
    >> ^^^
    >> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    >> the class."

  • On Nov 1, 2007, at 3:57 PM, Karl Goiser wrote:

    > So, let's make a comparison using class extensions (this seems to me
    > to be the most applicable because it allows the compiler to do more
    > checking which is good):
    > [...]
    > If so, this hardly seems like an advantage.  Sure, the number of
    > lines has decreased, but that is mostly in terms of white space, and
    > only marginally - and traded off with hiding the implementation of
    > the actual methods.
    >
    It may not appear much of an advantage for one property, however if
    you spread this over numerous properties the effect is more
    noticeable.  Particularly when you have properties that are publicly
    declared as readwrite so you don't have to do the category dance.  The
    effect is especially noticeable for Core Data (see <http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles
    /cdAccessorMethods.html
    >).

    There are two additional considerations:

    (a) You have incorrectly specified your property; given the
    implementation you seem to want, it should be:

    @property(readonly, retain, nonatomic) NSString *value;

    By default properties are atomic, so you're actually "not seeing"
    considerably more code than you first showed.

    (b) Consumers of your class now see, instead of:

    @interface MyClass : NSObject {
        NSString *value;
    }
    - (NSString *) value;
    @end

    this:

    @interface MyClass : NSObject {
        NSString *value;
    }
    @property(readonly, retain [, nonatomic]) NSString *value;
    @end

    This makes your intent for the property much more clear.

    > Also, there were three places where I have to worry about the
    > instance variable (in the class declaration, getter method
    > declaration and method implementations), now there are four (in the
    > class declaration, getter method declaration, class extension and
    > synthesize statement). which won't make maintenance any easier.
    >
    It's not clear exactly what you mean by "worrying about the instance
    variable".

    One of the attractions of properties is that they're not tied to an
    instance variable -- you can rename either the ivar or the property
    and "redirect" using the synthesize directive 'ivar='.

    Moreover, in the traditional case you certainly have more than three
    places where the property/ivar name is required:

    @interface MyClass : NSObject {
      NSString *value; // 1
    }
    - (NSString *) value; // 2
    @end

    <implementation file>
    @implementation MyClass

    - (NSString *) value /* 3 */ {return value /* 4 */};

    - (void) setValue: /* 5 */ (NSString *) stringParameter {
      [stringParameter retain];
      [value release]; //6
      value = stringParameter; // 7
    }

    I don't think the burden of properties is any greater.
    And in the case of 64-bit, you don't have to worry about the actual
    instance variable at all.  Thus you would simply have:

    @interface MyClass : NSObject {
    }
    @property(readonly, retain [, nonatomic]) NSString *value;
    @end
    ...
    @synthesize value;

    ... etc.

    mmalc
  • On Nov 1, 2007, at 3:57 PM, Karl Goiser wrote:

    > <interface file>
    > @interface MyClass : NSObject {
    > NSString *value;
    > }
    > - (NSString *) value;
    > @end
    >
    > <implementation file>
    > @implementation MyClass
    >
    > - (NSString *) value {return value};
    >
    > - (void) setValue: (NSString *) stringParameter {
    > [stringParameter retain];
    > [value release];
    > value = stringParameter;
    > }
    >
    > @end
    >
    Thinking about this a little more, of course there's a further deficit
    in this example: in the general case it only really works if you make
    sure your implementation of the set method precedes all the other code
    that use it.  Otherwise, when you use a property name such as
    firstName (and hence have setFirstName:, which the compiler doesn't
    know about -- contrast setValue:) you'll get compiler warnings...

    So typically you still have to declare the set accessor somewhere...

    mmalc
  • On Nov 1, 2007, at 6:07 AM, Karl Goiser wrote:

    > Along these lines, I am looking for advise on how to implement a
    > pattern that I am sure many people use: having a private setter and
    > a public getter.  Before properties, I'd implement the two methods
    > in the implementation part and only declare the getter in the
    > interface part.  But now, in the 2.0 world, how can I leverage the
    > magic of synthesis to implement such a pattern?

    This is what I do.  I follow this general pattern in all of my coding,
    and it really helps keep "internals" isolated from the public
    interface the rest of the code should know about, while also helping
    out my unit tests (since they do test the internals).

    Hope this helps!

      -- Chris

    // Foo.h - public class declaration for Foo

    #import <Foundation/Foundation.h>

    @interface Foo : NSObject {
    @private
      id _selectedObject;
    }

    // selectedObject changes based on some user action.
    @property(readonly, retain) selectedObject;
    @end

    // Foo_Internal.h - internal class declaration for Foo
    // Only used by Foo.m and the unit tests that specify Foo's behavior

    #import "Foo.h"

    // this is an Objective-C 2.0 "class extensions"
    @interface Foo ()

    // a property can be promoted from readonly to readwrite in a class
    extension
    @property(readwrite, retain) selectedObject;
    @end

    // Foo.m - Foo's implementation

    #import "Foo_Internal.h"

    @implementation Foo

    // generates both -selectedObject and -setSelectedObject: thanks to
    the second @property
    @synthesize selectedObject = _selectedObject;

    - (void)dealloc {
        self.selectedObject = nil;

        [super dealloc];
    }

    @end
  • Hi mmalc,

    Ok, thanks for that!  That seems reasonable.

    So, would you recommend doing the following?

    <interface file>
    @interface MyClass : NSObject {
        NSString *name;
    }
    @property(readonly, retain, nonatomic) NSString * name;
    @end

    <implementation file>
    @interface MyClass ()
    @property(readwrite, retain, nonatomic) NSString * name;
    @end

    @implementation MyClass
    @synthesize name;

    @end

    Looking a bit further, there are more combinations that are possible
    (and useful too!):

    - Completely private setters and getters
    I guess you would only put the @property in the class extension in
    the .m file.

    - Only a private setter, but direct getters.
    What if I don't want to use a getter to access an instance variable
    that I know will only be accessed from within the class, but do want
    to have a synthesised setter?

    Thanks!

    Karl

    On 02/11/2007, at 11:34 AM, mmalc crawford wrote:

    >
    > On Nov 1, 2007, at 3:57 PM, Karl Goiser wrote:
    >
    >> So, let's make a comparison using class extensions (this seems to
    >> me to be the most applicable because it allows the compiler to do
    >> more checking which is good):
    >> [...]
    >> If so, this hardly seems like an advantage.  Sure, the number of
    >> lines has decreased, but that is mostly in terms of white space,
    >> and only marginally - and traded off with hiding the implementation
    >> of the actual methods.
    >>
    > It may not appear much of an advantage for one property, however if
    > you spread this over numerous properties the effect is more
    > noticeable.  Particularly when you have properties that are publicly
    > declared as readwrite so you don't have to do the category dance.
    > The effect is especially noticeable for Core Data (see <http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles
    /cdAccessorMethods.html
    > >).
    >
    > There are two additional considerations:
    >
    > (a) You have incorrectly specified your property; given the
    > implementation you seem to want, it should be:
    >
    > @property(readonly, retain, nonatomic) NSString *value;
    >
    > By default properties are atomic, so you're actually "not seeing"
    > considerably more code than you first showed.
    >
    > (b) Consumers of your class now see, instead of:
    >
    > @interface MyClass : NSObject {
    > NSString *value;
    > }
    > - (NSString *) value;
    > @end
    >
    >
    > this:
    >
    > @interface MyClass : NSObject {
    > NSString *value;
    > }
    > @property(readonly, retain [, nonatomic]) NSString *value;
    > @end
    >
    >
    > This makes your intent for the property much more clear.
    >
    >
    >> Also, there were three places where I have to worry about the
    >> instance variable (in the class declaration, getter method
    >> declaration and method implementations), now there are four (in the
    >> class declaration, getter method declaration, class extension and
    >> synthesize statement). which won't make maintenance any easier.
    >>
    > It's not clear exactly what you mean by "worrying about the instance
    > variable".
    >
    > One of the attractions of properties is that they're not tied to an
    > instance variable -- you can rename either the ivar or the property
    > and "redirect" using the synthesize directive 'ivar='.
    >
    > Moreover, in the traditional case you certainly have more than three
    > places where the property/ivar name is required:
    >
    > @interface MyClass : NSObject {
    > NSString *value; // 1
    > }
    > - (NSString *) value; // 2
    > @end
    >
    > <implementation file>
    > @implementation MyClass
    >
    > - (NSString *) value /* 3 */ {return value /* 4 */};
    >
    > - (void) setValue: /* 5 */ (NSString *) stringParameter {
    > [stringParameter retain];
    > [value release]; //6
    > value = stringParameter; // 7
    > }
    >
    >
    > I don't think the burden of properties is any greater.
    > And in the case of 64-bit, you don't have to worry about the actual
    > instance variable at all.  Thus you would simply have:
    >
    > @interface MyClass : NSObject {
    > }
    > @property(readonly, retain [, nonatomic]) NSString *value;
    > @end
    > ...
    > @synthesize value;
    >
    > ... etc.
    >
    >
    > mmalc
  • On Nov 1, 2007, at 11:30 PM, Karl Goiser wrote:

    > So, would you recommend doing the following?
    >
    I'd rather not go so far as to making recommendations -- your
    implementation looks fine to me, but see also Chris' reply.  Different
    people have different styles and preferences...

    mmalc
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today