Os operadores “++” e “-” foram reprovados no Xcode 7.3

139

Estou olhando para as notas do Xcode 7.3 e noto esse problema.

Os operadores ++ e - foram descontinuados

Alguém poderia explicar por que está obsoleto? E estou certo de que, na nova versão do Xcode, agora você vai usar em vez ++disso x += 1;

Exemplo:

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

Captura de tela para aviso

Oleg Gordiichuk
fonte
6
Acho que essa pergunta está fora do escopo do stackoverflow, principalmente porque toda a proposta aceita para a rápida evolução pode ser encontrada no Github, você pode ler mais sobre o porquê dessa proposta github.com/apple/swift-evolution/blob/master / propostas /…
Victor Sigler 02/02
7
Estou pensando seriamente em voltar ao Objective-C. Não vale a pena tentar acompanhar todas as alterações no Swift.
Greg Brown
3
@OlegGordiichuk Também é possível remover os for-loops, pois o estilo C também, consulte este github.com/Vkt0r/swift-evolution/blob/master/proposals/…, para que você não precise usar mais os operadores ++and--
Victor Sigler 02/02
10
Existem muitas mudanças no meu gosto. Sou a favor de melhorias, mas realmente não quero gastar meu tempo reescrevendo partes substanciais da minha base de código toda vez que um lançamento do Xcode point for lançado.
Greg Brown
4
@Fogmeister Não sei ao certo como poderia ser mais claro. Prefiro usar o Swift, mas não sinto que seja estável o suficiente. Eu trabalhei extensivamente com outros idiomas no passado e nunca tive tantas mudanças significativas em um período tão curto de tempo. Sinto que a Apple quer que todos adotemos o Swift, mas eles estão tornando mais difícil do que deveria ser.
Greg Brown

Respostas:

210

Uma explicação completa aqui de Chris Lattner, criador de Swift. Vou resumir os pontos:

  1. É outra função que você precisa aprender enquanto aprende Swift
  2. Não muito menor que x += 1
  3. Swift não é C. Não deve carregá-los apenas para agradar aos programadores C
  4. Seu principal uso é no estilo C para loop for i = 0; i < n; i++ { ... }:, que Swift tem melhores alternativas, como for i in 0..<n { ... }(o estilo C para loop também está saindo )
  5. Pode ser difícil de ler e manter, por exemplo, qual é o valor de x - ++xou foo(++x, x++)?
  6. Chris Lattner não gosta.

Para os interessados ​​(e para evitar o apodrecimento do link), as razões de Lattner em suas próprias palavras são:

  1. Esses operadores aumentam o ônus de aprender o Swift como a primeira linguagem de programação - ou qualquer outro caso em que você ainda não os conheça de uma linguagem diferente.

  2. Sua vantagem expressiva é mínima - x ++ não é muito menor que x + = 1.

  3. O Swift já se desvia de C, pois as operações =, + = e outras operações semelhantes a atribuições retornam Void (por várias razões). Esses operadores são inconsistentes com esse modelo.

  4. O Swift possui recursos poderosos que eliminam muitos dos motivos mais comuns pelos quais você usaria ++ i em um loop for no estilo C em outros idiomas; portanto, eles são usados ​​com pouca frequência em códigos Swift bem escritos. Esses recursos incluem o loop for-in, intervalos, enumerar, mapa, etc.

  5. O código que realmente usa o valor resultante desses operadores geralmente é confuso e sutil para um leitor / mantenedor de código. Eles incentivam códigos "excessivamente complicados" que podem ser engraçados, mas difíceis de entender.

  6. Embora o Swift tenha uma ordem de avaliação bem definida, qualquer código que dependesse dela (como foo (++ a, a ++)) seria indesejável, mesmo que estivesse bem definido.

  7. Esses operadores são aplicáveis ​​a relativamente poucos tipos: escalares de números inteiros e de ponto flutuante e conceitos semelhantes ao iterador. Eles não se aplicam a números complexos, matrizes, etc.

Finalmente, eles falham na métrica de "se ainda não as tivéssemos, as adicionaríamos ao Swift 3?"

