Re: OT: Categories and alloc.
Re: OT: Categories and alloc.
- Subject: Re: OT: Categories and alloc.
- From: Jorge Mederos <email@hidden>
- Date: Tue, 09 Jul 2002 03:32:19 +0200
- Organization: qarana...
This is sort of off topic, but it's a topic that applies to Java and
Objective C developers.
The goal question: How do you allocate from a protocol/interface?
The problem: Objective C and Java both allow protocols/interfaces to
specify what you can do with an object. Anything that is written to an
interface specification will work with any object that implements that
specification, and can work with any class that does so.
But how does it get something of that interface type?
[Snip ...]
But it has occurred to me that even if you had all that, you'd still have
a problem. Allocation.
Very concretely: Lets say you've got a program that uses the HTMLEngine
interface. You want to use an HTMLEngine.
Microsoft makes one. Netscape makes one. Opera makes one. Omni makes one.
Lynx makes one. [Lets live in a fantasy for a second. Assume that the
HTMLEngine API is a W3 standard, and everyone of those 5 has an engine that
implements that API, as well as the output display that uses that engine.]
How does the user tell you which one to use? After all, none of them
will display the same way -- one might strive to make the output exactly
as the web page designer wants it, another might allow the end user more
control over how tags translate into output, a third might give you better
control over what graphics and cookies are fetched; they might all have
different caching strategies, or ordering to fetch and display the different
parts of a web page, etc.
Somewhere, someone has to write
myNewObject = [[ <something> alloc] init]
Right now, <something> has to be either a class, or a function that
returns a class.
How do you write something like this so that it's extendable, and
works?
[Snip ...]
I'm looking for ideas. I haven't even begun looking at the security issues
(what if a package on the system doesn't really do what it claims, or does
do what it claims, but also copies the data for someone else [no big brother
concerns here, nope, nada]).
Hi.
So you're going forward trying to use protocols in each place where a class
could be used... not as easy at it seems to be.
There are two possible scenarios here for a protocol/interface X variable
use. Let's say that we have the following variable definition:
id<X> x;
where X is some protocol, like the HTMLEngine one of your post. To be
useful we need to assign x to some HTML engine implementation class, but to
put things more interesting you added the restriction that you don't want
to know that implementation class.
Case 1) An object that adopts the X interface already exists and it's
available. In this case, no special handling needs to be done for that
object allocation (it was done earlier at some unknown point). But a
problem closely related with the one you're facing might appear if you want
to create a new object of the same _class_ using only the interface X in
your main code.
A solution for this case is simple: add a creator function to the interface
X, and let any class that adopts X to instantiate itself. Something in
spirit similar to this pseudocode:
@protocol X
{
// tons of methods...
id<X> newX;
}
// ...
@implementation XClass1 : NSObject <X>
{
// ...
id<X> newX
{
return (id<X>) [[XClass1 alloc] init];
}
}
// ...
@implementation XClass2 : NSObject <X>
{
// ...
id<X> newX
{
return (id<X>) [[XClass2 alloc] init];
}
}
This way, to request a new object following the protocol X without knowing
its real class you just need to issue:
id<X> myx = [x newX];
Of course, the big problem here is: how I could obtain the first x object?
which lead us to the second case:
Case 2) We want an object of an unknown class, i.e., "an exemplar object of
protocol X" but we explicitly don't want to know to which class it belongs
to. If we don't have an already created x object following the X protocol
then we're suffering the "sorry, not having enough information to deal
with" problem.
Somewhere, at some place, a first exemplar must be created following the X
protocol, and there should be a way to access to it. If we don't want to
write down a class reference that adopts the X protocol in our main code
(which is the obvious way to request a new X exemplar) then we should
know at least the code symbol of an X exemplar, regardtheless its class.
For example:
extern id<X> XExemplar;
In this case we might ignore the process that sets the first X exemplar up.
We want this process to be as "external" to our main code as we could, so
that we wouldn't be hard-wiring dependencies to it as far as we could.
That "external" process might be sorted out with dynamic load as you were
leading to think. At loading time a +initialize method of XClass1 or
XClass2 could be used to set up an X object reference associed with the
known symbol XExemplar. Note that in this case the program that loads up
the class adopting X must know the class name to load, but this code must
be kept unrelated with our main code.
Another possibility for that process might be sorted out by a configuration
file, specifying the class name (either to instantiate an item or to load a
class that instantiate an item), again issued by an unrelated chunck of
code separated from our main code.
Now, the important part: Whatever the way might be, we are ending up with
the _deep need_ of having an X protocol exemplar object created somehow.
What's funny about it is that we are trying to work more like a
prototype-based language rather than like a class-based one, using features
of a class-based language. We want objects following a given protocol,
whatever the class is, but we need some exemplar object to start working
with to avoid the lack of information problem we discussed earlier. We
don't want to use the class name in our main code. Thus, if we don't have
any exemplar to play with, we need to create one using some "external
initialization procedure". Well, it happens that prototype-based languages
set up automatically this kind of procedure, like class-based ones set up a
way to instantiate objects from a given class name or class object.
Protocols tend to work better with prototype-based object semantics than
what they do with class-based ones [1].
PD: The same thoughts could be applied to Java as well, as the inteface
construct is quite similar to the Obj-C one (and both are class based
languages).
Hope this helps.
Jorge.
-------------------------
[1] I do NOT want to start here any kind of language wars by any means.
Just pointing out that while working hard with protocols, we should keep in
mind prototype-like object semantics, not only class-based object
semantics. It could allow us to set up procedures to deal with issues like
this one.
_______________________________________________
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.