Actually, how about Objective C instead?
It's got explicit interface and
implementation sections!
// ANumber.h
#import
<Cocoa/Cocoa.h>
@interface ANumber: NSObject
{
@private
NSNumber* _theNumber;
};
-
(NSNumber*)number;
- (void)setNumber:(NSNumber*)number;
-
(ANumber*)add:(ANumber*)toNumber;
@end
// ANumber.m
#import
"ANumber.h"
@implementation ANumber
- (NSNumber*)number
{
return _theNumber;
}
-
(void)setNumber:(NSNumber*)number {
[number
retain];
[_theNumber
release];
_theNumber=number;
}
-
(ANumber*)add:(ANumber*)toNumber {
int a=[_theNumber
integerValue];
int b=[[toNumber number]
integerValue];
int
r=a+b;
ANumber *newNumber=[[[ANumber alloc] init]
autorelease];
[newNumber setNumber:[NSNumber
numberWithInteger:r]];
return
newNumber;
}
@end
Obviously that's quite degenerate and
pointless. But what's going on is, the "@interface...@end" block is the
information needed to "declare" our new class, "ANumber". It also establishes
that the parent class is the "NSObject" intrinsic class--like Java and
SmallTalk, Objective C uses a "tree" object model, every class must have
"NSObject" as its ultimate ancestor class.
(This means, all methods
implemented by NSObject are available to ANumber objects as well, they don't
need to be re-declared or defined. This is one of the powers of OO programming,
and lets you develop classes that can deal with arbitrary objects. Re-using
known-working code means avoiding known pitfalls.)
This new class really
just provides a (pointless) interface to another class, called an NSNumber.
(NSNumber is actually a bit of an odd duck in Cocoa, but that isn't important
here--what is important is, it can hold numbers. Java has the same sort of
class wrappers for C-style integer and floating point types.)
The only new
methods defined in the interface are a "getter", to fetch the stored number, a
"setter", to replace the stored number with a new one, and an "add" method to
add the integer values of two numbers together and return a new one containing
the result.
The "@implementation" section contains the actual code to make
this work. I've actually avoided some of the features of Objective C and
Apple's current runtime to increase the amount of implementation code
required--no declared properties, no automatic reference counting, and so on.
This results in some boilerplate idioms showing up all the time--there is no
need to write getter and setter methods by hand, for example, there's a way to
tell the compiler to do it. (And for 2.0, to even create the instance variable
to store the data.)
Since this is a simple class, the methods are also
simple: the getter just returns the stored object. The setter does a retain and
release method invocation, which are boilerplate needed to manage memory.
(They're also an example of methods provided by NSObject, so we don't have to
bother writing them.)
The one method that actually does something is add:;
it gets the integer value of the current object from the NSNumber. Then it gets
the integer value of the toNumber object argument (which is provided by the
caller). It actually has to first get the underlying NSNumber, then it gets the
integer from that. It adds the two integers together in good old-fashioned C.
Then it creates a new ANumber instance, with some more boilerplate for memory
management. It then sets the number of that new instance to a newly-created
NSNumber that contains the result of the addition.
Now, there is one thing
in all this which would inspire debate about its presence in an API: the
instance variables. The compiler needs to know about instance variables any
time it might need to know the size of the resulting object--but the programmer
does not. As a result, the instance variables in many languages are present in
the interface declaration--even though, as is the case here, they are not
allowed to be accessed from outside classes.
So, if we look at the above
example from the perspective of the parts of the API necessary to create a
compatible implementation, the instance variables marked with "@private" are
actually not necessary--they are only accessible to the class specifying them.
That means the only code that needs to know their type or name is the code in
the implementation of that class.
All other instance variables may be
accessed from outside the instant class--either in a subclass (protected) or
from anywhere (public). Consequently, the name and type of those variables is
critical and cannot change in a compatible implementation.
But, like I said,
there's technical reasons why the compiler may need to know about all instance
variables all the time; depending on the compiler, the order, name, and type of
all instance variables can affect the in-memory data layout. And the in-memory
layout is crucial for binary compatibility. And without binary compatibility,
you wouldn't be able to just run an existing program with your replacement
class--all existing programs that use it would have to be re-compiled from
source code. (Some languages make this harder than others; Java and Objective C
are fairly flexible. C++ can be torture to keep binary compatibility and don't
know details of your particular compiler.)
[ Reply to This | Parent | # ]
|