Código Diferente
fonte
54
A resposta real é o número 6. Tudo bem, nós (ex-C, Java, ... programadores) somos flexíveis o suficiente :-). Geralmente, para o mundo real, mutação, cruzamento e seleção são suficientes. Eu, Você e Cris também, nós somos todos os resultados desses três operadores ...
user3441734
5
Ponto 5: esses sempre foram dependentes da implementação em C, e ninguém com nenhum sentido jamais os fez. Basta definir o comportamento e vamos nos acostumar. Melhor do que ter que voltar e alterar perfeitamente um bom código antigo sem motivo real.
Echelon
3
Gosto do ponto 3. Você não pode ficar preso ao contrato do legado para sempre. Eu amo C, mas você está criando uma nova linguagem de programação; faz sentido começar com a lousa tão limpa quanto você precisa.
Nicolas Miari 06/04
8
É porque a maçã gosta de forçá-lo a pensar como eles. Eu acho que é perfeitamente bom e usado em qualquer lugar que você precise incrementar ou diminuir uma variável. Não é algo que você "precise aprender"; você se sairá bem sem ele. E o número 5 é apenas um código mal escrito, do tipo que eu nunca vi. Então é # 6. Negar é suficiente para me fazer coçar a cabeça e fazer uma pesquisa no google, então obrigado por desperdiçar meu tempo, Chris.
Csga5000
4
@ csga5000 Esse é um argumento bastante fraco, considerando que você pode definir o operador se quiser. Não tem nada a ver com a maçã, querendo que as pessoas pensem como elas. Simplesmente não se encaixa no idioma. Se ++não existisse nas linguagens do estilo C, ninguém em sã consciência examinaria o design do Swift 3.0 e pensaria que um ++operador seria uma boa adição a ele.
overactor
37

Sei que esse comentário não responde à pergunta, no entanto, pode haver pessoas procurando uma solução para manter esses operadores funcionando e essa solução pode ser encontrada na parte inferior. 😇

Eu pessoalmente prefiro ++e --operadores. Não posso concordar com a opinião de que eles são complicados ou difíceis de gerenciar. Depois que o desenvolvedor entender o que esses operadores fazem (e estamos falando de coisas bem simples), o código deve ficar bem claro.

Na explicação de por que os operadores foram descontinuados, é mencionado que seu principal uso era no estilo C para loops. Eu não sei sobre os outros, mas eu pessoalmente não usar loops de estilo C em tudo e ainda há muitos outros lugares ou situações quando ++ou --operador é útil.

Gostaria de mencionar também que varName++retorna um valor para que possa ser usado no returnwhile varName += 1não pode.

Para qualquer um de vocês que gostaria de manter esses operadores trabalhando aqui, é a solução:

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
fonte
Eu não gosto da sua return (x - 1)para os operadores postfix - IMHO é que é mais limpo para manter a semântica que eles retornam (uma cópia) do valor original e não o que você ganha se você fazerx + 1 - 1
Alnitak
Também não gosto, mas não conheço nenhuma outra maneira (melhor, mais limpa) de fazer isso. Eu não entendo completamente o seu segundo ponto.
0101 16/05
1
Entendo, eu não queria fazer isso apenas por criar uma outra variável (ou melhor, constante nesse caso). Se estamos falando Intapenas, o resultado de (x + 1)será transbordado, o que interromperá a execução e, portanto result - 1, nem será executado. Outros tipos de dados, como Doublepor exemplo, se comportam de maneira diferente, por isso preciso investigar isso.
0101
3
Você pode usar deferpara isso também. defer { x += 1 }; return x
Tim Vermeulen
4
por que não usar genéricos e escrever isso em poucas linhas?
μολὼν.λαβέ
22

A Apple removeu ++e tornou muito mais simples com a outra velha maneira tradicional.

Em vez de ++, você precisa escrever +=.

Exemplo:

var x = 1

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

Da mesma forma para o operador de decremento --, você precisa escrever-=

Exemplo:

var x = 1

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

Para forloops:

Exemplo de incremento:

Ao invés de

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

Você pode escrever:

//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)")
}

Exemplo de Decremento:

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

Você pode escrever:

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 isto ajude!

Sohil R. Memon
fonte
Eles não substituíram nada; +=estava lá o tempo todo.
Nicolas Miari 06/04
@NicolasMiari Sim apenas editando com o formato muito melhor
Sohil R. Memon
@NicolasMiari Você pode verificar agora?
Sohil R. Memon 06/04
3
Que tal ++ie --i?
precisa saber é o seguinte
7

