Los operadores "++" y "-" han quedado en desuso Xcode 7.3

139

Estoy mirando las notas de Xcode 7.3 y noto este problema.

Los operadores ++ y - han quedado en desuso

¿Podría alguien explicar por qué está en desuso? Y estoy en lo cierto, en la nueva versión de Xcode ahora vas a usar en lugar de ++esto x += 1;

Ejemplo:

for var index = 0; index < 3; index += 1 {
    print("index is \(index)")
}

Captura de pantalla para advertencia

Oleg Gordiichuk
fuente
66
Creo que esta pregunta está fuera del alcance del stackoverflow principalmente porque toda la propuesta aceptada para la evolución rápida se puede encontrar en Github, puede leer más sobre el por qué de esta propuesta github.com/apple/swift-evolution/blob/master / propuestas / ...
Victor Sigler
77
Estoy considerando seriamente regresar a Objective-C. No vale la pena intentar mantenerse al día con todos los cambios en Swift.
Greg Brown
3
@OlegGordiichuk Es lo que hacen los bucles for, ya que también se eliminaría el estilo C, mira este github.com/Vkt0r/swift-evolution/blob/master/proposals/… para que no necesites usar más++-- operadores y
Victor Sigler
10
Hay demasiados cambios importantes para mi gusto. Estoy a favor de las mejoras, pero realmente no quiero pasar mi tiempo reescribiendo porciones sustanciales de mi base de código cada vez que sale un lanzamiento de punto Xcode.
Greg Brown
44
@Fogmeister No estoy seguro de cómo podría ser más claro. Prefiero usar Swift, pero no creo que sea lo suficientemente estable. He trabajado extensamente con otros idiomas en el pasado y nunca me he encontrado con tantos cambios importantes en un período de tiempo tan corto. Siento que Apple quiere que todos adoptemos Swift, pero lo están haciendo más difícil de lo que debería ser.
Greg Brown

Respuestas:

210

Una explicación completa aquí de Chris Lattner, el creador de Swift. Resumiré los puntos:

  1. Es otra función que debes aprender mientras aprendes Swift
  2. No mucho más corto que x += 1
  3. Swift no es C. No debería llevarlos solo para complacer a los programadores de C
  4. Su uso principal es en el estilo C para el bucle: for i = 0; i < n; i++ { ... }Swift tiene mejores alternativas, como for i in 0..<n { ... }(el estilo C para el bucle también se está apagando )
  5. Puede ser difícil de leer y mantener, por ejemplo, ¿cuál es el valor de x - ++xo foo(++x, x++)?
  6. A Chris Lattner no le gusta.

Para aquellos interesados ​​(y para evitar la pudrición de enlaces), las razones de Lattner en sus propias palabras son:

  1. Estos operadores aumentan la carga de aprender Swift como primer lenguaje de programación, o cualquier otro caso en el que aún no conozca a estos operadores de un idioma diferente.

  2. Su ventaja expresiva es mínima: x ++ no es mucho más corto que x + = 1.

  3. Swift ya se desvía de C en que =, + = y otras operaciones similares a asignaciones devuelven Void (por varias razones). Estos operadores son inconsistentes con ese modelo.

  4. Swift tiene características poderosas que eliminan muchas de las razones comunes por las que usaría ++ i en un estilo C para bucle en otros idiomas, por lo que estas se usan con poca frecuencia en un código Swift bien escrito. Estas características incluyen el bucle for-in, rangos, enumerar, mapear, etc.

  5. El código que realmente utiliza el valor del resultado de estos operadores a menudo es confuso y sutil para un lector / mantenedor de código. Alientan el código "demasiado complicado" que puede ser lindo, pero difícil de entender.

  6. Si bien Swift tiene un orden de evaluación bien definido, cualquier código que dependiera de él (como foo (++ a, a ++)) sería indeseable incluso si estuviera bien definido.

  7. Estos operadores son aplicables a relativamente pocos tipos: escalares enteros y de coma flotante, y conceptos similares a iteradores. No se aplican a números complejos, matrices, etc.

