66

I'm new to backend Swift and thought I'd use Vapor to get up-and-running on a side project fast... I ran vapor new WebServer --template=auth-template, and now I'm trying to figure out what something like return \.email means. For more context, I'm looking in WebServer > Sources > App > Models > Users.swift:

import Authentication
import FluentSQLite
import Vapor

/// Allows users to be verified by basic / password auth middleware.
extension User: PasswordAuthenticatable {
    /// See `PasswordAuthenticatable`.
    static var usernameKey: WritableKeyPath<User, String> {
        return \.email
    }

// ...
}

And here is the definition of the User class:

/// A registered user, capable of owning todo items.
final class User: SQLiteModel {
    // {omit extra code} ...

    var email: String

    // {omit extra code} ...

    /// Creates a new `User`.
    init(id: Int? = nil, name: String, email: String, passwordHash: String) {
        // {omit extra code} ...
        self.email = email
        // {omit extra code} ...
    }
}

What does this backslash-dot notation mean?

user3773048
  • 5,839
  • 4
  • 18
  • 22

2 Answers2

56

tl;dr: We take a look at the Swift language reference, and sure enough, the usage of this backslash-dot notation is called a key-path-expression.

(The question has been sufficiently answered, by this point.)

A more hands-on approach on how to get to that piece of buried documentation:

As you can see from the code you posted, the User class contains a property named email.

Notice that, assuming you're using Xcode, if you replace return \.email with return \, you get the compile-error "Expected expression path in Swift key path", so this is a hint that this backslash-dot notation might have to do with something called a key path.

From that documentation on key-path, we see that we could also have written \User.email (and you can try it out in Xcode with no compiler error).

Understanding the greater context of what's going on in that code:

So, semantically, to understand the meaning of the usernameKey declaration you're looking at, we might want to understand what a WritableKeyPath is. In simple, from the documentation, we see that a WritableKeyPath is: "A key path that supports reading from and writing to the resulting value."

So, we see that the usernameKey declaration takes in a WritableKeyPath object and returns a String that is User.email.

Furthermore, it's apparent that the User class needs this usernameKey property in order to conform to the PasswordAuthenticatable protocol, which was imported on the first line with import Authentication (if you care to explore there, take a look at Dependencies > Auth 2.0.0 > Authentication > Basic > BasicAuthenticatable.swift).

brotskydotcom
  • 665
  • 7
  • 10
user3773048
  • 5,839
  • 4
  • 18
  • 22
  • 17
    Specifically, using `\.property` is just shorthand for `\Type.property`. Swift can usually infer what the root type is you are using, but sometimes you do have to type out the whole key-path. – Caleb Kleveter Sep 27 '18 at 20:32
  • @CalebKleveter's comment is the crucial information that this “accepted” answer elides: type inference. The “accepted” answer could focus instead on type inference as the core concept to actually •communicate•. And user3773048 answered its own question & accepted its own answer. CalebKleveter's comment should have been the accepted answer had it been elevated to answer status instead of being merely a comment. – Andreas ZUERCHER Mar 25 '21 at 18:46
  • It should be prohibited on this platform to submit one's own question, then write one's own answer, and then accept one's own answer. It is incestuous, such as to artificially inflate one's reputation point score. If not prohibited, then it should result in zero quantitative effect on reputation score. – Andreas ZUERCHER Mar 25 '21 at 18:48
  • 2
    @AndreasZUERCHER Accepting your own answer does not increase your reputation level. If you answer your own question, you can only gain from that answer if other people upvote it. – Caleb Kleveter Mar 26 '21 at 12:55
  • @CalebKleveter, it was upvoted 32 times. Actually 33 until my downvote for not mentioning the core answer among all its strongly definitive language. – Andreas ZUERCHER Mar 26 '21 at 12:57
  • 4
    @AndreasZUERCHER https://stackoverflow.com/help/self-answer – Caleb Kleveter Mar 26 '21 at 16:45
  • 5
    ^ yeah, self-answer. I was also legitimately wondering about that at the time, and I didn't find much online, so I decided to post a Q-A so that it's easy to find for those who prefer having the availability of a StackOverflow answer. @AndreasZUERCHER Feel free to answer with a better answer; it may be a helpful alternative perspective for those interested in this question. – user3773048 Mar 27 '21 at 00:14
  • 1
    Yes, I will. I am pondering what else I can add. @user3773048, your answer is excellent regarding what it says. I'll figure out a parallel flight path in formation with yours so that they complement each other. – Andreas ZUERCHER Mar 27 '21 at 00:58
-1

[Swift Key Value Coding (KVC)]

This syntax(\<path_to_type_property>) is used to specify KeyPath and allows to check this path in compile time(Objective-C used String to specify it).

What we can get from it:

//`WritableKeyPath` allows in addition to read also write to this property 
//Value Path is User.email
//Root Type is User
//Value Type is String as a result of .email 
var usernameKey: WritableKeyPath<User, String> = \.email
//or
var usernameKey: WritableKeyPath<User, String> = \User.email

How it can be used like:

//read
let userEmail = someUser[keyPath: usernameKey]

//write
someUser[keyPath: usernameKey] = "foo@gmail.com"
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
  • Why post the same basic answer on two questions? Why not vote to close one question as a duplicate of the other instead? – HangarRash Aug 19 '23 at 17:26