Argument of '#selector' cannot refer to a property?


(David Hart) #1

I’ve played with the new #selector syntax and am loving it. But I often want to use it as a way to provide strong-typing to APIs which require String representations of properties. For example:

class Model: NSObject {
  dynamic var firstName: String = ""
  dynamic var lastName: String = ""
}

extension Model {
  var jsonValue: [String:AnyObject] {
    return [
      #selector(self.firstName): firstName,
      #selector(self.lastName): lastName
    ]
  }
}

extension Model {
  func modelWithName(name: String) {
    return Database.execute("SELECT * FROM Model WHERE \(#selector(self.firstName)) = ? OR \(#selector(self.lastName)) = ?")
  }
}

But there are currently two problems with this:

1) The compiler doesn’t accept #selector of properties with the error message: Argument of '#selector' cannot refer to a property. What’s the reasoning for that?
2) Even if it did, I would still have the wrap #selector with NSStringFromSelector. It would be really convenient if Selector objects would convert to String. How is that possible?


(Jordan Rose) #2

I’ve played with the new #selector syntax and am loving it. But I often want to use it as a way to provide strong-typing to APIs which require String representations of properties. For example:

class Model: NSObject {
  dynamic var firstName: String = ""
  dynamic var lastName: String = ""
}

extension Model {
  var jsonValue: [String:AnyObject] {
    return [
      #selector(self.firstName): firstName,
      #selector(self.lastName): lastName
    ]
  }
}

extension Model {
  func modelWithName(name: String) {
    return Database.execute("SELECT * FROM Model WHERE \(#selector(self.firstName)) = ? OR \(#selector(self.lastName)) = ?")
  }
}

But there are currently two problems with this:

1) The compiler doesn’t accept #selector of properties with the error message: Argument of '#selector' cannot refer to a property. What’s the reasoning for that?

It's not obvious whether you want the selector of the getter or the selector of the setter. It is a hole, though. Doug, did you have any comments here?

2) Even if it did, I would still have the wrap #selector with NSStringFromSelector. It would be really convenient if Selector objects would convert to String. How is that possible?

I'm not sure why this would make sense. Selectors are not strings. (However, they are CustomStringConvertible, so you can just use "String(…)" to convert them.)

Jordan

···

On Feb 21, 2016, at 1:19, David Hart via swift-evolution <swift-evolution@swift.org> wrote:


(Brent Royal-Gordon) #3

1) The compiler doesn’t accept #selector of properties with the error message: Argument of '#selector' cannot refer to a property. What’s the reasoning for that?

Because in Objective-C, a property is syntactic sugar for a pair of accessor methods, but in Swift, a property is a completely distinct entity from a method.

2) Even if it did, I would still have the wrap #selector with NSStringFromSelector. It would be really convenient if Selector objects would convert to String. How is that possible?

It isn't appropriate. A selector is a different type from a string. Even Objective-C doesn't let you do this.

Basically, both of these are instances of you wanting vastly looser semantics. That's just not in Swift's nature.

A different way to approach this whole problem is to use strings instead of selectors for your field names, which allows you to use traditional Key-Value Coding:

  class Model: NSObject {
    dynamic var firstName: String = ""
    dynamic var lastName: String = ""
  }
  
  extension Model {
    static var jsonFields = ["firstName", "lastName"]
    
    var jsonValue: [String: AnyObject] {
      return dictionaryWithValuesForKeys(Model.jsonFields)
    }
  }

You could even protocolize it for reusability:

  protocol JSONRepresentable {
    static var jsonFields: [String] { get }
    var jsonValue: [String: AnyObject] { get }
  }
  
  extension JSONRepresentable where Self: NSObject {
    var jsonValue: [String: AnyObject] {
      return dictionaryWithValuesForKeys(Self.jsonFields)
    }
  }
  
  class Model: NSObject {
    dynamic var firstName: String = ""
    dynamic var lastName: String = ""
  }
  
  extension Model: JSONRepresentable {
    static var jsonFields = ["firstName", "lastName"]
  }

That solves both problems, though you lose the typo checking that #selector might provide.

···

--
Brent Royal-Gordon
Architechies


(David Hart) #4

I’ll write it up.

···

On 22 Feb 2016, at 23:25, Douglas Gregor <dgregor@apple.com> wrote:

On Feb 22, 2016, at 2:24 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Feb 22, 2016, at 2:18 PM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

On Feb 22, 2016, at 2:14 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Feb 22, 2016, at 2:09 PM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

On Feb 22, 2016, at 1:50 PM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

Is a design for lenses imaginable for Swift 3.0 or is that completely out of scope?

I was going to say “imaginable”, but property behaviors is taking up far more design and engineering time than I’d hoped, and at this point I’m expecting lenses to fall off the Swift 3 schedule. JoeG might have more insight here.

Yeah, I don't think lenses will fit into Swift 3 at this point. Since we've taken a special #-form for selector references, I wouldn't feel too bad about inventing some ad-hoc syntax for naming the get and set selectors for an @objc property.

Something like #selector(getter: <PROPERTY>) and #selector(setter: <PROPERTY>) would fit easily enough.

SGTM.

Someone want to write this up as a follow-on proposal?

  - Doug


(Douglas Gregor) #5

Thanks!

···

Sent from my iPhone

On Feb 22, 2016, at 11:14 PM, David Hart <david@hartbit.com> wrote:

I’ll write it up.

On 22 Feb 2016, at 23:25, Douglas Gregor <dgregor@apple.com> wrote:

On Feb 22, 2016, at 2:24 PM, Joe Groff <jgroff@apple.com> wrote:

On Feb 22, 2016, at 2:18 PM, Douglas Gregor <dgregor@apple.com> wrote:

On Feb 22, 2016, at 2:14 PM, Joe Groff <jgroff@apple.com> wrote:

On Feb 22, 2016, at 2:09 PM, Douglas Gregor <dgregor@apple.com> wrote:

On Feb 22, 2016, at 1:50 PM, David Hart <david@hartbit.com> wrote:

Is a design for lenses imaginable for Swift 3.0 or is that completely out of scope?

I was going to say “imaginable”, but property behaviors is taking up far more design and engineering time than I’d hoped, and at this point I’m expecting lenses to fall off the Swift 3 schedule. JoeG might have more insight here.

Yeah, I don't think lenses will fit into Swift 3 at this point. Since we've taken a special #-form for selector references, I wouldn't feel too bad about inventing some ad-hoc syntax for naming the get and set selectors for an @objc property.

Something like #selector(getter: <PROPERTY>) and #selector(setter: <PROPERTY>) would fit easily enough.

SGTM.

Someone want to write this up as a follow-on proposal?

  - Doug