Finalmente, estos fallan la métrica de "si aún no los tuviéramos, ¿los agregaríamos a Swift 3?"

Código diferente
fuente
54
Creo que la respuesta real es la número 6. Eso está bien, nosotros (ex C, Java, ... programadores) somos lo suficientemente flexibles :-). En general, para el mundo real, la mutación, el crossover y la selección son suficientes. Yo, tú y Cris también, todos somos resultados de esos tres operadores ...
user3441734
55
Punto 5: siempre fueron dependientes de la implementación en C, y nadie con ningún sentido lo hizo. Simplemente defina el comportamiento y nos acostumbraremos. Mejor que tener que regresar y cambiar el código antiguo perfectamente bueno sin ninguna razón real.
Echelon
3
Me gusta el punto 3. No puedes ser encadenado al contrato de legado para siempre. Me encanta C pero estás creando un nuevo lenguaje de programación; tiene sentido comenzar con la pizarra tan limpia como sea necesario.
Nicolas Miari
8
Es porque a Apple le gusta obligarte a pensar como ellos. Creo que está perfectamente bien y se usa en cualquier lugar donde necesites incrementar o degradar una variable. No es algo que "tienes que aprender" que harás bien sin él. Y el n. ° 5 es solo un código mal escrito, que nunca he visto. Entonces # 6 es. Explicarlo es suficiente para hacerme rascar la cabeza y hacer una búsqueda en Google, así que gracias por perder mi tiempo Chris.
csga5000
44
@ csga5000 Ese es un argumento bastante débil considerando que puede definir el operador usted mismo si realmente lo desea. No tiene nada que ver con la manzana que quiere que la gente piense como ellos. Simplemente no se ajusta al idioma. Si ++no existiera en los lenguajes de estilo C, nadie en su sano juicio miraría el diseño de Swift 3.0 y pensaría que un ++operador sería una buena adición.
overactor
37

Me doy cuenta de que este comentario no responde la pregunta, sin embargo, puede haber personas que buscan una solución para mantener a estos operadores trabajando y tal solución se puede encontrar en la parte inferior. 😇

Yo personalmente prefiero ++y-- operadores. No puedo estar de acuerdo con la opinión de que son difíciles o difíciles de manejar. Una vez que el desarrollador comprende lo que hacen estos operadores (y estamos hablando de cosas bastante simples), el código debe ser muy claro.

En la explicación de por qué los operadores quedaron en desuso se menciona que su uso principal era en estilo C para bucles. No conozco a otros, pero personalmente no uso bucles de estilo C en absoluto y todavía hay muchos otros lugares o situaciones cuando ++o-- operador es útil.

También me gustaría mencionar que varName++devuelve un valor para que pueda usarse en elreturn mientras varName += 1que no.

Para cualquiera de ustedes que deseen mantener a estos operadores trabajando aquí, la solución es:

prefix operator ++ {}
postfix operator ++ {}

prefix operator -- {}
postfix operator -- {}


// Increment
prefix func ++(inout x: Int) -> Int {
    x += 1
    return x
}

postfix func ++(inout x: Int) -> Int {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt) -> UInt {
    x += 1
    return x
}

postfix func ++(inout x: UInt) -> UInt {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Int8) -> Int8 {
    x += 1
    return x
}

postfix func ++(inout x: Int8) -> Int8 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt8) -> UInt8 {
    x += 1
    return x
}

postfix func ++(inout x: UInt8) -> UInt8 {
    x += 1
    return (x - 1)
}
prefix func ++(inout x: Int16) -> Int16 {
    x += 1
    return x
}

postfix func ++(inout x: Int16) -> Int16 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt16) -> UInt16 {
    x += 1
    return x
}

postfix func ++(inout x: UInt16) -> UInt16 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Int32) -> Int32 {
    x += 1
    return x
}

postfix func ++(inout x: Int32) -> Int32 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt32) -> UInt32 {
    x += 1
    return x
}