Chris Lattner entrou em guerra contra ++ e -. Ele escreve: “O código que realmente usa o valor resultante desses operadores geralmente é confuso e sutil para um leitor / mantenedor de código. Eles incentivam códigos "excessivamente complicados", que podem ser engraçados, mas difíceis de entender ... Embora o Swift tenha uma ordem de avaliação bem definida, qualquer código que dependesse dele (como foo (++ a, a ++)) seria indesejável, mesmo que foi bem definido ... eles falham na métrica de "se ainda não os tivéssemos, os adicionaríamos ao Swift 3?"

A Apple queria manter rápida uma linguagem limpa, clara, não confusa e direta ao ponto. E então eles preteriram ++ e - palavra-chave.

Jay Mehta
fonte
9
Limpar \ limpo? Olhe para esse inferno de retorno de chamada e chame de limpo? Eu discordo ... E eu acrescentaria: deixar a ++ e - sozinho
mcatach
22
algo como ...for i in 0.stride(to: 10, by: 2)...ou ...for i in (1...10).reverse()...está limpo ?!
mad_manny
6
Concordo. O argumento "limpo" é fundamentalmente contraditório com o resto de Swift. Vindo do Objective-C, que é objetivamente impuro, é muito difícil aceitar 'limpo' como um objetivo de idioma da Apple.
Adrian Bartholomew
2
Tente analisar json e swift e me diga como é limpo.
nickthedude
6

Captura de tela para aviso

O Fix-it featuredo Xcode dá uma resposta clara para isso.

Solução para aviso

Substitua ++ increment operatorpor antiquado value += 1(operador de mão curta) e -- decrement operatorporvalue -= 1

Jayprakash Dubey
fonte
6

Para o Swift 4, você pode restaurar os operadores ++e --como extensões para Inte outros tipos. Aqui está um exemplo:

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
    }
}

Ele funciona da mesma maneira para outros tipos, tais como UIInt, Int8, Float, Double, etc.

Você pode colar essas extensões em um único arquivo no diretório raiz e elas estarão disponíveis para uso em todos os seus outros arquivos lá.

Percebi alguns votos negativos para a minha resposta aqui, quase assim que a publiquei. O que considero um desacordo filosófico, em vez de uma crítica de como meu código funciona. Funciona perfeitamente, se você der uma olhada em um playground.

A razão pela qual publiquei esta resposta é porque discordo de tornar as linguagens de programação de computador desnecessariamente diferentes uma da outra.

Ter muitas semelhanças entre idiomas facilita a aprendizagem e a troca de um idioma para outro.

Os desenvolvedores normalmente usam várias linguagens de programação, em vez de apenas uma. E é um verdadeiro aborrecimento mudar de um idioma para outro, quando não há convenções nem padronização comum entre os idiomas.

Acredito que deve haver diferenças de sintaxe entre os idiomas apenas o necessário e não mais do que isso.


fonte
Adoro quando as línguas “ousam” ser diferentes. Sinceramente, existem muitas linguagens 'sintaxe C', e o C foi projetado há muito tempo. Houve mais de 50 anos de experiência no idioma. Independentemente disso, como essa resposta não foi um incômodo para os operadores, ainda um voto positivo.
precisa saber é o seguinte
5

Aqui está uma versão genérica de alguns dos códigos publicados até o momento. Eu expressaria as mesmas preocupações que os outros: é uma prática recomendada não usá-las no Swift. Concordo que isso pode ser confuso para quem ler seu código no 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
}

Isso também pode ser escrito como uma extensão no tipo numérico.

Doghound
fonte
Eu adicionei @discardableResulta cada uma dessas funções para silenciar o aviso sobre o valor de retorno não estar sendo usado; caso contrário, exatamente o que eu estava procurando.
Devinn Lane
4

Dos documentos :

Os operadores de incremento / decréscimo no Swift foram adicionados muito cedo no desenvolvimento do Swift, como uma transferência de C. Estes foram adicionados sem muita consideração e não se pensou muito desde então. Este documento fornece uma nova visão para eles e, em última análise, recomenda que os removamos completamente, pois são confusos e não carregam seu peso.

