"We need to get ahold of a class given a name" is definitely a requirement to 
do NSCoding right. I'm not at all convinced dlsym is a valid long-term answer 
for that, though. If you have an 'internal' class, it doesn't (currently) have 
a public symbol that you can use dlsym for.

This sort of goes with the existing problem of static registration: there's no 
pure Swift way to get all subclasses of a class, or to get a class from a name 
for any other reason. That's a general language problem, though, and we should 
discuss it on swift-dev.

Jordan


> On Dec 23, 2015, at 15:12, Philippe Hausler <phaus...@apple.com> wrote:
> 
> NSCoding will have to use something to transform from strings to classes, and 
> that satisfy the two cases (or more) that we have already shown, currently 
> there is no thing that does that in either form; either mangled or non 
> mangled. Basically we need something to implement NSClassFromString with. 
> Which we have clearly shown that dlsym does not fully meet the needs since 
> there are cases that will emit as “module.classname” and others that emit as 
> the mangled name. The simple case is probably going to be the a very common 
> usage pattern for consumers (and of previously built applications). The inner 
> class should definitely be handled in addition to this case.
> 
> Are there any methods that can fetch the name (either the symbolic or the 
> readable) given a AnyClass in the runtime to get work started here? I think 
> it is definitely sensible as a start to restrict this just to descendants of 
> the class NSObject. I would presume that since the Metadata is potentially 
> volatile contents we should use something along the lines of 
> swift_getTypeName etc?
> 
>> On Dec 23, 2015, at 2:53 PM, Jordan Rose <jordan_r...@apple.com 
>> <mailto:jordan_r...@apple.com>> wrote:
>> 
>> Here's another example on OS X:
>> 
>> import Foundation
>> 
>> class Outer {
>>     class Inner : NSObject, NSCoding {
>>         let uuid: Foundation.NSUUID
>>         required init?(coder aDecoder: NSCoder) {
>>             uuid = aDecoder.decodeObjectForKey("my.uuid") as! 
>> Foundation.NSUUID
>>         }
>>         override init() {
>>             uuid = Foundation.NSUUID()
>>         }
>>         func encodeWithCoder(aCoder: NSCoder) {
>>             aCoder.encodeObject(uuid, forKey: "my.uuid")
>>         }
>>     }
>> }
>> 
>> NSKeyedArchiver.archiveRootObject(Outer.Inner(), toFile: 
>> "/Users/jrose/Desktop/test-archive")
>> 
>> 
>> Which results in this archive:
>> 
>> {
>>   "$version" => 100000
>>   "$objects" => [
>>     0 => "$null"
>>     1 => {
>>       "my.uuid" => <CFKeyedArchiverUID 0x7f8992c0e9d0 
>> [0x7fff7c5acd80]>{value = 2}
>>       "$class" => <CFKeyedArchiverUID 0x7f8992c0ec90 [0x7fff7c5acd80]>{value 
>> = 4}
>>     }
>>     2 => {
>>       "NS.uuidbytes" => <67f0b08b c8274f8c b0c78d90 bd4627dc>
>>       "$class" => <CFKeyedArchiverUID 0x7f8992c0eda0 [0x7fff7c5acd80]>{value 
>> = 3}
>>     }
>>     3 => {
>>       "$classname" => "NSUUID"
>>       "$classes" => [
>>         0 => "NSUUID"
>>         1 => "NSObject"
>>       ]
>>     }
>>     4 => {
>>       "$classname" => "_TtCC4main5Outer5Inner"
>>       "$classes" => [
>>         0 => "_TtCC4main5Outer5Inner"
>>         1 => "NSObject"
>>       ]
>>     }
>>   ]
>>   "$archiver" => "NSKeyedArchiver"
>>   "$top" => {
>>     "root" => <CFKeyedArchiverUID 0x7f8992c0f0c0 [0x7fff7c5acd80]>{value = 1}
>>   }
>> }
>> 
>> NSStringFromClass makes pretty names when they fall into the "simple" 
>> category, but that's not an arbitrarily extensible transformation, and 
>> NSCoding shouldn't have to know anything about it.
>> 
>> Jordan
>> 
>>> On Dec 23, 2015, at 14:48, Philippe Hausler <phaus...@apple.com 
>>> <mailto:phaus...@apple.com>> wrote:
>>> 
>>> The archiving format encodes the names of the classes in the archive 
>>> itself. Here are a few code examples and a quasi readable output from them:
>>> 
>>> let uuid = NSUUID()
>>> let data = NSKeyedArchiver.archivedDataWithRootObject(uuid)
>>> let archive = try! NSPropertyListSerialization.propertyListWithData(data, 
>>> options: [], format: nil)
>>> print(archive)
>>> 
>>> prints the following:
>>> 
>>> {
>>>     "$archiver" = NSKeyedArchiver;
>>>     "$objects" =     (
>>>         "$null",
>>>                 {
>>>             "$class" = "<CFKeyedArchiverUID 0x1030025e0 
>>> [0x7fff7ab33bb0]>{value = 2}";
>>>             "NS.uuidbytes" = <797639fe dad74b14 902afab3 c490448b>;
>>>         },
>>>                 {
>>>             "$classes" =             (
>>>                 NSUUID,
>>>                 NSObject
>>>             );
>>>             "$classname" = NSUUID;
>>>         }
>>>     );
>>>     "$top" =     {
>>>         root = "<CFKeyedArchiverUID 0x103002a80 [0x7fff7ab33bb0]>{value = 
>>> 1}";
>>>     };
>>>     "$version" = 100000;
>>> }
>>> 
>>> Note the $classes and $classname objects; which are what tell the internal 
>>> implementation of NSKeyedUnarchiver what to construct; moreover you can 
>>> create your own classes..
>>> 
>>> // I don’t really think this is a good naming for an application’s class 
>>> but hey it might happen...
>>> class NSUUID : NSObject, NSCoding {
>>>     let uuid: Foundation.NSUUID
>>>     required init?(coder aDecoder: NSCoder) {
>>>         uuid = aDecoder.decodeObjectForKey("my.uuid") as! Foundation.NSUUID
>>>     }
>>>     override init() {
>>>         uuid = Foundation.NSUUID()
>>>     }
>>>     func encodeWithCoder(aCoder: NSCoder) {
>>>         aCoder.encodeObject(uuid, forKey: "my.uuid")
>>>     }
>>> }
>>> 
>>> let uuid = NSUUID()
>>> let data = NSKeyedArchiver.archivedDataWithRootObject(uuid)
>>> let archive = try! NSPropertyListSerialization.propertyListWithData(data, 
>>> options: [], format: nil)
>>> print(archive)
>>> 
>>> prints the following:
>>> 
>>> {
>>>     "$archiver" = NSKeyedArchiver;
>>>     "$objects" =     (
>>>         "$null",
>>>                 {
>>>             "$class" = "<CFKeyedArchiverUID 0x100709630 
>>> [0x7fff7ab33bb0]>{value = 4}";
>>>             "my.uuid" = "<CFKeyedArchiverUID 0x100708e60 
>>> [0x7fff7ab33bb0]>{value = 2}";
>>>         },
>>>                 {
>>>             "$class" = "<CFKeyedArchiverUID 0x100709740 
>>> [0x7fff7ab33bb0]>{value = 3}";
>>>             "NS.uuidbytes" = <546e5b5e 15c244a1 aa96eb90 30c3f7f6>;
>>>         },
>>>                 {
>>>             "$classes" =             (
>>>                 NSUUID,
>>>                 NSObject
>>>             );
>>>             "$classname" = NSUUID;
>>>         },
>>>                 {
>>>             "$classes" =             (
>>>                 "Archiver.NSUUID",
>>>                 NSObject
>>>             );
>>>             "$classname" = "Archiver.NSUUID";
>>>         }
>>>     );
>>>     "$top" =     {
>>>         root = "<CFKeyedArchiverUID 0x100709b70 [0x7fff7ab33bb0]>{value = 
>>> 1}";
>>>     };
>>>     "$version" = 100000;
>>> }
>>> 
>>> Granted this is a questionable name for a class but it illustrates which 
>>> class names are encoded where and how they should be interpreted in the 
>>> pre-existing archive format; which we will have to figure out some sensible 
>>> way of inflating and deflating to/from disk/network etc.
>>> 
>>>> On Dec 23, 2015, at 2:37 PM, Jordan Rose <jordan_r...@apple.com 
>>>> <mailto:jordan_r...@apple.com>> wrote:
>>>> 
>>>> No, we cannot encode things "non-mangled but with the namespace". For any 
>>>> type other than top-level non-generic class types, using a non-mangled 
>>>> name is not unique. The only correct answer for arbitrary classes is to 
>>>> use mangled names, or something that maps one-to-one with mangled names.
>>>> 
>>>> Now, Foundation classes are not arbitrary classes, but then I don't see 
>>>> why we'd need to use mangled names for those. We can just use the plain 
>>>> old Objective-C names that the OS X classes use today.
>>>> 
>>>> Jordan
>>>> 
>>>>> On Dec 22, 2015, at 10:16, Philippe Hausler via swift-corelibs-dev 
>>>>> <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>> 
>>>>> wrote:
>>>>> 
>>>>> To clarify the goals: I think it is reasonable for us to have a goal to 
>>>>> be able to encode/decode archives from foreign targets; e.g. linux 
>>>>> encodes an archive and mac os x decodes or iOS encodes and linux decodes. 
>>>>> This will allow for server architecture to transmit binary archives 
>>>>> across the wire. This will mean that we will want to have the encoded 
>>>>> class names from the application scope to be encoded as the non mangled 
>>>>> name but with the namespace. However this presents a problem; Foundation 
>>>>> will have a namespace which will need to be inferred both for encoding 
>>>>> and decoding. Thankfully there may be a reasonable way to approach this;
>>>>> 
>>>>> public class func classNameForClass(cls: AnyClass) -> String?
>>>>> public class func setClassName(codedName: String?, forClass cls: AnyClass)
>>>>> 
>>>>> These methods can be used to allow for translation of classes by 
>>>>> registering the appropriate classes for a “shortened” name that drops the 
>>>>> Foundation/SwiftFoundation namespace prefix during encoding.
>>>>> 
>>>>>> On Dec 22, 2015, at 2:45 AM, Luke Howard via swift-corelibs-dev 
>>>>>> <swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>> 
>>>>>> wrote:
>>>>>> 
>>>>>> 
>>>>>>> On 22 Dec 2015, at 5:50 AM, Jordan Rose <jordan_r...@apple.com 
>>>>>>> <mailto:jordan_r...@apple.com>> wrote:
>>>>>>> 
>>>>>>> IMHO on Linux NSKeyedArchiver should always use mangled names. If we 
>>>>>>> want cross-platform archives, we should set up standard substitutions, 
>>>>>>> but given that Swift classes exposed to Objective-C are archived with 
>>>>>>> their full names it doesn't make sense to use "half the name" in the 
>>>>>>> archive.
>>>>>> 
>>>>>> You mean namespaced but unmangled yes? If so I agree.
>>>>>> 
>>>>>> BTW I found a couple of small CF nits:
>>>>>> 
>>>>>> * in CFDictionaryGetKeysAndValues(), keybuf and valuebuf are transposed 
>>>>>> in the call to CF_SWIFT_FUNCDISPATCHV(NSDictionary.getObjects())
>>>>>> 
>>>>>> * _CFSwiftDictionaryGetKeysAndValues() does not handle keybuf or valbuf 
>>>>>> being NULL (either of which are valid when calling 
>>>>>> CFDictionaryGetKeysAndValues())
>>>>>> 
>>>>> 
>>>>> This is a bit un-related to NSCoding and the transposition is probably a 
>>>>> mistake if it is inverted (the CF method should be reversed from the NS 
>>>>> method to mimic the objc counterpart)
>>>>> 
>>>>>> — Luke
>>>>>> _______________________________________________
>>>>>> swift-corelibs-dev mailing list
>>>>>> swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
>>>>>> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev 
>>>>>> <https://lists.swift.org/mailman/listinfo/swift-corelibs-dev>
>>>>> 
>>>>> _______________________________________________
>>>>> swift-corelibs-dev mailing list
>>>>> swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev 
>>>>> <https://lists.swift.org/mailman/listinfo/swift-corelibs-dev>
>>> 
>> 
> 

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev

Reply via email to