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


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


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
}

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!


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.


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


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.


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.


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.


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?


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
}

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.