Dániel Nagy
fonte
Em outras palavras, esta operação é muito cara para ser usada?
Oleg Gordiichuk 02/02
2
github.com/apple/swift-evolution/blob/master/proposals/… aqui você pode ler sobre isso, mas não é por ser caro, mas pelo design de linguagem.
Dániel Nagy 02/02
Então, como eu andei Swift
deixando
2
@OlegGordiichuk bem, eu diria que eles querem enfatizar que Swift não é um superconjunto de C ao contrário do Objective-C.
Dániel Nagy 02/02
1
@mah muito do que você disse simplesmente não faz sentido. "Não orientado para desenvolvedores existentes" de que maneira? Da mesma maneira que o Java não é orientado para desenvolvedores de PHP? "orientado para aqueles que podem não ter a tendência de ser desenvolvedores"? Sim, porque todos os não-desenvolvedores que estão por aí estão começando a trabalhar com programação orientada a protocolo e genéricos. "Uma maneira de ativar um bom design" basta dar uma olhada no SO, você verá que nenhuma linguagem de programação pode "ativar um bom design".
Fogmeister 02/02
0
var value : Int = 1

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

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

Esta é definitivamente uma desvantagem, certo?

exilado
fonte
5
Você quer dizer elegante como em "você precisa se lembrar de todas as sutilezas da linguagem de programação C, caso contrário, não será imediatamente óbvio se a primeira chamada retornar 1 ou 2"? Acho que podemos todas as peças algumas linhas extras de código em troca de não passar vários minutos coçando a cabeça tentando encontrar uma causa bug por um erro bobo ...
Nicolas Miari
0

Como você nunca trabalha com ponteiros no Swift, faz sentido remover os operadores ++e --na minha opinião. No entanto, se você não pode viver sem, você pode adicionar estas declarações do operador Swift 5+ ao seu projeto:

@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
}
LimeRed
fonte
-3

No Swift 4.1, isso pode ser alcançado da seguinte maneira:



    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)")


Observe que, apesar do fato de que esta solução é semelhante às soluções anteriores deste post, elas não funcionam mais no Swift 4.1 e este exemplo funciona. Observe também que quem menciona acima que + = é um substituto para ++ simplesmente não entende completamente o operador, pois ++ combinado com a atribuição é na verdade duas operações, portanto, um atalho. No meu exemplo:var s = t++faz duas coisas: atribua o valor de t a se incremente t. Se o ++ vier antes, são as mesmas duas operações feitas em ordem inversa. Na minha opinião, o raciocínio da Apple sobre o motivo de remover esse operador (mencionado nas respostas anteriores) não é apenas um raciocínio falso, mas além disso acredito que é uma mentira e o verdadeiro motivo é que eles não conseguiram fazer com que o compilador lidasse com isso. Isso deu a eles problemas nas versões anteriores, então eles desistiram. A lógica do "operador muito complicado de entender, portanto removido" é obviamente uma mentira porque o Swift contém operadores muito mais complicados e muito menos úteis que não foram removidos. Além disso, a grande maioria das linguagens de programação possui. JavaScript, C, C #, Java, C ++ e muito mais. Os programadores o usam alegremente. Para quem é muito difícil entender esse operador,

A estratégia por trás do Swift é simples: a Apple acredita que o programador é burro e, portanto, deve ser tratado de acordo.

A verdade é que o Swift, lançado em setembro de 2014, deveria estar em outro lugar até agora. Outras línguas cresceram muito mais rapidamente.

Posso listar muitos erros importantes na linguagem, desde os graves: como arrays colados por valor e não por referência, até os irritantes: funções de parâmetros variados não podem aceitar um array, que é a idéia por trás dele. Não acho que os funcionários da Apple tenham permissão para procurar outras linguagens como Java, para que nem saibam que a Apple está anos-luz atrás. A Apple poderia ter adotado o Java como uma linguagem, mas atualmente, o desafio não é a tecnologia, mas o ego. Se eles tivessem aberto o IntelliJ para escrever um pouco de Java, certamente fechariam seus negócios, entendendo que, neste momento, eles não podem e nunca vão se atualizar.

Elad Lavi
fonte