mutability?
-
hello,
we actually need to be able to distinguish
mutable versus immutable instances of class clusters
such as NSString, NSArray, NSDictionary etc.
it does however turn out that all NSStrings
are CFStrings and that they say yes if
asked [isKindOfClass:[NSMutableString class]].
on the other hand if you create an immutable
NSString and send a mutating message
you get an exception that shows that this
string knows about its immutability.
but I was unable to find any API that
would retreive this mutability information...
any help?
guenther
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On 07.07.2004, at 16:13, Guenther Fuerthaller wrote:
> it does however turn out that all NSStrings
> are CFStrings and that they say yes if
> asked [isKindOfClass:[NSMutableString class]].
Well, I had the same problem with dictionaries, I assume a similiar
"solution" exists for strings.
Apparently there is _no_ public API for finding that out, which I
personally consider a major bug. My current workaround for dictionaries
looks like:
bool _CFDictionaryIsMutable(CFDictionaryRef dict);
if ([object isKindOfClass:NSCFDictionaryClass] &&
!_CFDictionaryIsMutable((CFDictionaryRef)object))
But someone said that _CFDictionaryIsMutable is deprecated and not
unlikely to be removed in upcoming OSX versions :-|
So apparently the only portable "solution" is to wrap all mutations in
exception handlers ...
regards,
Helge
--
http://docs.opengroupware.org/Members/helge
OpenGroupware.org
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
The question in these cases is why you need to know that an object you
didn't create is mutable or not... (If you created it, presumably you
know, and you can remember the state.)
I'm asking this because some decisions that are made based on the
mutability of an object you don't own can be dangerous, as you don't
know whether the object is actually part of some other graph of
objects.
Ali
Begin forwarded message:
> From: Helge Hess <helge.hess...>_______________________________________________
> Date: July 7, 2004 11:02:41 PDT
> To: Guenther Fuerthaller <Guenther.Fuerthaller...>
> Cc: <macosx-dev...>
> Subject: Re: mutability?
>
> On 07.07.2004, at 16:13, Guenther Fuerthaller wrote:
>> it does however turn out that all NSStrings
>> are CFStrings and that they say yes if
>> asked [isKindOfClass:[NSMutableString class]].
>
> Well, I had the same problem with dictionaries, I assume a similiar
> "solution" exists for strings.
>
> Apparently there is _no_ public API for finding that out, which I
> personally consider a major bug. My current workaround for
> dictionaries looks like:
>
> bool _CFDictionaryIsMutable(CFDictionaryRef dict);
>
> if ([object isKindOfClass:NSCFDictionaryClass] &&
> !_CFDictionaryIsMutable((CFDictionaryRef)object))
>
> But someone said that _CFDictionaryIsMutable is deprecated and not
> unlikely to be removed in upcoming OSX versions :-|
>
> So apparently the only portable "solution" is to wrap all mutations in
> exception handlers ...
>
> regards,
> Helge
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On 7 Jul 2004, at 19:02, Helge Hess wrote:
> Apparently there is _no_ public API for finding that out, which I
> personally consider a major bug. My current workaround for
> dictionaries looks like:
>
> bool _CFDictionaryIsMutable(CFDictionaryRef dict);
>
> if ([object isKindOfClass:NSCFDictionaryClass] &&
> !_CFDictionaryIsMutable((CFDictionaryRef)object))
>
> But someone said that _CFDictionaryIsMutable is deprecated and not
> unlikely to be removed in upcoming OSX versions :-|
bool _CFArrayIsMutable(CFArrayRef array);
bool _CFDictionaryIsMutable(CFDictionaryRef dict);
bool _CFSetIsMutable(CFSetRef set);
bool _CFCharacterSetIsMutable(CFCharacterSetRef cset);
Boolean __CFStringIsMutable(CFStringRef str);
I don't see any reason why they would be deprecated, although they only
seem to be used internally within Foundation. But yes, of course it is
entirely possible that they won't exist in future releases.
It's generally considered bad practice to actually test for mutability
- you should know whether or not it's mutable from the selector that
you obtained it from (if you did a mutableCopy, or you did an
NSMutable* init..., or whatever). If you mutate something that, while
mutable, isn't expected to be mutated, you could have problems.
-- Finlay
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
appreciate your participation, hello!
> I'm asking this because some decisions that are made based on the
> mutability of an object you don't own can be dangerous...
nobody here intends to use such a mutability check
to mutate a foreign object, not with me!
to give a short illustration of the background,
consider a convenient type mapping:
name <--> NS(Immutable)String
string <--> NSMutableString
where the types name/string originate
from a ps/pdf world.
another operation that uses mutability
is what I called -(id)deepMutabilityPreservingCopy.
another operation that uses mutability
is an object archiver that may use immutability
as sufficient to unify instances via isEqual.
> (If you created it, presumably you know, and you can remember the state.)sometimes, but in general this would require
a wrapping object/struct to store that state.
I hope you can aggree on my scenarios that
there might be some reasonable use cases
for the mutability status of an object.
regards
guenther
Ali Ozer <aozer...>
07.07.2004 20:19
To
Guenther Fuerthaller <Guenther.Fuerthaller...>
cc
Ali Ozer <aozer...>, <macosx-dev...>
Subject
Re: mutability?
The question in these cases is why you need to know that an object you
didn't create is mutable or not... (If you created it, presumably you
know, and you can remember the state.)
I'm asking this because some decisions that are made based on the
mutability of an object you don't own can be dangerous, as you don't
know whether the object is actually part of some other graph of
objects.
Ali
Begin forwarded message:
> From: Helge Hess <helge.hess...>
> Date: July 7, 2004 11:02:41 PDT
> To: Guenther Fuerthaller <Guenther.Fuerthaller...>
> Cc: <macosx-dev...>
> Subject: Re: mutability?
>
> On 07.07.2004, at 16:13, Guenther Fuerthaller wrote:
>> it does however turn out that all NSStrings
>> are CFStrings and that they say yes if
>> asked [isKindOfClass:[NSMutableString class]].
>
> Well, I had the same problem with dictionaries, I assume a similiar
> "solution" exists for strings.
>
> Apparently there is _no_ public API for finding that out, which I
> personally consider a major bug. My current workaround for
> dictionaries looks like:
>
> bool _CFDictionaryIsMutable(CFDictionaryRef dict);
>
> if ([object isKindOfClass:NSCFDictionaryClass] &&
> !_CFDictionaryIsMutable((CFDictionaryRef)object))
>
> But someone said that _CFDictionaryIsMutable is deprecated and not
> unlikely to be removed in upcoming OSX versions :-|
>
> So apparently the only portable "solution" is to wrap all mutations in
> exception handlers ...
>
> regards,
> Helge
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Hello,
Actually the problem is not you the case, but that isKindOfClass and
isMemberOfClass don't do the right thing for the string classes (and
probably other toll-free bridged classes). From the user's perspective,
you would expect these methods (a contract) to work regardless of
whether they are toll-bridged or not. This is something that should be
fixed.
/a
On Jul 8, 2004, at 4:38 AM, Guenther Fuerthaller wrote:
> I hope you can aggree on my scenarios that
> there might be some reasonable use cases
> for the mutability status of an object.
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On 07.07.2004, at 20:19, Ali Ozer wrote:
> The question in these cases is why you need to know that an object you
> didn't create is mutable or not... (If you created it, presumably you
> know, and you can remember the state.)
A somewhat weird question as this can be generalized as why reflection
and runtime instrospection is useful and necessary. Hopefully we don't
need to discuss this ;-)
All code which does Objective-C reflection to discover what messages
can be send fail on the mentioned Foundation classes (eg immutable
objects respond to setObject:forKey: which is IMHO clearly a design
mistake in the ObjC context).
I consider it somewhat obvious that you have reusable code that deals
with generic objects. And in a non-trivial application/framework you
almost never know how an object was constructed even if you have it
under control (IMHO construction should never be relevant for object
behaviour?!). After all thats one reason why reference counting / GC is
useful (passing an objects around).
> I'm asking this because some decisions that are made based on the
> mutability of an object you don't own can be dangerous
You don't need to "own" it, a client object which owns the object can
give the object to some other utility class which does some processing
on it. So its an intended and documented mutation on the object
triggered by the client.
I'm not talking about some accessor method which checks for mutability
to avoid creating a mutable copy (which clearly is a bug).
The point where we stumbled across this is actually
WOKeyPathAssociation which needs to know whether the bound object is
mutable or not (so whether it should try to push values into it or just
retrieve them). Actually WOAssociation even has a reflection methods
for that (-isValueConstant, -isValueSettable).
All sorts of bridges are in this category as well.
BTW: if Foundation is going to keep the mutable/immutable distinction,
I would actually prefer a general method -(BOOL)isImmutable in NSObject
(or some protocol implemented by the collections) -isKindOfClass: is
kind of a Javaish hack too.
Further, -respondsToSelector:@(setObject:forKey:) could return NO for
the NSCFDictionary (and maybe nil for -methodForSelector:) if the
object is created immutable to properly support Foundation reflection.
Greets,
Helge
--
http://docs.opengroupware.org/Members/helge
OpenGroupware.org
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
>
> BTW: if Foundation is going to keep the mutable/immutable distinction,
> I would actually prefer a general method -(BOOL)isImmutable in
> NSObject (or some protocol implemented by the collections)
> -isKindOfClass: is kind of a Javaish hack too.
Actually these methods predate Java by 10+ years (1988)
ObjC had:
-isKindOf:
-isKindOfClassNamed:
-isMemberOf:
-isMemberOfClassNamed:
-conformsTo:
+conformsTo:
+instancesRespondTo:
-methodFor:
+instanceMethodFor:
-descriptionForMethod:
+descriptionForInstanceMethod:
+class
-class
+superclass
-superclass
+name
The current methods were tweaked with <objc/Object.h> ceased to be the
root class and NSObject showed up in 1993 or there about.
[if you ask me, the introspection mechanism was pretty rich considering
that it was still the dark ages, (Pascal was still very prevalent and C
was only popular in UNIX) - I am not a SmallTalk developer, it is
possible that these things came from there.]
>
> Further, -respondsToSelector:@(setObject:forKey:) could return NO for
> the NSCFDictionary (and maybe nil for -methodForSelector:) if the
> object is created immutable to properly support Foundation reflection.
+ 100. The contract of NSObject needs to be supported regardless of the
implementation.
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Fuerthaller wrote:
[...]
> I hope you can aggree on my scenarios that
> there might be some reasonable use cases
> for the mutability status of an object.
Like you I think there are perfectly legitimate use cases where it
makes sense to determine at run-time whether a string is mutable,
especially in a dynamic language like Objective-C. Yes, this can be
misused and dangerous, but no more than the possibility of asking an
object about its class. And I hope no one is thinking about removing
this feature from Objective-C ;-)
I don't think that the right way to offer information about mutability
would be to add a public API. As you noted, the problem at hand comes
from the fact that, in the current implementation, non-mutable strings
are instances of a subclass of NSMutableString (how something like that
can pass design reviews and finds its way into the, otherwise
excellent, major framework of a major operating system will be a
subject of amazement for generations of developers). Just fix this
nonsense and the problem will disappear.
Best,
Philippe Mougin
F-Script: Interactive and scripting environment for Cocoa.
http://www.fscript.org
PS: I originally sent this e-mail to the wrong mailing list. Sorry,
unintended cross-posting.
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 8, 2004, at 11:40 AM, Philippe Mougin wrote:
> Fuerthaller wrote:
>
> [...]
>> I hope you can aggree on my scenarios that
>> there might be some reasonable use cases
>> for the mutability status of an object.
>
> Like you I think there are perfectly legitimate use cases where it
> makes sense to determine at run-time whether a string is mutable,
> especially in a dynamic language like Objective-C. Yes, this can be
> misused and dangerous, but no more than the possibility of asking an
> object about its class. And I hope no one is thinking about removing
> this feature from Objective-C ;-)
>
> I don't think that the right way to offer information about mutability
> would be to add a public API. As you noted, the problem at hand comes
> from the fact that, in the current implementation, non-mutable strings
> are instances of a subclass of NSMutableString (how something like
> that can pass design reviews and finds its way into the, otherwise
> excellent, major framework of a major operating system will be a
> subject of amazement for generations of developers).
> Just fix this nonsense and the problem will disappear.
Well not fully. APIs can say they return an immutable objects yet they
are free to return a mutable one since mutable objects are a refinement
of immutable versions in Cocoa. So looking at the object to see if it
is mutable or not can mislead you on what the intent was of the code
that generated the instance for you.
Of course ideally those APIs should return a copy (immutable copy) of
any mutable version used internally if the API implies that what you
get back is unchanging, etc. In theory NSProxy object can be used as
well to prevent unwanted modification (say the returned object should
track changes but not allow changes by others).
-Shawn
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 7, 2004, at 1:19 PM, Ali Ozer wrote:
> The question in these cases is why you need to know that an object youI am sorry Ali, but the following is just plain wrong, no matter what
> didn't create is mutable or not... (If you created it, presumably you
> know, and you can remember the state.)
>
> I'm asking this because some decisions that are made based on the
> mutability of an object you don't own can be dangerous, as you don't
> know whether the object is actually part of some other graph of
> objects.
>
the intentions were:
id obj=[[NSString alloc]init];
//... somewhere else later
if([obj isKindOfClass:[NSMutableString class]])
{
[obj appendString:@"Test"];
}
-> An uncaught exception was raised
-> Attempt to mutate immutable NSString with appendString:
As I have said many times since their inception for Openstep: The Class
Clusters are a poor design, and their implementation is even worse.
Gerd
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 8, 2004, at 12:26 PM, Gerd Knops wrote:
> I am sorry Ali, but the following is just plain wrong, no matter what
> the intentions were:
>
> id obj=[[NSString alloc]init];
>
> //... somewhere else later
> if([obj isKindOfClass:[NSMutableString class]])
> {
> [obj appendString:@"Test"];
> }
>
> -> An uncaught exception was raised
> -> Attempt to mutate immutable NSString with appendString:
>
> As I have said many times since their inception for Openstep: The
> Class Clusters are a poor design, and their implementation is even
> worse.
Have you tried this?
if ([obj respondsToSelector: @selector(appendString:)] {
....
}
- Scott
--
Tree House Ideas
http://treehouseideas.com/
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Yes and it returns true on NSString
/a
On Jul 8, 2004, at 2:39 PM, Scott Stevenson wrote:
>
> On Jul 8, 2004, at 12:26 PM, Gerd Knops wrote:
>
>> I am sorry Ali, but the following is just plain wrong, no matter what
>> the intentions were:
>>
>> id obj=[[NSString alloc]init];
>>
>> //... somewhere else later
>> if([obj isKindOfClass:[NSMutableString class]])
>> {
>> [obj appendString:@"Test"];
>> }
>>
>> -> An uncaught exception was raised
>> -> Attempt to mutate immutable NSString with appendString:
>>
>> As I have said many times since their inception for Openstep: The
>> Class Clusters are a poor design, and their implementation is even
>> worse.
>
> Have you tried this?
>
> if ([obj respondsToSelector: @selector(appendString:)] {
> ....
> }
>
>
> - Scott
>
> --
> Tree House Ideas
> http://treehouseideas.com/
>
> _______________________________________________
> MacOSX-dev mailing list
> <MacOSX-dev...>
> http://www.omnigroup.com/mailman/listinfo/macosx-dev
>
>
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 8, 2004, at 2:39 PM, Scott Stevenson wrote:
>That's beside the point. And the fact that it returns true goes to show
> On Jul 8, 2004, at 12:26 PM, Gerd Knops wrote:
>
>> I am sorry Ali, but the following is just plain wrong, no matter what
>> the intentions were:
>>
>> id obj=[[NSString alloc]init];
>>
>> //... somewhere else later
>> if([obj isKindOfClass:[NSMutableString class]])
>> {
>> [obj appendString:@"Test"];
>> }
>>
>> -> An uncaught exception was raised
>> -> Attempt to mutate immutable NSString with appendString:
>>
>> As I have said many times since their inception for Openstep: The
>> Class Clusters are a poor design, and their implementation is even
>> worse.
>
> Have you tried this?
>
> if ([obj respondsToSelector: @selector(appendString:)] {
> ....
> }
>
how perverted this situation really is... Basically there is an object
that claims to be an NSMutableString, and then complains bitterly if
you treat it as such. OOP at it's worst!
Gerd
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 8, 2004, at 1:21 PM, Gerd Knops wrote:
> That's beside the point. And the fact that it returns true goes to
> show how perverted this situation really is... Basically there is an
> object that claims to be an NSMutableString, and then complains
> bitterly if you treat it as such. OOP at it's worst!
Eh, not sure I agree with that. I haven't followed this thread closely,
but every language/framework has its own idea of how to implement the
ideals of OO ideals.
One of the themes in Cocoa is "loosely coupled". Personally, I don't
think you should worry about the implementation details of the object
you acquire from another source. That's somewhat heavy handed. If you
need a mutable string, take the string object and do a -mutableCopy. If
you need to apply changes back to the source, send the new object to
the appropriate setter.
I think you could argue that this is a better approach because it gives
the source of the original string the opportunity to do additional work
when changes are made to the string. Changing the contents out from
under the source means it may not be able to keep something else in
sync easily.
I do, however, agree that if something says it can respond to a
selector, it should.
- Scott
--
Tree House Ideas
http://treehouseideas.com/
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Time to file a bug I guess.
It seems that most of the CF based classes are implemented as one class
for their mutable and non-mutable parts.
NSAttributedString and NSMutableAttributedString which are non CF based
do not show that stupid behavior. Hope that Tiger will fix this! And
because of the NDA I will have no way to tell :-(
Here a sample code:
> #import <Foundation/Foundation.h>
>
> int main (int argc, const char * argv[]) {
> NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>
> // insert code here...
> NSString *str = [NSString stringWithFormat:@"Hello %d times",3];
> NSMutableString *mstr = [[[NSMutableString alloc] init] autorelease];
> NSArray *array = [NSArray
> arrayWithObjects:@"one",@"two",@"three",nil];
> NSMutableArray *marray = [[[NSMutableArray alloc] init] autorelease];
> NSSet *set = [NSSet setWithObjects:@"one",@"two",@"three",nil];
> NSMutableSet *mset = [[[NSMutableSet alloc] init] autorelease];
> NSAttributedString *ats = [[NSAttributedString alloc]
> initWithString:@"I am an NSAttributedString"];
> NSMutableAttributedString *mats = [[NSMutableAttributedString alloc]
> initWithString:@"I am an NSMutableAttributedString"];
> if ([str respondsToSelector: @selector(appendString:)]) {
> NSLog(@"Should not happen!");
> NSLog(@"[str class] = %@",[str class]);
> }
> if ([mstr respondsToSelector: @selector(appendString:)]) {
> NSLog(@"Ok for NSMutableString!");
> NSLog(@"[mstr class] = %@",[mstr class]);
> }
> if ([array respondsToSelector: @selector(addObject:)]) {
> NSLog(@"Should not happen!");
> NSLog(@"[array class] = %@",[array class]);
> }
> if ([marray respondsToSelector: @selector(addObject:)]) {
> NSLog(@"Ok for NSMutableArray!");
> NSLog(@"[mstr class] = %@",[marray class]);
> }
> if ([set respondsToSelector: @selector(addObject:)]) {
> NSLog(@"Should not happen!");
> NSLog(@"[set class] = %@",[set class]);
> }
> if ([mset respondsToSelector: @selector(addObject:)]) {
> NSLog(@"Ok for NSMutableSet!");
> NSLog(@"[mset class] = %@",[mset class]);
> }
> if ([ats respondsToSelector: @selector(appendAttributedString:)]) {
> NSLog(@"Should not happen!");
> NSLog(@"[ats class] = %@",[ats class]);
> }
>
> if ([mats respondsToSelector: @selector(appendAttributedString:)]) {
> NSLog(@"Ok for NSMutableSet!");
> NSLog(@"[mats class] = %@",[mats class]);
> }
>
> [pool release];
> return 0;
> }
Here the results:
> Current language: auto; currently objective-c
> 2004-07-08 14:00:33.366 AAA[2308] Should not happen!
> 2004-07-08 14:00:34.448 AAA[2308] [str class] = NSCFString
> 2004-07-08 14:00:37.457 AAA[2308] Ok for NSMutableString!
> 2004-07-08 14:00:38.553 AAA[2308] [mstr class] = NSCFString
> 2004-07-08 14:00:40.669 AAA[2308] Should not happen!
> 2004-07-08 14:00:45.180 AAA[2308] [array class] = NSCFArray
> 2004-07-08 14:00:55.527 AAA[2308] Ok for NSMutableArray!
> 2004-07-08 14:00:56.765 AAA[2308] [mstr class] = NSCFArray
> 2004-07-08 14:00:59.753 AAA[2308] Should not happen!
> 2004-07-08 14:01:00.808 AAA[2308] [set class] = NSCFSet
> 2004-07-08 14:01:10.595 AAA[2308] Ok for NSMutableSet!
> 2004-07-08 14:01:12.655 AAA[2308] [mset class] = NSCFSet
> 2004-07-08 14:01:21.643 AAA[2308] Ok for NSMutableSet!
> 2004-07-08 14:01:42.514 AAA[2308] [mats class] =
> NSConcreteMutableAttributedString
> (gdb)
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 8, 2004, at 3:40 PM, Scott Stevenson wrote:
>
> On Jul 8, 2004, at 1:21 PM, Gerd Knops wrote:
>
>> That's beside the point. And the fact that it returns true goes to
>> show how perverted this situation really is... Basically there is an
>> object that claims to be an NSMutableString, and then complains
>> bitterly if you treat it as such. OOP at it's worst!
>
> Eh, not sure I agree with that. I haven't followed this thread
> closely, but every language/framework has its own idea of how to
> implement the ideals of OO ideals.
>
> One of the themes in Cocoa is "loosely coupled". Personally, I don't
> think you should worry about the implementation details of the object
> you acquire from another source. That's somewhat heavy handed.
Introspection has been part of (and in IMHO a strength of) the
Objective-C runtime since the beginning. In many situations it has
tremendous benefits, for example in modular software or wherever
delegation is involved.
> If you need a mutable string, take the string object and do aAgreed.
> -mutableCopy. If you need to apply changes back to the source, send
> the new object to the appropriate setter.
>
> I think you could argue that this is a better approach because itAnd that it shouldn't pretend to be class X when it really isn't. And
> gives the source of the original string the opportunity to do
> additional work when changes are made to the string. Changing the
> contents out from under the source means it may not be able to keep
> something else in sync easily.
>
> I do, however, agree that if something says it can respond to a
> selector, it should.
>
that is the point. If I get an object, I should NOT have to worry about
how it came into existence. I should be able to rely on it behaving
like an object of the class it is pretending to be a member of. When it
doesn't, we break some of the fundamental ideas of OOP, and end up with
action on a distance. And this counts doubly so for such fundamental
Objects like String, Number, Array and Dictionary.
Gerd
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Fabien,
Essentially its a no-op. The problem is that when you create an
instance of a string, the library is returning a subclass on you - or
making NSCFString 'poseAsClass' NSString. Thus if you ask an NSString
what class it is, it will happily tell you that it is an NSCFString
which of course responds to all the methods of NSString and
NSMutableString.
The only problem is that to you they are NSString or NSMutableString so
you are expecting these things to respond that they are those things.
But they are not. Hence the issue. For those who care, here's the
class-dump of this thing.
Cheers,
/a
@interface NSCFString : NSMutableString
{
}
- (id)retain;
- (oneway void)release;
- (unsigned int)retainCount;
- (unsigned int)hash;
- (unsigned int)length;
- (unsigned short)characterAtIndex:(unsigned int)fp8;
- (void)getCharacters:(unsigned short *)fp8 range:(struct _NSRange)fp12;
- (const unsigned short *)_fastCharacterContents;
- (const char *)_fastCStringContents:(BOOL)fp8;
- (const char *)cString;
- (const char *)UTF8String;
- (unsigned int)cStringLength;
- (id)substringWithRange:(struct _NSRange)fp8;
- (BOOL)isEqual:(id)fp8;
- (BOOL)isEqualToString:(id)fp8;
- (BOOL)hasPrefix:(id)fp8;
- (BOOL)hasSuffix:(id)fp8;
- (void)getLineStart:(unsigned int *)fp8 end:(unsigned int *)fp12
contentsEnd:(unsigned int *)fp16 forRange:(struct _NSRange)fp20;
- (id)copyWithZone:(struct _NSZone *)fp8;
- (id)mutableCopyWithZone:(struct _NSZone *)fp8;
- (unsigned int)fastestEncoding;
- (unsigned int)smallestEncoding;
- (Class)classForCoder;
- (BOOL)_isCString;
- (void)replaceCharactersInRange:(struct _NSRange)fp8
withString:(id)fp16;
- (void)insertString:(id)fp8 atIndex:(unsigned int)fp12;
- (void)appendString:(id)fp8;
- (void)deleteCharactersInRange:(struct _NSRange)fp8;
- (void)appendFormat:(id)fp8;
- (void)setString:(id)fp8;
- (void)appendCharacters:(const unsigned short *)fp8 length:(unsigned
int)fp12;
- (unsigned int)replaceOccurrencesOfString:(id)fp8 withString:(id)fp12
options:(unsigned int)fp16 range:(struct _NSRange)fp20;
@end
On Jul 8, 2004, at 4:10 PM, Fabien Roy wrote:
> Time to file a bug I guess.
> It seems that most of the CF based classes are implemented as one
> class for their mutable and non-mutable parts.
> NSAttributedString and NSMutableAttributedString which are non CF
> based do not show that stupid behavior. Hope that Tiger will fix this!
> And because of the NDA I will have no way to tell :-(
>
> Here a sample code:
>
>> #import <Foundation/Foundation.h>
>>
>> int main (int argc, const char * argv[]) {
>> NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>>
>> // insert code here...
>> NSString *str = [NSString stringWithFormat:@"Hello %d times",3];
>> NSMutableString *mstr = [[[NSMutableString alloc] init] autorelease];
>> NSArray *array = [NSArray
>> arrayWithObjects:@"one",@"two",@"three",nil];
>> NSMutableArray *marray = [[[NSMutableArray alloc] init] autorelease];
>> NSSet *set = [NSSet setWithObjects:@"one",@"two",@"three",nil];
>> NSMutableSet *mset = [[[NSMutableSet alloc] init] autorelease];
>> NSAttributedString *ats = [[NSAttributedString alloc]
>> initWithString:@"I am an NSAttributedString"];
>> NSMutableAttributedString *mats = [[NSMutableAttributedString alloc]
>> initWithString:@"I am an NSMutableAttributedString"];
>> if ([str respondsToSelector: @selector(appendString:)]) {
>> NSLog(@"Should not happen!");
>> NSLog(@"[str class] = %@",[str class]);
>> }
>> if ([mstr respondsToSelector: @selector(appendString:)]) {
>> NSLog(@"Ok for NSMutableString!");
>> NSLog(@"[mstr class] = %@",[mstr class]);
>> }
>> if ([array respondsToSelector: @selector(addObject:)]) {
>> NSLog(@"Should not happen!");
>> NSLog(@"[array class] = %@",[array class]);
>> }
>> if ([marray respondsToSelector: @selector(addObject:)]) {
>> NSLog(@"Ok for NSMutableArray!");
>> NSLog(@"[mstr class] = %@",[marray class]);
>> }
>> if ([set respondsToSelector: @selector(addObject:)]) {
>> NSLog(@"Should not happen!");
>> NSLog(@"[set class] = %@",[set class]);
>> }
>> if ([mset respondsToSelector: @selector(addObject:)]) {
>> NSLog(@"Ok for NSMutableSet!");
>> NSLog(@"[mset class] = %@",[mset class]);
>> }
>> if ([ats respondsToSelector: @selector(appendAttributedString:)]) {
>> NSLog(@"Should not happen!");
>> NSLog(@"[ats class] = %@",[ats class]);
>> }
>>
>> if ([mats respondsToSelector: @selector(appendAttributedString:)]) {
>> NSLog(@"Ok for NSMutableSet!");
>> NSLog(@"[mats class] = %@",[mats class]);
>> }
>>
>> [pool release];
>> return 0;
>> }
>
> Here the results:
>> Current language: auto; currently objective-c
>> 2004-07-08 14:00:33.366 AAA[2308] Should not happen!
>> 2004-07-08 14:00:34.448 AAA[2308] [str class] = NSCFString
>> 2004-07-08 14:00:37.457 AAA[2308] Ok for NSMutableString!
>> 2004-07-08 14:00:38.553 AAA[2308] [mstr class] = NSCFString
>> 2004-07-08 14:00:40.669 AAA[2308] Should not happen!
>> 2004-07-08 14:00:45.180 AAA[2308] [array class] = NSCFArray
>> 2004-07-08 14:00:55.527 AAA[2308] Ok for NSMutableArray!
>> 2004-07-08 14:00:56.765 AAA[2308] [mstr class] = NSCFArray
>> 2004-07-08 14:00:59.753 AAA[2308] Should not happen!
>> 2004-07-08 14:01:00.808 AAA[2308] [set class] = NSCFSet
>> 2004-07-08 14:01:10.595 AAA[2308] Ok for NSMutableSet!
>> 2004-07-08 14:01:12.655 AAA[2308] [mset class] = NSCFSet
>> 2004-07-08 14:01:21.643 AAA[2308] Ok for NSMutableSet!
>> 2004-07-08 14:01:42.514 AAA[2308] [mats class] =
>> NSConcreteMutableAttributedString
>> (gdb)
>
>
>
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
This is huge regression from OPENSTEP. Even if that returned class says
that it responds to all methods of NSString and NSMutableString how in
the hell is when you try to execute a mutable method on a non mutable
instance of NSCFString the method crashes! So there must be a way that
this class KNOWS that this instance is immutable.
I would like to see the technical justification of this design.
Fabien
I was not convince that CF was a good move for Apple. Now I think that
it was a STUPID move.
On Jul 9, 2004, at 9:05 AM, Alberto Ricart wrote:
> Fabien,
>
> Essentially its a no-op. The problem is that when you create an
> instance of a string, the library is returning a subclass on you - or
> making NSCFString 'poseAsClass' NSString. Thus if you ask an NSString
> what class it is, it will happily tell you that it is an NSCFString
> which of course responds to all the methods of NSString and
> NSMutableString.
>
> The only problem is that to you they are NSString or NSMutableString
> so you are expecting these things to respond that they are those
> things. But they are not. Hence the issue. For those who care, here's
> the class-dump of this thing.
>
> Cheers,
>
> /a
>
>
> @interface NSCFString : NSMutableString
> {
> }
>
> - (id)retain;
> - (oneway void)release;
> - (unsigned int)retainCount;
> - (unsigned int)hash;
> - (unsigned int)length;
> - (unsigned short)characterAtIndex:(unsigned int)fp8;
> - (void)getCharacters:(unsigned short *)fp8 range:(struct
> _NSRange)fp12;
> - (const unsigned short *)_fastCharacterContents;
> - (const char *)_fastCStringContents:(BOOL)fp8;
> - (const char *)cString;
> - (const char *)UTF8String;
> - (unsigned int)cStringLength;
> - (id)substringWithRange:(struct _NSRange)fp8;
> - (BOOL)isEqual:(id)fp8;
> - (BOOL)isEqualToString:(id)fp8;
> - (BOOL)hasPrefix:(id)fp8;
> - (BOOL)hasSuffix:(id)fp8;
> - (void)getLineStart:(unsigned int *)fp8 end:(unsigned int *)fp12
> contentsEnd:(unsigned int *)fp16 forRange:(struct _NSRange)fp20;
> - (id)copyWithZone:(struct _NSZone *)fp8;
> - (id)mutableCopyWithZone:(struct _NSZone *)fp8;
> - (unsigned int)fastestEncoding;
> - (unsigned int)smallestEncoding;
> - (Class)classForCoder;
> - (BOOL)_isCString;
> - (void)replaceCharactersInRange:(struct _NSRange)fp8
> withString:(id)fp16;
> - (void)insertString:(id)fp8 atIndex:(unsigned int)fp12;
> - (void)appendString:(id)fp8;
> - (void)deleteCharactersInRange:(struct _NSRange)fp8;
> - (void)appendFormat:(id)fp8;
> - (void)setString:(id)fp8;
> - (void)appendCharacters:(const unsigned short *)fp8 length:(unsigned
> int)fp12;
> - (unsigned int)replaceOccurrencesOfString:(id)fp8 withString:(id)fp12
> options:(unsigned int)fp16 range:(struct _NSRange)fp20;
>
> @end
>
>
>
>
> On Jul 8, 2004, at 4:10 PM, Fabien Roy wrote:
>
>> Time to file a bug I guess.
>> It seems that most of the CF based classes are implemented as one
>> class for their mutable and non-mutable parts.
>> NSAttributedString and NSMutableAttributedString which are non CF
>> based do not show that stupid behavior. Hope that Tiger will fix
>> this! And because of the NDA I will have no way to tell :-(
>>
>> Here a sample code:
>>
>>> #import <Foundation/Foundation.h>
>>>
>>> int main (int argc, const char * argv[]) {
>>> NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>>>
>>> // insert code here...
>>> NSString *str = [NSString stringWithFormat:@"Hello %d times",3];
>>> NSMutableString *mstr = [[[NSMutableString alloc] init]
>>> autorelease];
>>> NSArray *array = [NSArray
>>> arrayWithObjects:@"one",@"two",@"three",nil];
>>> NSMutableArray *marray = [[[NSMutableArray alloc] init]
>>> autorelease];
>>> NSSet *set = [NSSet setWithObjects:@"one",@"two",@"three",nil];
>>> NSMutableSet *mset = [[[NSMutableSet alloc] init] autorelease];
>>> NSAttributedString *ats = [[NSAttributedString alloc]
>>> initWithString:@"I am an NSAttributedString"];
>>> NSMutableAttributedString *mats = [[NSMutableAttributedString
>>> alloc] initWithString:@"I am an NSMutableAttributedString"];
>>> if ([str respondsToSelector: @selector(appendString:)]) {
>>> NSLog(@"Should not happen!");
>>> NSLog(@"[str class] = %@",[str class]);
>>> }
>>> if ([mstr respondsToSelector: @selector(appendString:)]) {
>>> NSLog(@"Ok for NSMutableString!");
>>> NSLog(@"[mstr class] = %@",[mstr class]);
>>> }
>>> if ([array respondsToSelector: @selector(addObject:)]) {
>>> NSLog(@"Should not happen!");
>>> NSLog(@"[array class] = %@",[array class]);
>>> }
>>> if ([marray respondsToSelector: @selector(addObject:)]) {
>>> NSLog(@"Ok for NSMutableArray!");
>>> NSLog(@"[mstr class] = %@",[marray class]);
>>> }
>>> if ([set respondsToSelector: @selector(addObject:)]) {
>>> NSLog(@"Should not happen!");
>>> NSLog(@"[set class] = %@",[set class]);
>>> }
>>> if ([mset respondsToSelector: @selector(addObject:)]) {
>>> NSLog(@"Ok for NSMutableSet!");
>>> NSLog(@"[mset class] = %@",[mset class]);
>>> }
>>> if ([ats respondsToSelector: @selector(appendAttributedString:)]) {
>>> NSLog(@"Should not happen!");
>>> NSLog(@"[ats class] = %@",[ats class]);
>>> }
>>>
>>> if ([mats respondsToSelector: @selector(appendAttributedString:)]) {
>>> NSLog(@"Ok for NSMutableSet!");
>>> NSLog(@"[mats class] = %@",[mats class]);
>>> }
>>>
>>> [pool release];
>>> return 0;
>>> }
>>
>> Here the results:
>>> Current language: auto; currently objective-c
>>> 2004-07-08 14:00:33.366 AAA[2308] Should not happen!
>>> 2004-07-08 14:00:34.448 AAA[2308] [str class] = NSCFString
>>> 2004-07-08 14:00:37.457 AAA[2308] Ok for NSMutableString!
>>> 2004-07-08 14:00:38.553 AAA[2308] [mstr class] = NSCFString
>>> 2004-07-08 14:00:40.669 AAA[2308] Should not happen!
>>> 2004-07-08 14:00:45.180 AAA[2308] [array class] = NSCFArray
>>> 2004-07-08 14:00:55.527 AAA[2308] Ok for NSMutableArray!
>>> 2004-07-08 14:00:56.765 AAA[2308] [mstr class] = NSCFArray
>>> 2004-07-08 14:00:59.753 AAA[2308] Should not happen!
>>> 2004-07-08 14:01:00.808 AAA[2308] [set class] = NSCFSet
>>> 2004-07-08 14:01:10.595 AAA[2308] Ok for NSMutableSet!
>>> 2004-07-08 14:01:12.655 AAA[2308] [mset class] = NSCFSet
>>> 2004-07-08 14:01:21.643 AAA[2308] Ok for NSMutableSet!
>>> 2004-07-08 14:01:42.514 AAA[2308] [mats class] =
>>> NSConcreteMutableAttributedString
>>> (gdb)
>>
>>
>>
>
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
On Jul 9, 2004, at 7:27 PM, Fabien Roy wrote:
> This is huge regression from OPENSTEP. Even if that returned class
> says that it responds to all methods of NSString and NSMutableString
> how in the hell is when you try to execute a mutable method on a non
> mutable instance of NSCFString the method crashes! So there must be a
> way that this class KNOWS that this instance is immutable.
> I would like to see the technical justification of this design.
What about speed?
This is a well known fact that the "type" returned by the AppKit and
Foundation are not necessarily exactly the "type" declared in the
prototype.
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Take an old 68040 NeXT machine and see that some operations are still
snappy!
I don't care about the type but an object pretending to respond to a
method and would crash when applying that method is just useless. Its
like having a really fast car with really bad brakes or steering. And
talking about speed, I was told that some the early CF classes did
regress from the OPENSTEP ones, i.e. their algorithm were in "N^2"
where the original implementation was on "N log N".
Fabien
On Jul 9, 2004, at 10:37 AM, Stéphane Sudre wrote:
> What about speed?
>
> This is a well known fact that the "type" returned by the AppKit and
> Foundation are not necessarily exactly the "type" declared in the
> prototype.
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev -
Speed? My take is that this depends on the algorithm used, not on how
one class implements (some/all) the functionality of another. Aside
from the messaging overhead (which makes me, a programmer, speedier),
we are talking about 'C' code. If you need it faster, you can always
tweak your algorithm, write plain C code, or take a dive into assembly.
Regardless of speed, I do have a problem with NSString and
NSMutableStrings not being what they claim to be. If you told me these
classes came from an "NSStringFactory" which returned any
implementation appropriate for the task/interface I would be happy
because I would known that the type is really based on some interface
and the actual impl is not important, but that is not what is happening
here.
In the end this is all kind of 'pointless'. As I don't think they are
going to revamp foundation to fix how ObjC handles respondsToSelector.
AppKit is second to the other apis and this is just another hint/result
of this.
And yes, CF was not a good move because it introduced inconsistencies
and weird integration points. However, if it wasn't for these types of
things, we probably wouldn't have what we have. As for sure Steve
wasn't going to make the same mistake twice of having an app-less nice
environment.
I think the solution is simply type these things as id, and if you need
to edit it, mutableCopy it, and do your thing. Let the library deal
with how quickly it needs to copy the bytes (I am sure altivec comes
really handy for these).
Cheers,
/a
On Jul 9, 2004, at 12:37 PM, Stéphane Sudre wrote:
>
> On Jul 9, 2004, at 7:27 PM, Fabien Roy wrote:
>
>> This is huge regression from OPENSTEP. Even if that returned class
>> says that it responds to all methods of NSString and NSMutableString
>> how in the hell is when you try to execute a mutable method on a non
>> mutable instance of NSCFString the method crashes! So there must be a
>> way that this class KNOWS that this instance is immutable.
>> I would like to see the technical justification of this design.
>
> What about speed?
>
> This is a well known fact that the "type" returned by the AppKit and
> Foundation are not necessarily exactly the "type" declared in the
> prototype.
>
> _______________________________________________
> MacOSX-dev mailing list
> <MacOSX-dev...>
> http://www.omnigroup.com/mailman/listinfo/macosx-dev
>
>
_______________________________________________
MacOSX-dev mailing list
<MacOSX-dev...>
http://www.omnigroup.com/mailman/listinfo/macosx-dev


