Re: case-insensitive strings
Re: case-insensitive strings
- Subject: Re: case-insensitive strings
- From: Ali Ozer <email@hidden>
- Date: Thu, 10 Oct 2002 10:41:21 -0700
>
I didn't get any useful answers. The thing that amazes me is that no
>
one
>
chimed in with outraged cries of how the NSString model is inadequate.
>
Doesn't this bother anyone else out there besides me? This thing is an
>
object; the whole point of having an object is that the knowledge of
>
how to
>
do stuff, such as decide whether two instance are "equal", should be
>
made
>
to reside in the object. The idea that you can't flip case sensitivity
>
on
>
or off for an individual string instance is just nutty to me. The idea
>
of
>
having to do case-insensitive comparison "from the outside" makes me
>
barf.
>
The idea of having to do it by making both comparands uppercase makes
>
me
>
barf twice. I do it, but I also do a lot of barfing. m.
What you're thinking NSString should be able to do implies adding a new
attribute (property) to NSString --- and that is not a good idea for a
low-level value object such as NSString, as it invalidates all sorts of
assumptions made by existing code. NSString has "two" attributes
(corresponding to the two primitive methods): an ordered list of
characters, and the number of characters. If
"compares-case-insensitively" is now added as a new attribute to
NSString, one would assume that it's preserved across archiving,
copying, etc. Otherwise if your dictionary was saved to a plist and
read back in, your strings would no longer function correctly. However,
if we did add this as an attribute, then any code which copied a string
using the well-documented primitives would now do the job only halfway.
Usually overriding hash and isEqual: is a way to get an object to
change its behavior in cases like this. (hash and isEqual: are the
methods used by NSDictionary to manage the keys.) However, because hash
and isEqual: are general-purpose, and called by different and
potentially unrelated subsystems, rather than having them change based
on how you want to use them, they should be implemented in one way
which is appropriate for the object. In the case of NSString, these
methods have a deterministic behavior based on the NSString primitives,
and you don't want to change that behavior based on another setting
(compares-case-insensitively).
Now, you can still achieve the goal of having isEqual: and hash do want
you want, by either creating a subclass of NSString or an object which
holds an NSString; then you'd also have to make sure these custom
objects were used to store your strings in the dictionary and any
probes into the dictionary. The subclass route is less desirable,
because, like described above, it ends up changing the basic definition
of an NSString; that is, you have something which claims to be an
NSString, but it has more attributes.
Another approach is to use custom isEqual: and hash methods or
functions tuned for your purpose. Something like
isCaseInsensitiveEqual: and caseInsensitiveHash. NSDictionary does not
let you specify what methods to use though, so you'd probably have to
use NSMapTable, and specify your custom isEqual and hash methods.
Basically use the predefined NSObjectMapKeyCallBacks and specify your
own hash() and isEqual() callbacks, something like:
BOOL caseInsensitiveIsEqual(NSMapTable *table, const void *s1, const
void *s2) {
return ([(id)s1 compare:(id)s2
options:NSCaseInsensitiveSearch|NSLiteralSearch] == NSOrderedSame) ?
YES : NO
}
unsigned caseInsensitiveHash(NSMapTable *table, const void *s) {
return [[(id)s1 lowercaseString] hash];
}
NSMapTableKeyCallBacks keyCB = NSObjectMapKeyCallBacks;
keyCB.hash = caseInsensitiveHash;
keyCB.isEqual = caseInsensitiveIsEqual;
NSMapTable *table = NSCreateMapTable(keyCB, NSObjectMapValueCallBacks,
0);
Or you can use a CFDictionary, which provides similar level of
customization.
Unfortunately, neither NSMapTable or CFDictionary provide the one
method you used as an example: allKeysForObject:. If you really want
to use an NSDictionary, then doing a custom subclass of NSObject which
holds an NSString is probably the best option. All you need is to
implement isEqual: and hash. Downside is having to create these
"wrapper" instances for insertion and probing.
Ali
_______________________________________________
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.