Regression in Xcode8-beta6 Swift?


(Travis Griggs) #1

Upgrading to beta6 of Xcode8, I’ve read through various SE’s and made fixes as appropriate, but the following behavior I didn’t catch an explanation as to why its now an error where it was fine before.

In a ViewController, I have something that looks like:

    var addButton = UIButton(type: .custom)
    var addPrompt = UILabel()
    var timesButton = UIButton(type: .system)
    var removeButton = UIButton(type: .system)
    var menuButton = UIButton(type: .system)
  
    func commonInit() {
        [self.addButton, self.addPrompt, self.timesButton, self.removeButton, self.menuButton].forEach { control in
            control.sizeToFit()
            self.addSubview(control)
    }

This code was fine until the latest update. It seemed to a heterogenous array of UILabel and UIButtons was a homogeneous array of UIView objects. But now I get the errors:

    Value of type ‘Any’ has no member ‘sizeToFit'
    Cannot covert value of type ‘Any’ to expected argument type of ‘UIView’

This seems like it might be related to SE-0116 (Import Objective-C id as Swift Any ) but I’m not sure why the inferencer can no longer find the shared parent type, where it could before.

Aside, I can fix it by simply helping it a little, e.g.

    [self.addButton, self.addPrompt, self.timesButton, self.removeButton, self.menuButton].forEach { (control:UIView) in...

But remain curious why the inferencer can’t handle this for me anymore.


(David Hart) #2

You can’t call arbitrary functions on AnyObject anymore. Previously, you could do this:

let a: AnyObject = UIView()
a.hasPrefix(“test”) // This compiled (because hasPrefix(:_) exists on NSString), but would obviously crash

This is not allowed anymore.

···

On 25 Aug 2016, at 03:33, Travis Griggs via swift-users <swift-users@swift.org> wrote:

Upgrading to beta6 of Xcode8, I’ve read through various SE’s and made fixes as appropriate, but the following behavior I didn’t catch an explanation as to why its now an error where it was fine before.

In a ViewController, I have something that looks like:

   var addButton = UIButton(type: .custom)
   var addPrompt = UILabel()
   var timesButton = UIButton(type: .system)
   var removeButton = UIButton(type: .system)
   var menuButton = UIButton(type: .system)
  
   func commonInit() {
       [self.addButton, self.addPrompt, self.timesButton, self.removeButton, self.menuButton].forEach { control in
           control.sizeToFit()
           self.addSubview(control)
   }

This code was fine until the latest update. It seemed to a heterogenous array of UILabel and UIButtons was a homogeneous array of UIView objects. But now I get the errors:

   Value of type ‘Any’ has no member ‘sizeToFit'
   Cannot covert value of type ‘Any’ to expected argument type of ‘UIView’

This seems like it might be related to SE-0116 (Import Objective-C id as Swift Any ) but I’m not sure why the inferencer can no longer find the shared parent type, where it could before.

Aside, I can fix it by simply helping it a little, e.g.

   [self.addButton, self.addPrompt, self.timesButton, self.removeButton, self.menuButton].forEach { (control:UIView) in...

But remain curious why the inferencer can’t handle this for me anymore.

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


(Quinn “The Eskimo!”) #3

You’re mixing up `Any` and `AnyObject`. You can still call arbitrary methods on `AnyObject`, as Martin demonstrated, but Travis’s error message referenced `Any`.

SE-0116 [1] means that `Any` is a lot more common these days.

Notwithstanding the above, I don’t have any input on the change of behaviour Travis is seeing.

Share and Enjoy

···

On 25 Aug 2016, at 08:23, David Hart via swift-users <swift-users@swift.org> wrote:

You can’t call arbitrary functions on AnyObject anymore.

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1] <https://github.com/apple/swift-evolution/blob/master/proposals/0116-id-as-any.md>


(Martin R) #4

Did that change recently? In Xcode 8 beta 6

    let a: AnyObject = UIView()
    a.hasPrefix("test")

still compiles (but of course crashes at runtime).

Martin

···

Am 25.08.2016 um 09:23 schrieb David Hart via swift-users <swift-users@swift.org>:

You can’t call arbitrary functions on AnyObject anymore. Previously, you could do this:

let a: AnyObject = UIView()
a.hasPrefix(“test”) // This compiled (because hasPrefix(:_) exists on NSString), but would obviously crash

This is not allowed anymore.

On 25 Aug 2016, at 03:33, Travis Griggs via swift-users <swift-users@swift.org> wrote:

Upgrading to beta6 of Xcode8, I’ve read through various SE’s and made fixes as appropriate, but the following behavior I didn’t catch an explanation as to why its now an error where it was fine before.

In a ViewController, I have something that looks like:

  var addButton = UIButton(type: .custom)
  var addPrompt = UILabel()
  var timesButton = UIButton(type: .system)
  var removeButton = UIButton(type: .system)
  var menuButton = UIButton(type: .system)
  
  func commonInit() {
      [self.addButton, self.addPrompt, self.timesButton, self.removeButton, self.menuButton].forEach { control in
          control.sizeToFit()
          self.addSubview(control)
  }

This code was fine until the latest update. It seemed to a heterogenous array of UILabel and UIButtons was a homogeneous array of UIView objects. But now I get the errors:

  Value of type ‘Any’ has no member ‘sizeToFit'
  Cannot covert value of type ‘Any’ to expected argument type of ‘UIView’

This seems like it might be related to SE-0116 (Import Objective-C id as Swift Any ) but I’m not sure why the inferencer can no longer find the shared parent type, where it could before.

Aside, I can fix it by simply helping it a little, e.g.

  [self.addButton, self.addPrompt, self.timesButton, self.removeButton, self.menuButton].forEach { (control:UIView) in...

But remain curious why the inferencer can’t handle this for me anymore.

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

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


(David Hart) #5

That proposal also says:
Deciding the fate of AnyObject lookup

We currently bestow the AnyObject existential type with the special ability to look up any @objc method dynamically, in order to ensure id-based ObjC APIs remain fluent when used in Swift. This is another special, unprincipled, nonportable feature that relies on the Objective-C runtime. If we change id to bridge to Any, it definitely no longer makes sense to apply to AnyObject. A couple of possibilities to consider:

We could transfer the existing AnyObject behavior verbatim to Any.
We could attempt to eliminate the behavior as a language feature. An approximation of AnyObject's magic behavior can be made using operators and unapplied method references, in a way that also works for Swift types:

  /// Dynamically dispatch a method on Any.
  func => <T, V>(myself: Any, method: (T) -> V) -> V? {
    if let myself = myself as? T {
      return method(myself)
    }
    return nil
  }
though that's not quite the right thing for id lookup, since you want a respondsToSelector rather than isKindOfClass check.

We could narrow the scope of the behavior. Jordan has suggested allowing only property and subscript lookup off of AnyObject or Any, as a way of allowing easy navigation of property lists, one of the most common sources of id in Foundation.
If we're confident that the SDK will be sufficiently Swiftified that ids become relatively rare, maybe we could get away without a replacement at all.
What was decided concerning that? I felt sure that the lookup had been completely removed, but I’m obviously mistaken.

David.

···

On 25 Aug 2016, at 09:59, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

On 25 Aug 2016, at 08:23, David Hart via swift-users <swift-users@swift.org> wrote:

You can’t call arbitrary functions on AnyObject anymore.

You’re mixing up `Any` and `AnyObject`. You can still call arbitrary methods on `AnyObject`, as Martin demonstrated, but Travis’s error message referenced `Any`.

SE-0116 [1] means that `Any` is a lot more common these days.

Notwithstanding the above, I don’t have any input on the change of behaviour Travis is seeing.

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1] <https://github.com/apple/swift-evolution/blob/master/proposals/0116-id-as-any.md>

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


(Quinn “The Eskimo!”) #6

That proposal also says:

Indeed. Good point.

What was decided concerning that?

I don’t know, although given that that text was from the “Future Directions” section it seems like that nothing has changed yet.

Share and Enjoy

···

On 25 Aug 2016, at 09:27, David Hart <david@hartbit.com> wrote:
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(David Hart) #7

I misunderstood the release notes for Xcode 8 beta 6 I read a few days ago. Here what will interest you:

Since ‘id’ now imports as ‘Any’ rather than ‘AnyObject’, you may see errors where you were previously performing dynamic lookup on ‘AnyObject’. For example in:

      guard let fileEnumerator = FileManager.default.enumerator(atPath: path)
      else {
return }

      for fileName in fileEnumerator {
          if fileName.hasSuffix(".txt") {
              // error: value of type ‘Element’ (aka ‘Any’) has no member
      hasSuffix
              print(fileName)
          }
}
The fix is to either cast to AnyObject explicitly before doing the dynamic lookup, or force cast to a

specific object type:

      guard let fileEnumerator = FileManager.default.enumerator(atPath: path)
      else {
return }

      for fileName in fileEnumerator {
          if (fileName as AnyObject).hasSuffix(".txt") {
              // cast to AnyObject
              print(fileName)
          }
}

(27639935)

···

On 25 Aug 2016, at 10:32, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

On 25 Aug 2016, at 09:27, David Hart <david@hartbit.com> wrote:

That proposal also says:

Indeed. Good point.

What was decided concerning that?

I don’t know, although given that that text was from the “Future Directions” section it seems like that nothing has changed yet.

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

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