postfix func ++(inout x: UInt32) -> UInt32 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Int64) -> Int64 {
    x += 1
    return x
}

postfix func ++(inout x: Int64) -> Int64 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: UInt64) -> UInt64 {
    x += 1
    return x
}

postfix func ++(inout x: UInt64) -> UInt64 {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Double) -> Double {
    x += 1
    return x
}

postfix func ++(inout x: Double) -> Double {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Float) -> Float {
    x += 1
    return x
}

postfix func ++(inout x: Float) -> Float {
    x += 1
    return (x - 1)
}

prefix func ++(inout x: Float80) -> Float80 {
    x += 1
    return x
}

postfix func ++(inout x: Float80) -> Float80 {
    x += 1
    return (x - 1)
}

prefix func ++<T : _Incrementable>(inout i: T) -> T {
    i = i.successor()
    return i
}

postfix func ++<T : _Incrementable>(inout i: T) -> T {
    let y = i
    i = i.successor()
    return y
}

// Decrement
prefix func --(inout x: Int) -> Int {
    x -= 1
    return x
}

postfix func --(inout x: Int) -> Int {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt) -> UInt {
    x -= 1
    return x
}

postfix func --(inout x: UInt) -> UInt {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Int8) -> Int8 {
    x -= 1
    return x
}

postfix func --(inout x: Int8) -> Int8 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt8) -> UInt8 {
    x -= 1
    return x
}

postfix func --(inout x: UInt8) -> UInt8 {
    x -= 1
    return (x + 1)
}
prefix func --(inout x: Int16) -> Int16 {
    x -= 1
    return x
}

postfix func --(inout x: Int16) -> Int16 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt16) -> UInt16 {
    x -= 1
    return x
}

postfix func --(inout x: UInt16) -> UInt16 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Int32) -> Int32 {
    x -= 1
    return x
}

postfix func --(inout x: Int32) -> Int32 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt32) -> UInt32 {
    x -= 1
    return x
}

postfix func --(inout x: UInt32) -> UInt32 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Int64) -> Int64 {
    x -= 1
    return x
}

postfix func --(inout x: Int64) -> Int64 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: UInt64) -> UInt64 {
    x -= 1
    return x
}

postfix func --(inout x: UInt64) -> UInt64 {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Double) -> Double {
    x -= 1
    return x
}

postfix func --(inout x: Double) -> Double {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Float) -> Float {
    x -= 1
    return x
}

postfix func --(inout x: Float) -> Float {
    x -= 1
    return (x + 1)
}

prefix func --(inout x: Float80) -> Float80 {
    x -= 1
    return x
}

postfix func --(inout x: Float80) -> Float80 {
    x -= 1
    return (x + 1)
}

prefix func --<T : BidirectionalIndexType>(inout i: T) -> T {
    i = i.predecessor()
    return i
}

postfix func --<T : BidirectionalIndexType>(inout i: T) -> T {
    let y = i
    i = i.predecessor()
    return y
}
0101
fuente
No me gusta su return (x - 1)para los operadores de postfix: en mi humilde opinión, es más limpio mantener la semántica que devuelven (una copia del) valor original en lugar de lo que obtienes si lo hacesx + 1 - 1
Alnitak
Tampoco me gusta, pero no conozco ninguna otra forma (mejor, más limpia) de hacerlo. No entiendo completamente tu segundo punto.
0101
1
Ya veo, no quería hacer eso solo por crear otra variable (o más bien constante en este caso). Si solo estamos hablando Int, el resultado de (x + 1)se desbordará, lo que interrumpirá la ejecución y, por result - 1lo tanto , ni siquiera se ejecutará. Otros tipos de datos como, Doublepor ejemplo, se comportan de manera diferente, así que necesito investigar eso.
0101
3
Puedes usar deferpara esto también. defer { x += 1 }; return x
Tim Vermeulen
44
¿por qué no usar genéricos y escribir esto en pocas líneas?
μολὼν.λαβέ
22

Apple ha eliminado el ++ y lo ha hecho mucho más simple con la otra forma tradicional.

