Automatic value types to Objective-C objects

33 views
Skip to first unread message

Bruno Berisso

unread,
Aug 12, 2015, 10:45:22 AM8/12/15
to swift-l...@googlegroups.com
Hi,

Today i hit a strange behaviour with Swift arrays. If I declare an array with the type Array<AnyObject> and try yo 'append' an Int value Swift return an error, what it's fine because Int is not an object. But if I import Foundation the 'append' wraps the Int in an NSNumber and what was failing before now work.

Here is the output from the Swift REPL:

➜  ~  swift
Welcome to Swift version 1.2. Type :help for assistance.

//Create an array of AnyObject
  1> var array = [AnyObject]()
array: [AnyObject] = 0 values

//Now try to append an Int give the expected result
  2> array.append(1)
repl.swift:2:7: error: cannot invoke 'append' with an argument list of type '(Int)'
array.append(1)
      ^

//Now import foundation and try again result in the expected error
  2> import Foundation
  3> array.append(1)
repl.swift:3:7: error: cannot invoke 'append' with an argument list of type '(Int)'
array.append(1)
      ^

//Try with a new array, just in case...
  3> var secondArray = [AnyObject]()
secondArray: [AnyObject] = 0 values
  4> secondArray.append(1)
repl.swift:4:13: error: cannot invoke 'append' with an argument list of type '(Int)'
secondArray.append(1)
            ^


//Restart the REPL
  4> :quit
➜  ~  swift
Welcome to Swift version 1.2. Type :help for assistance.

//First import Foundation
  1> import Foundation
  2> var array = [AnyObject]()
array: [AnyObject] = 0 values

//Now it doesn't fail
  3> array.append(1)

//And the Int is an "kind of" NSNumber
  4> array[0].isKindOfClass(NSNumber.self)
$R0: Bool = true



I understand that in this case it's kind of not a big deal because NSNumber has value semantics, but I was not expecting this. If you stress this idea you find some inconsistencies at some point like if you have a function expecting an Int, for example:

➜  ~  swift
Welcome to Swift version 1.2. Type :help for assistance.
  1> import Foundation
  2> var array = [AnyObject]()
array: [AnyObject] = 0 values
  3> array.append(1)
  4> func expect_an_int(x : Int) -> Int {
  5.     return Int(12) + x
  6. }    
  7> expect_an_int(array[0])
repl.swift:7:1: error: cannot invoke 'expect_an_int' with an argument list of type '((AnyObject))'
expect_an_int(array[0])
^
repl.swift:7:15: note: expected an argument list of type '(Int)'
expect_an_int(array[0])
                       ^

  7> array.append(Int(2))
  8> array
$R0: [AnyObject] = 2 values {
  [0] = Int64(1)
  [1] = Int64(2)
}
  9> array[0].isKindOfClass(NSNumber.self)
$R1: Bool = true
 10> array[1].isKindOfClass(NSNumber.self)
$R2: Bool = true


Any thoughts?

Jens Alfke

unread,
Aug 12, 2015, 12:14:13 PM8/12/15
to Bruno Berisso, swift-l...@googlegroups.com

On Aug 12, 2015, at 7:45 AM, Bruno Berisso <goja...@gmail.com> wrote:

Today i hit a strange behaviour with Swift arrays. If I declare an array with the type Array<AnyObject> and try yo 'append' an Int value Swift return an error, what it's fine because Int is not an object. But if I import Foundation the 'append' wraps the Int in an NSNumber and what was failing before now work.

That’s correct. NSObject, and subclasses like NSNumber and NSString, are not pure Swift. By importing Foundation you’re telling the compiler you want to use NSObject, so that makes extra bridging features available.

The big question I have is whether the open-source Swift release will include NSObject (and the Objective-C runtime.) If it doesn’t, there are a whole lot of important features that won’t be available to cross-platform Swift code.

—Jens

Bruno Berisso

unread,
Aug 12, 2015, 1:14:44 PM8/12/15
to Swift Language, goja...@gmail.com

I don't think that any feature in Swift needs NSObject or the Objective-C runtime, could you name any?

By the way, there is an open source version of the Foundation classes here, among other things, as part of GNUStep project. The ObjC runtime is already open source by Apple so in the worse case that wont be a problem.

Jens Alfke

unread,
Aug 12, 2015, 1:27:59 PM8/12/15
to Bruno Berisso, Swift Language

On Aug 12, 2015, at 10:14 AM, Bruno Berisso <goja...@gmail.com> wrote:

I don't think that any feature in Swift needs NSObject or the Objective-C runtime, could you name any?

Well, there are many String methods that are implicitly bridged to NSString and aren’t available if you don’t import Foundation.

But primarily I meant that there are a lot of important features people use in writing apps in Swift, which are provided by the Objective-C runtime: KVC, KVO, looking up classes by name, proxying, dynamic (@NSManaged) properties, etc. 

Brent Simmons has been blogging about his frustrations with pure Swift, and in the most recent post decided to give up and start using NSObject features in his object model:

My main problems with Swift are:
• Collections of protocol-conforming objects don’t work as I need them to.
• No KVC.
• No equivalent of NSClassFromString.
Now, these aren’t really problems with Swift — they’re problems with pure Swift.

But there’s no such thing as a pure Swift app. The frameworks are Objective-C frameworks. You can’t load nibs without Objective-C.

Given that, I made the pragmatic decision to start using @objc protocols, classes, and collection types where those things make sense, where Swift fought against my design.

And suddenly the language is a joy to use. It’s like Objective-C but with type inference, no .h files, fewer imports, shorter syntax — and I get the things I was missing.

—Jens

Jeremy Pereira

unread,
Aug 19, 2015, 11:10:08 AM8/19/15
to Jens Alfke, Bruno Berisso, Swift Language

> On 12 Aug 2015, at 18:27, Jens Alfke <je...@mooseyard.com> wrote:
>
>
> Brent Simmons has been blogging about his frustrations with pure Swift, and in the most recent post decided to give up and start using NSObject features in his object model:

An interesting series. However, I know the answer to Swift Diary #7 and it's really bugging me that I can't comment on his blog to tell him what the problem is. Here is the answer in the hope that he reads this mailing list.

This is Swift Diary #7

http://inessential.com/2015/08/02/swift_diary_7_protocols_arrays_and_c

He has this code

protocol NodeRepresentedObject : class {
var children: [NodeRepresentedObject]? {get}
}

protocol EmailMessage : NodeRepresentedObject {
// stuff here…
}

class Mailbox : NodeRepresentedObject {
var messages = [EmailMessage]()
var children: [NodeRepresentedObject]? {
get {
return messages
}
}
}

But it errors on "return messages" because messages is of type [EmailMessage] not type [NodeRepresentedObject]

That seems crazy until you realise that, given the protocol declaration, it should be legal to do the following

if let children = myMailBox.children
{
children.append(someArbitraryNodeRepresentedObjectThatIsNotAnEmailMessage)
}



>
>

Jeremy Pereira

unread,
Aug 19, 2015, 11:19:20 AM8/19/15
to Jens Alfke, Bruno Berisso, Swift Language

> On 19 Aug 2015, at 16:10, Jeremy Pereira <jeremy.j...@googlemail.com> wrote:
>
>
> That seems crazy until you realise that, given the protocol declaration, it should be legal to do the following
>
> if let children = myMailBox.children
> {
> children.append(someArbitraryNodeRepresentedObjectThatIsNotAnEmailMessage)
> }
>

Oops, should have tested it, that won't work. You need to make a mutable copy or something.

>
>
>>
>>
>

Reply all
Reply to author
Forward
0 new messages