Re: Categories and adding instance variables
Re: Categories and adding instance variables
- Subject: Re: Categories and adding instance variables
- From: "Dennis C. De Mars" <email@hidden>
- Date: Sun, 1 Aug 2004 12:59:07 -0700
On Aug 1, 2004, at 10:27 AM, Kay Roepke wrote:
Yes, I know it doesn't work. I know about subclassing.
Now that I said that ;-), here's my question:
Is there a technical reason that you cannot add instance variables to
class using categories?
Or is it just convenient for the runtime?
The experts can address this more thoroughly, but I believe it is
because there may be code that did not see the category, possibly
compiled before you defined the category, and that code will allocate
memory for the instance variables without allocating space for your new
instance variable. Initialization is an issue also.
It is possible, in principle, for an OO language to allow instance
variables to be added at runtime. Dylan can do this, possibly some of
the OO flavors of Lisp (I don't know about Smalltalk). But you
potentially lose some efficiency in accessing the instance variables in
order to allow this possibility, and although Objective C is pretty
dynamic, it does make some concessions to retain the core efficiency of
C.
I have this generated class, lets call it Lexer. It inherits from
Scanner, which is part of an existing framework.
While generating Lexer's source code, I also end up with a enum
containing the tokens to be produced by Lexer.
Of course I could simply add this enum to the Lexer class and be done
with it, but guess what:
I have a Parser class which wants the very same enum, in order to know
which tokens it must
handle. Obviously, I don't want that enum to be duplicated in my
(albeit generated) code for
hygenical reasons.
In the C++ version this is done via multiple inheritance and in Java
one could simply make an
interface for this. ObjC on the other hand craps out.
I can't quite figure out from this description what the problem is.
Does Parser also derive from scanner, so you want to put this enum in
Scanner so both Lexer and Parser will share it?
Also, if you think you can solve this in Java with an interface, why
can't the same solution be applied in Obj C with a protocol? Obj C
protocols are basically the same thing as Java interfaces, aren't they?
You can't declare instance variables in interfaces, so I'm not quite
sure how you would solve the problem in Java.
Does anyone have a suggestion how this could be cleanly done?
One thing I came up with would be to use a static dictionary and get
the tokens from there, but that
seems like overkill to me.
The static dictionary is pretty much the standard thing to do when you
want to add "instance variables" to a category. You create a private
static dictionary associated with that class, and arrange to have each
instance enter itself as a key of the dictionary, with the value being
the instance variable (or variables) you want to add. It is clearly
less efficient than having a real instance variable and takes some
effort to set up. so it is a matter of how badly you need the instance
variable.
Personally, I would just add the enum to each subclass. (I've become
more cavalier about issues of type safety and type identity since I've
been using Objective C). If you want to put a more formal veneer over
this, you could do the following:
1) Add a category to the Scanner class that contains setter and getter
methods for the enum. Implement these in the category by having them
print an error message or raise an exception or something (i.e. it is
not legal to use the methods directly, they must be overridden).
2) Add the enum instance variables to the subclasses and override the
accessor methods to use the variable.
3) Only use the accessor methods to access the variable.
This allows you, for instance, to access the enum on Scanner* pointers
without knowing whether they are Lexer or Parser (and without the
compiler complaining).
A variation would be to define a protocol instead of category with
these accessor methods, and then have Lexer and Parser inherit from
this protocol as well as Scanner. Again, you'd have to implement the
methods separately in each class. Then you could refer to objects of
either type with pointer of type id<TokenProtocolName> (or whatever you
decide to call the protocol). This may be similar to the solution you
were thinking of in Java.
- Dennis D.
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.