En lugar de ++, necesitas escribir +=.

Ejemplo:

var x = 1

//Increment
x += 1 //Means x = x + 1 

De manera similar para el operador de decremento --, debe escribir-=

Ejemplo:

var x = 1

//Decrement
x -= 1 //Means x = x - 1

por for bucles:

Ejemplo de incremento:

En vez de

for var index = 0; index < 3; index ++ {
    print("index is \(index)")
}

Puedes escribir:

//Example 1
for index in 0..<3 {
    print("index is \(index)")
}

//Example 2
for index in 0..<someArray.count {
    print("index is \(index)")
}

//Example 3
for index in 0...(someArray.count - 1) {
    print("index is \(index)")
}

Ejemplo de decremento:

for var index = 3; index >= 0; --index {
   print(index)
}

Puedes escribir:

for index in 3.stride(to: 1, by: -1) {
   print(index)
}
//prints 3, 2

for index in 3.stride(through: 1, by: -1) {
   print(index)
}
//prints 3, 2, 1

for index in (0 ..< 3).reverse() {
   print(index)
}

for index in (0 ... 3).reverse() {
   print(index)
}

¡Espero que esto ayude!

Sohil R. Memon
fuente
No han reemplazado nada; +=Estuve allí todo el tiempo.
Nicolas Miari
@NicolasMiari Sí, solo edito con el formato mucho mejor
Sohil R. Memon
@NicolasMiari ¿Puedes verificar ahora?
Sohil R. Memon
3
¿Qué hay de ++iy --i?
Zigii Wong
7

Chris Lattner ha ido a la guerra contra ++ y -. Él escribe: “El código que realmente utiliza el valor del resultado de estos operadores a menudo es confuso y sutil para un lector / mantenedor de código. Fomentan el código "demasiado complicado" que puede ser lindo, pero difícil de entender ... Si bien Swift tiene un orden de evaluación bien definido, cualquier código que dependiera de él (como foo (++ a, a ++)) sería indeseable incluso si estaba bien definido ... estos fallan la métrica de "si aún no los tuviéramos, ¿los agregaríamos a Swift 3?"

Apple quería mantener rápido un lenguaje limpio, claro, no confuso y directo al grano. Y por eso desaprobaron ++ y - palabra clave.

Jay Mehta
fuente
9
¿Limpiar? Mira este infierno de devolución de llamada y llámalo limpio? No estoy de acuerdo ... Y agregaría: deje el ++ & - solo
mcatach el
22
algo como ...for i in 0.stride(to: 10, by: 2)...o ...for i in (1...10).reverse()...esta limpio ?!
mad_manny 01 de
66
Estoy de acuerdo. El argumento "limpio" es fundamentalmente contradictorio wrt para el resto de Swift. Viniendo de Objective-C, que es objetivamente inmundo, es bastante difícil aceptar 'clean' como un objetivo del lenguaje Apple.
Adrian Bartholomew
2
Intenta analizar json y swift y dime qué tan limpio está.
nickthedude
6

Captura de pantalla para advertencia

El Fix-it featurede Xcode da una respuesta clara a esto.

Solución a la advertencia

Reemplazar ++ increment operatorcon anticuado value += 1(operador de mano corta) y -- decrement operatorconvalue -= 1

Jayprakash Dubey
fuente
6

Para Swift 4, puede restaurar los operadores ++y --como extensiones para Inty otros tipos. Aquí hay un ejemplo:

extension Int{
   static prefix func ++(x: inout Int) -> Int {
        x += 1
        return x
    }

    static postfix func ++(x: inout  Int) -> Int {
        defer {x += 1}
        return x
    }

    static prefix func --(x: inout Int) -> Int {
        x -= 1
        return x
    }

    static postfix func --(x: inout Int) -> Int {
        defer {x -= 1}
        return x
    }
}

Funciona de la misma manera para otros tipos, tales como UIInt, Int8, Float, Double, etc.

Puede pegar estas extensiones en un solo archivo en su directorio raíz, y estarán disponibles para su uso dentro de todos sus otros archivos allí.

