Вычислимое свойство только для чтения vs функция в Swift

В сеансе Введение в Swift WWDC показано свойство description только для чтения:

class Vehicle {
    var numberOfWheels = 0
    var description: String {
        return "\(numberOfWheels) wheels"
    }
}

let vehicle = Vehicle()
println(vehicle.description)

Есть ли какие-либо последствия для выбора вышеупомянутого подхода с использованием метода:

class Vehicle {
    var numberOfWheels = 0
    func description() -> String {
        return "\(numberOfWheels) wheels"
    }
}

let vehicle = Vehicle()
println(vehicle.description())

Мне кажется, что наиболее очевидными причинами, по которым вы выбрали вычисляемое свойство только для чтения, являются:

  • Семантика - в этом примере для description имеет смысл свойство класса, а не действие, которое оно выполняет.
  • Краткость/Ясность - предотвращает необходимость использования пустых круглых скобок при получении значения.

Очевидно, что приведенный выше пример слишком прост, но есть ли другие веские причины выбирать один за другим? Например, существуют ли какие-то функции функций или свойств, которые могли бы определять ваше решение?


N.B. На первый взгляд это кажется довольно распространенным вопросом ООП, но я заинтересован в том, чтобы узнать какие-либо особенности, зависящие от Swift, которые наилучшим образом помогут при использовании этого языка.

Ответ 1

Мне кажется, что это в основном вопрос стиля: я предпочитаю использовать свойства только для: свойств; что означает простые значения, которые вы можете получить и/или установить. Я использую функции (или методы), когда выполняется фактическая работа. Возможно, что-то нужно вычислять или читать с диска или из базы данных: в этом случае я использую функцию, даже когда возвращается только простое значение. Таким образом, я могу легко увидеть, дешев (свойства) или, возможно, дорогой (функции).

Мы, вероятно, получим больше ясности, когда Apple опубликует некоторые соглашения о кодировании Swift.

Ответ 2

В то время как вопрос о вычисленных свойствах против методов в целом является жестким и субъективным, в настоящее время в случае Swift существует один важный аргумент для предпочтения методов над свойствами. Вы можете использовать методы в Swift как чистые функции, которые не соответствуют свойствам (как и для Swift 2.0 beta). Это делает методы намного более мощными и полезными, поскольку они могут участвовать в функциональной композиции.

func fflat<A, R>(f: (A) -> () -> (R)) -> (A) -> (R) {
    return { f($0)() }
}

func fnot<A>(f: (A) -> Bool) -> (A) -> (Bool) {
    return { !f($0) }
}

extension String {
    func isEmptyAsFunc() -> Bool {
        return isEmpty
    }
}

let strings = ["Hello", "", "world"]

strings.filter(fnot(fflat(String.isEmptyAsFunc)))

Ответ 3

Есть разница: Если вы используете свойство, вы можете в конечном итоге переопределить его и сделать его чтение/запись в подклассе.

Ответ 4

Поскольку время выполнения одинаково, этот вопрос относится и к Objective-C. Я бы сказал, со свойствами вы получите

  • возможность добавления сеттера в подкласс, создавая свойство readwrite
  • возможность использования KVO/ didSet для уведомлений об изменениях
  • В более общем плане вы можете передать свойство методам, которые ожидают ключевые пути, например. сортировка запроса выборки

Что касается чего-то определенного для Swift, единственный пример, который у меня есть, это то, что вы можете использовать @lazy для свойства.

Ответ 5

Хорошо, вы можете использовать советы Kotlin https://kotlinlang.org/docs/reference/coding-conventions.html#functions-vs-properties.

В некоторых случаях функции без аргументов могут быть взаимозаменяемыми с свойствами только для чтения. Хотя семантика подобна, являются некоторыми стилистическими соглашениями о том, когда следует отдать предпочтение друг другу.

Предпочитает свойство над функцией, когда базовый алгоритм:

  • не бросает
  • имеет O (1)
  • сложность дешево вычислять (или закрывать при первом запуске)
  • возвращает тот же результат по вызовам

Ответ 6

Бывают ситуации, когда вы предпочли бы вычисленное свойство над нормальными функциями. Например: возвращение полного имени человека. Вы уже знаете имя и фамилию. Таким образом, свойство fullName является не функцией. В этом случае это вычисленное свойство (поскольку вы не можете установить полное имя, вы можете просто извлечь его с использованием имени и последнего имени)

class Person{
    let firstName: String
    let lastName: String
    init(firstName: String, lastName: String){
        self.firstName = firstName
        self.lastName = lastName
    }
    var fullName :String{
        return firstName+" "+lastName
    }
}
let william = Person(firstName: "William", lastName: "Kinaan")
william.fullName //William Kinaan

Ответ 7

Исторически описание является свойством в NSObject, и многие ожидали бы, что он продолжит то же самое в Swift. Добавление parens после этого только добавит путаницу.

EDIT: После яростного downvoting я должен что-то прояснить - если к нему обращаются через точечный синтаксис, его можно считать свойством. Неважно, что под капотом. Вы не можете получить доступ к обычным методам с точечным синтаксисом.

Кроме того, вызов этого свойства не требовал дополнительных парнеров, например, в случае Swift, что может привести к путанице.