Jacob Carlborg wrote:
Walter Bright wrote:
Setting aside the technical issues for the moment, isn't that exactly what inheritance is supposed to be good for?

A few times I've had the need for this, I've always been able to solve the problem but it would have been easier with support for this. But to be honest I don't remember these problems right now, so perhaps it's not that important.

I think it has less to do with how often its needed and more to do with how much more elegant the solution will be.

Just because I want to supply one example of where it's even appropriate to use a category-pattern to extend a class' function table without extending the class into a new type, I'll just spit out something I just wrote in Objective-C.

===== Short Story =====

I needed to search through a String (NSString) specifically to know whether a character at a specific index is any one of a given set of characters. Rather than subclass NSString, I decided to make a category:

== NSString.h ==

#import <Cocoa/Cocoa.h>

@interface NSString (ACSExtensions)

- (bool)characterAtIndex:(int)idx
                 isOneOf:(NSString*)characters;

@end

== NSString.m ==

#import "NSString.h"

@implementation NSString (ACSExtensions)

- (bool)characterAtIndex:(int)idx
                 isOneOf:(NSString*)characters {
    unichar *arr = malloc([characters length]*sizeof(unichar));
    [characters getCharacters:arr];

    char ch = [self characterAtIndex:idx];

    int lp=([characters length]-1)/10,rm=[characters length]%10;

    switch(rm){
        case 0: do {
                    if(ch==arr[lp*10+9]) return YES;
        case 9:     if(ch==arr[lp*10+8]) return YES;
        case 8:     if(ch==arr[lp*10+7]) return YES;
        case 7:     if(ch==arr[lp*10+6]) return YES;
        case 6:     if(ch==arr[lp*10+5]) return YES;
        case 5:     if(ch==arr[lp*10+4]) return YES;
        case 4:     if(ch==arr[lp*10+3]) return YES;
        case 3:     if(ch==arr[lp*10+2]) return YES;
        case 2:     if(ch==arr[lp*10+1]) return YES;
        case 1:     if(ch==arr[lp*10  ]) return YES;
                } while(0<--lp);
            break;
    }
    return NO;
}

@end

== end of file ==

As you can see, I added important functionality to the class NSString without going through all the trouble to make a new class and type cast between NSString and MyDerivedString all over the place. It's more transparent, and it's far better than a global function, or placing this kind of code into an unrelated class, or worse yet, a "kitchen-sink" class.

===== Special Extended Explanation =====

Since some of you may be in a hurry, this part is kind of secondary.

The purpose for adding functionality to NSString is because I'm trying my hand at writing my own programming language (interpreted, but a language nonetheless). It's very rudimentary in syntax and capability, and it's only designed to script the effects of cards in a card game called Arcomage. I later extended some of its capabilities to make it suitable for AI scripting as well.

Mind you I haven't implemented the language yet. I just wrote a specification that I'm now focusing on implementing. If you want to have a laugh or maybe see how badly I've been spoiled by D, you can read through the specsheet here:

http://www.fsdev.net/~cmiller/pdf/acs_spec.pdf

And I talk a bit on how I plan to implement such a system over here:

http://www.fsdev.net/~cmiller/a/20090126_acsadv.html

Anyways, the specific and immediate purpose for writing such functionality into NSString was so that I could - as I was parsing through the source script - quickly and easily check to see if characters are certain control characters. For instance, when searching for an integer, the first task is to read to the first numeric character. Two options: read to the first numeric character, or (more resistant to malformed code) read through all the whitespace characters and then if the next character isn't numeric, you have problems. What whitespace characters are there?

\t
\r
\n
(space)

Unfortunately, they aren't in sequential order in the ASCII table, so it's not as simple as determining if char c is numeric:

if ( c > '0' && c < '9' ) // c is numeric

Therefore, it's useful for searching quickly, without getting into the potential mess that could be a regular expression search. Well, I'm sure for a lot of people it'd be shorter and more concise, but my relative ineptitude with regular expressions would make it far more bothersome for me. Am I here to write a language, or to teach myself regular expressions?





Anyways, I'm really happy with the ensuing discussion about this - this is the entire reason why I decided to compare the two languages: in hopes of bringing up potentially useful features and getting people to think about them.

Reply via email to