methods - programacion - swift functions parameters
Propiedad de solo lectura calculada frente a función en Swift (9)
En la sesión de Introduction to Swift WWDC, se muestra una description
propiedad de solo lectura:
class Vehicle {
var numberOfWheels = 0
var description: String {
return "/(numberOfWheels) wheels"
}
}
let vehicle = Vehicle()
println(vehicle.description)
¿Hay alguna implicación para elegir el enfoque anterior sobre el uso de un método en su lugar?
class Vehicle {
var numberOfWheels = 0
func description() -> String {
return "/(numberOfWheels) wheels"
}
}
let vehicle = Vehicle()
println(vehicle.description())
Me parece que las razones más obvias por las que elegiría una propiedad computada de solo lectura son:
- Semántica : en este ejemplo, tiene sentido que la
description
sea una propiedad de la clase, en lugar de una acción que realiza. - Brevedad / Claridad : evita la necesidad de usar paréntesis vacíos al obtener el valor.
Claramente, el ejemplo anterior es demasiado simple, pero ¿hay otras buenas razones para elegir una sobre la otra? Por ejemplo, ¿hay algunas características de funciones o propiedades que guiarían su decisión de cuál usar?
NB: A primera vista, esta parece ser una pregunta OOP muy común, pero estoy ansioso por conocer las características específicas de Swift que guiarían las mejores prácticas al usar este lenguaje.
Bueno, puedes aplicar los consejos de Kotlin https://kotlinlang.org/docs/reference/coding-conventions.html#functions-vs-properties .
En algunos casos, las funciones sin argumentos pueden ser intercambiables con propiedades de solo lectura. Aunque la semántica es similar, existen algunas convenciones estilísticas sobre cuándo preferir uno a otro.
Prefiere una propiedad sobre una función cuando el algoritmo subyacente:
- no tira
- tiene un O (1)
- la complejidad es barata de calcular (o cansa en la primera ejecución)
- devuelve el mismo resultado sobre las invocaciones
Dado que el tiempo de ejecución es el mismo, esta pregunta también se aplica a Objective-C. Yo diría que con propiedades obtienes
- una posibilidad de agregar un setter en una subclase, haciendo que la propiedad
readwrite
- la capacidad de usar KVO /
didSet
para las notificaciones de cambio - de forma más general, puede pasar la propiedad a métodos que esperan rutas clave, por ejemplo, buscar orden de búsqueda
En cuanto a algo específico para Swift, el único ejemplo que tengo es que puedes usar @lazy
para una propiedad.
En el caso de solo lectura, una propiedad calculada no debe considerarse semánticamente equivalente a un método, incluso cuando se comportan de forma idéntica, ya que func
declaración func
difumina la distinción entre cantidades que comprenden el estado de una instancia y cantidades que son meramente funciones de el estado. Guarda el tipeo ()
en el sitio de llamadas, pero corre el riesgo de perder claridad en su código.
Como ejemplo trivial, considere el siguiente tipo de vector:
struct Vector {
let x, y: Double
func length() -> Double {
return sqrt(x*x + y*y)
}
}
Al declarar la longitud como un método, está claro que es una función del estado, que solo depende de y
.
Por otro lado, si expresara la length
como una propiedad calculada
struct VectorWithLengthAsProperty {
let x, y: Double
var length: Double {
return sqrt(x*x + y*y)
}
}
luego, cuando puntee-tab-complete en su IDE en una instancia de VectorWithLengthAsProperty
, parecería que x
, y
, length
son propiedades en igualdad de condiciones, lo cual es conceptualmente incorrecto.
Existe una diferencia: si usa una propiedad, puede anularla y hacerla leer / escribir en una subclase.
Hay situaciones en las que preferiría la propiedad calculada sobre las funciones normales. Tales como: devolver el nombre completo de una persona. Ya sabes el primer nombre y el apellido. Entonces realmente la propiedad fullName
es una propiedad, no una función. En este caso, se trata de una propiedad calculada (porque no puede establecer el nombre completo, solo puede extraerlo usando el nombre y el apellido)
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
Históricamente, la descripción es una propiedad en NSObject y muchos esperarían que continúe igual en Swift. Agregar parens después de eso solo agregará confusión.
EDITAR: Después de downvoting furioso tengo que aclarar algo - si se accede a través de la sintaxis de puntos, se puede considerar una propiedad. No importa lo que hay debajo del capó. No puede acceder a los métodos habituales con la sintaxis de puntos.
Además, llamar a esta propiedad no requería paréntesis adicionales, como en el caso de Swift, lo que puede generar confusión.
Me parece que es sobre todo una cuestión de estilo: prefiero usar propiedades precisamente para eso: propiedades; es decir, valores simples que puede obtener y / o configurar. Utilizo funciones (o métodos) cuando realizo el trabajo real. Tal vez algo tiene que ser computado o leído desde el disco o desde una base de datos: en este caso utilizo una función, incluso cuando solo se devuelve un valor simple. De esta forma, puedo ver fácilmente si una llamada es barata (propiedades) o posiblemente costosa (funciones).
Probablemente obtengamos más claridad cuando Apple publique algunas convenciones de codificación Swift.
Semánticamente hablando, las propiedades calculadas deben estar estrechamente vinculadas con el estado intrínseco del objeto; si otras propiedades no cambian, la consulta de la propiedad calculada en diferentes momentos debe dar el mismo resultado (comparable a través de == o ===) - similar llamar a una función pura en ese objeto.
Los métodos, por otro lado, salen de la caja con la suposición de que no siempre obtendremos los mismos resultados, porque Swift no tiene una forma de marcar las funciones como puras. Además, los métodos en OOP se consideran acciones, lo que significa que su ejecución debería tener un efecto secundario. Si el método no tiene efectos secundarios, puede convertirse de manera segura en una propiedad calculada.
Tenga en cuenta que ambas afirmaciones anteriores son puramente desde una perspectiva semántica, ya que bien podría suceder que las propiedades calculadas tengan efectos secundarios que no esperamos y que los métodos sean puros.
Si bien la cuestión de las propiedades calculadas frente a los métodos en general es difícil y subjetiva, actualmente hay un argumento importante en el caso de Swift para preferir los métodos a las propiedades. Puede usar métodos en Swift como funciones puras, lo que no es cierto para las propiedades (a partir de Swift 2.0 beta). Esto hace que los métodos sean mucho más potentes y útiles ya que pueden participar en la composición funcional.
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)))