Printing Foundation objects shows only class names, no values

I just noticed that printing Foundation objects no longer shows their values in Swift 4.2:

let num = NSNumber(value: 123)
print(num)

In Swift 4.1 (Xcode 9.4.1, default toolchain) the output is

123

With Swift 4.2 (Xcode 10 beta 2, default toolchain) I get just

__NSCFNumber

I thought that print() uses the description or debugDescription, but apparently that is not the case (anymore):

let num = NSNumber(value: 123)
print(num)                  // __NSCFNumber
print(num.description)      // 123
print(num.debugDescription) // 123
print("\(num)")             // 123

I also thought (from [stdlib] Array.description calls debugDescription on its contents) that printing an array calls debugDescription on each element, but that does not work either:

let a = [NSNumber(value: 123), NSNumber(value: true)]
print(a)                   // [__NSCFNumber, __NSCFBoolean]
print(a.description)       // [__NSCFNumber, __NSCFBoolean]
print(a.debugDescription)  // [__NSCFNumber, __NSCFBoolean]
print("\(a)")              // [__NSCFNumber, __NSCFBoolean]

Another example: Bridging Data to NSData used to be a workaround to see the contents, since Data.description only shows the number of bytes:

let data = Data(bytes: [1, 2, 3])
print(data)           // 3 bytes

// Swift 4.1 (Xcode 9.4.1):
print(data as NSData) // <010203>

// Swift 4.2 (Xcode 10):
print(data as NSData) // Foundation._NSSwiftData

Another (perhaps more realistic) example where the new behavior is inconvenient:

let jsonData  = Data("""
    { "number" : 123, "string": "Hello World", "bool" : true }
""".utf8)
let dict = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [String: Any]

print(dict)      // ["number": __NSCFNumber, "string": __NSCFString, "bool": __NSCFBoolean]
print("\(dict)") // ["number": __NSCFNumber, "string": __NSCFString, "bool": __NSCFBoolean]

Is this a known problem, or am I overlooking something? Otherwise I'll file it as a bug.

I am aware that one cannot rely on a certain output when printing objects, but this makes it almost useless even for debugging/logging purposes.

Are you building a statically-linked CLI tool? There's a known issue with static linking we're currently investigating that can cause problems like this.

It is an Xcode project from the "macOS/Command Line Tool" template, without changing any build settings. So I guess the answer to your question is “yes”.

1 Like

Yeah, the Xcode Command Line Tool template will statically link by default, so this is likely the linker issue we're working on.

Indeed, the output is “correct” if the program is compiled with swiftc and linked dynamically against the Swift runtime libraries:

$ cat test.swift 
import Foundation

let num = NSNumber(value: 123)
print(num)

$ swiftc -v test.swift 
Apple Swift version 4.2 (swiftlang-1000.0.16.9 clang-1000.10.25.3)
Target: x86_64-apple-darwin17.6.0
/Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file test.swift -target x86_64-apple-darwin17.6.0 -enable-objc-interop -sdk /Applications/other/Xcode10-beta2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -color-diagnostics -module-name test -o /var/folders/qy/0w32gn3n2nlgd48__2s0n8_w0000gn/T/test-c7411d.o
/Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld /var/folders/qy/0w32gn3n2nlgd48__2s0n8_w0000gn/T/test-c7411d.o -syslibroot /Applications/other/Xcode10-beta2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -lobjc -lSystem -arch x86_64 -L /Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -rpath /Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -macosx_version_min 10.13.0 -no_objc_category_merging -o test

$ ./test 
123

$ otool -L test
test:
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1540.0.0)
    @rpath/libswiftCore.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftCoreFoundation.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftCoreGraphics.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftDarwin.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftDispatch.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftFoundation.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftIOKit.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftObjectiveC.dylib (compatibility version 1.0.0, current version 1000.0.16)
    @rpath/libswiftSwiftOnoneSupport.dylib (compatibility version 1.0.0, current version 1000.0.16)

On the other hand:

$ swiftc -v -static-stdlib test.swift 
Apple Swift version 4.2 (swiftlang-1000.0.16.9 clang-1000.10.25.3)
Target: x86_64-apple-darwin17.6.0
/Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file test.swift -target x86_64-apple-darwin17.6.0 -enable-objc-interop -sdk /Applications/other/Xcode10-beta2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -color-diagnostics -module-name test -o /var/folders/qy/0w32gn3n2nlgd48__2s0n8_w0000gn/T/test-9b7261.o
/Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld /var/folders/qy/0w32gn3n2nlgd48__2s0n8_w0000gn/T/test-9b7261.o -syslibroot /Applications/other/Xcode10-beta2.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -lobjc -lSystem -arch x86_64 -L /Applications/other/Xcode10-beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift_static/macosx -lc++ -framework Foundation -force_load_swift_libs -macosx_version_min 10.13.0 -no_objc_category_merging -o test

$ ./test 
__NSCFNumber
1 Like

Apparently this has been solved. With Xcode 10 beta 5 one gets the expected output, as it was in Swift 4.1:

import Foundation

let num = NSNumber(value: 123)
print(num) // 123

let a = [NSNumber(value: 123), NSNumber(value: true)]
print(a) // [123, 1]

let data = Data(bytes: [1, 2, 3])
print(data as NSData) // <010203>
2 Likes