He notado un par de votos negativos para mi respuesta aquí, casi tan pronto como la publiqué. Lo cual tomo como un desacuerdo filosófico, en lugar de criticar cómo funciona mi código. Funciona perfectamente, si lo revisas en un patio de recreo.

La razón por la que publiqué esta respuesta es porque no estoy de acuerdo con hacer que los lenguajes de programación de computadoras sean innecesariamente diferentes entre sí.

Tener muchas similitudes entre idiomas hace que sea más fácil para las personas aprender y cambiar de un idioma a otro.

Los desarrolladores normalmente usan varios lenguajes de programación, en lugar de solo uno. Y es una verdadera molestia cambiar de un idioma a otro, cuando no hay convenciones y no hay una estandarización común en todos los idiomas.

Creo que debería haber diferencias de sintaxis entre los idiomas solo tanto como sea necesario, y no más que esto.


fuente
Me encanta cuando los idiomas se "atreven" a ser diferentes. Honestamente, hay demasiados lenguajes de 'sintaxis C', y C fue diseñado hace mucho tiempo ... ha habido más de 50 años de experiencia en el lenguaje ... independientemente, ya que esta respuesta no entró en una diatriba sobre los operadores, todavía Un voto a favor.
user2864740
5

Aquí hay una versión genérica de algunos de los códigos publicados hasta ahora. Expresaría las mismas preocupaciones que los demás: es una buena práctica no usarlos en Swift. Estoy de acuerdo en que esto podría ser confuso para quienes lean su código en el futuro.

prefix operator ++
prefix operator --
prefix func ++<T: Numeric> (_ val: inout T) -> T {
    val += 1
    return val
}

prefix func --<T: Numeric> (_ val: inout T) -> T {
    val -= 1
    return val
}

postfix operator ++
postfix operator --
postfix func ++<T: Numeric> (_ val: inout T) -> T {
    defer { val += 1 }
    return val
}

postfix func --<T: Numeric> (_ val: inout T) -> T {
    defer { val -= 1 }
    return val
}

Esto también se puede escribir como una extensión en el tipo numérico.

Perro sabueso
fuente
Agregué @discardableResulta cada una de estas funciones para silenciar la advertencia sobre el valor de retorno no utilizado; de lo contrario, exactamente lo que estaba buscando.
Devin Lane,
4

De los documentos :

Los operadores de incremento / decremento en Swift se agregaron muy temprano en el desarrollo de Swift, como una transferencia de C. Estos se agregaron sin mucha consideración, y no se han pensado mucho desde entonces. Este documento proporciona una nueva mirada a ellos y, en última instancia, recomienda que los eliminemos por completo, ya que son confusos y no tienen su peso.

Dániel Nagy
fuente
En otras palabras, esta operación es demasiado cara para ser utilizada?
Oleg Gordiichuk
2
github.com/apple/swift-evolution/blob/master/proposals/… aquí puedes leer sobre esto, pero no es porque sea costoso, sino más bien por el diseño del lenguaje.
Dániel Nagy
Entonces, como andersen Swift dejará de admitir las características de estilo C
Oleg Gordiichuk
2
@OlegGordiichuk bueno, diría que quieren enfatizar que Swift no es un superconjunto de C a diferencia de Objective-C.
Dániel Nagy
1
@mah mucho de lo que dijiste simplemente no tiene sentido en absoluto. ¿"No orientado hacia los desarrolladores existentes" de qué manera? ¿De la misma manera que Java no está orientado a los desarrolladores de PHP? ¿"orientado hacia aquellos que pueden no tener la inclinación de ser desarrolladores"? Sí, porque todos los que no son desarrolladores están mordiendo la mano con programación orientada al protocolo y genéricos. "Una forma de habilitar un buen diseño" solo eche un vistazo a SO, verá que ningún lenguaje de programación puede "habilitar un buen diseño".
Fogmeister
0
var value : Int = 1

func theOldElegantWay() -> Int{
return value++
}

