Richard Frith-Macdonald wrote:
On 16 Oct 2006, at 04:13, Sheldon Gill wrote:
Hi Richard,
You've made some recent changes to base with the idea of making
private functions in base more obviously private and less accessible.
Yes ... as obviously private as possible.
It seems to be that there is really only one goal with these changes:
applications/tools shouldn't be using private functions in base
Is there any other objective that I'm missing?
Well, that's the main tactical objective ... the strategic objective is
to improve maintainability ... so centralisation and clarification
internally is almost as much of a goal as simply trying to ensure that
external apps/tools don't use private stuff.
Okay.
If this is the case, I think the approach being taken here isn't the
one which we should be pursuing.
The original situation is we have functions like these:
NSString *GSLastError(int);
BOOL GSEnvironmentFlag( const char *, BOOL );
which make these functions seem like GNUstep API additions but really
they are private.
What has been done is create an "artificial" object
@interface _GSPrivate : NSObject
+ (NSString*) error;
@end
@interface _GSPrivate (ProcessInfo)
+ (BOOL) environmentFlag: (const char *)name defaultValue: (BOOL)def;
@end
Yes, the idea is to collect everything together as much as possible,
making it easier to find these things and making it clear that the
various mechanisms are used internally.
Now I say artificial because it doesn't conform to an object design.
There never is an actual instantiation, for example, so you're always
sending messages to the class. There are many other things which make
this not really an object.
This is a work in progress ... I'm not sure yet whether it would be good
to have an instance and use instance methods rather than just a class
and use class methods. The main reason for using a class is to use
language features to support encapsulation and maintainability rather
than depending solely on conventions.
Well, you actually are relying on conventions anyway. You've called the class
_GSPrivate using the underscore convention to indicate privacy.
Also, these are private function calls within the library. Encapsulation
doesn't really apply here.
Doing this adds many more bytes to the library.
It also makes these method lookups rather than function calls so they
are slower.
True, but these are very minor overheads and I think clarity and
maintainability come first before looking at optimisation (obviously we
can optimise by caching method IMPs or by using a struct as a dispatch
table rather than using a class).
I'm quite aware of how we can optimise method calls but this isn't really
optimisation.
I also find this inconsistent with your previous statements about avoiding
'bloat', as you put it. Surely more size and less speed for no functional
changes is the very essence of 'bloat'?
I don't agree that these changes make anything more maintainable or easier than
simply decorating the function calls with an underscore in the conventional way.
So we've added an artificial/strange object, increased the library
size and slowed down those function calls all in an effort to prevent
applications using our private functions. Is this right?
As you can tell from my answers above, it's only partially right.
Now its long been idomatic to use the underscore to mark private
symbols. In fact, this is precisely what you've done with the class name.
Yes, I've tried to use every signal I could think of ... the leading
underscore, the word 'Private' the exclusion from any external headers
and reduced linker symbols, and the inclusion of comments.
Further, I think this makes navigating the source harder. Quick, tell
me without searching where you're going to find the implementation for
the above two functions?
I'm very surprised at this comment ... since a big part of the intent is
to make navigating the source *easier* and I believe this is achieved.
I certainly think it's not obvious where the old functions were ... but
the new methods are clear since the category names tell you where the
individual method implementations in each group are, the declarations
are all in a single place, and you can find all the private methods
implementations easily using a search for @implementation _GSPrivate.
Making sure all declarations are in GSPrivate.h is good but a matter of
programmer discipline and has no bearing on the function call vs class method
issue.
> That's a big improvement over the older code.
Conventional layout has private functions near the top of the source file, just
after header includes. They aren't that hard to find. Especially if you keep to
convention with the underscores.
Sure, the category names help you find where the particular function is
located. I've an equivalent way which adds precisely 0 bytes to the libnrary
and makes no impact on the runtime:
// f