func theNewFashionWay() -> Int{
let temp = value
value += 1
return temp
}

Esto es definitivamente un inconveniente, ¿verdad?

paria
fuente
55
¿Quieres decir elegante como en "tienes que recordar todas las sutilezas del lenguaje de programación C, de lo contrario no es inmediatamente obvio si la primera llamada devuelve 1 o 2"? Creo que todos podemos ahorrar algunas líneas adicionales de código a cambio de no pasar varios minutos rascándonos la cabeza tratando de encontrar un error causado por un error tonto ...
Nicolas Miari
0

Como nunca trabajas realmente con punteros en Swift, en mi opinión , tiene sentido eliminar los operadores ++y --. Sin embargo, si no puede vivir sin él, puede agregar estas declaraciones de operador Swift 5+ a su proyecto:

@discardableResult
public prefix func ++<T: Numeric>(i: inout T) -> T {
    i += 1
    return i
}

@discardableResult
public postfix func ++<T: Numeric>(i: inout T) -> T {
    defer { i += 1 }
    return i
}

@discardableResult
public prefix func --<T: Numeric>(i: inout T) -> T {
    i -= 1
    return i
}

@discardableResult
public postfix func --<T: Numeric>(i: inout T) -> T {
    defer { i -= 1 }
    return i
}
Rojo lima
fuente
-3

En Swift 4.1 se podría lograr de esta manera:



    prefix operator ++
    postfix operator ++
    extension Int{
        static prefix func ++(x: inout Int)->Int{
            x += 1
            return x
        }
        static postfix func ++(x: inout Int)->Int{
            x += 1
            return x-1
        }
    }
    //example:
    var t = 5
    var s = t++
    print("\(t) \(s)")


Tenga en cuenta que a pesar de que esta solución es similar a las soluciones anteriores en esta publicación, ya no funcionan en Swift 4.1 y este ejemplo sí. También tenga en cuenta que cualquiera de los anteriores menciona que + = es un reemplazo para ++ simplemente no entiende completamente al operador ya que ++ combinado con la asignación son en realidad dos operaciones, por lo tanto, un acceso directo. En mi ejemplo:var s = t++hace dos cosas: asigna el valor de t a sy luego incrementa t. Si el ++ viene antes, son las mismas dos operaciones realizadas en orden inverso. En mi opinión, el razonamiento de Apple sobre por qué eliminar este operador (mencionado en respuestas anteriores) no es solo un razonamiento falso, sino que además creo que es una mentira y la verdadera razón es que no pudieron hacer que su compilador lo maneje. Les dio problemas en versiones anteriores, por lo que se dieron por vencidos. La lógica de "operador demasiado complicado de entender, por lo tanto eliminado" es obviamente una mentira porque Swift contiene operadores mucho más complicados y mucho menos útiles que no fueron eliminados. Además, la gran mayoría de los lenguajes de programación lo tiene. JavaScript, C, C #, Java, C ++ y muchos más. Los programadores lo usan felizmente. Para quien es demasiado difícil entender a este operador,

La estrategia detrás de Swift es simple: Apple cree que el programador es tonto y, por lo tanto, debe ser tratado en consecuencia.

La verdad es que Swift, lanzado en septiembre de 2014, se suponía que ya estaría en otro lugar. Otros idiomas crecieron mucho más rápido.

Puedo enumerar muchos errores importantes en el lenguaje, desde serios: como matrices pegadas por valor y no por referencia, hasta molestas: las funciones de parámetros variables no pueden aceptar una matriz, que es la idea detrás de esto. No creo que a los empleados de Apple se les permita mirar otros lenguajes como Java, por lo que ni siquiera saben que Apple está a años luz de distancia. Apple podría haber adoptado Java como lenguaje, pero en estos días, el desafío no es la tecnología, sino el ego. Si hubieran abierto IntelliJ para escribir algo de Java, seguramente cerrarían su negocio entendiendo que en este punto, no pueden ponerse al día y nunca lo harán.

Elad Lavi
fuente