「++」および「-」演算子はXcode 7.3で廃止されました


139

Xcode 7.3のノートを見ていると、この問題に気づきました。

++および-演算子は廃止されました

誰かがなぜそれが非推奨であるかを説明できますか?Xcodeの新しいバージョンでは、++これの代わりに使用することになりますx += 1

例:

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

警告のスクリーンショット


6
迅速な進化のすべての受け入れられた提案がGithubにあることが主な理由で、stackoverflowの範囲外である場合、私はこの質問を考えています、あなたはこの提案の理由について詳細を読むことができますgithub.com/apple/swift-evolution/blob/master / proposals /…
Victor Sigler

7
Objective-Cに戻ることを真剣に検討しています。Swiftへのすべての変更に遅れずについていくことを試みる価値はありません。
グレッグブラウン

3
@OlegGordiichuk Cスタイルのforループも削除されるので、このgithub.com/Vkt0r/swift-evolution/blob/master/proposals/…を参照してください。そうすれば、++さらに--演算子や演算子を使用する必要がなくなります
ビクターシグラ

10
私の好みにはあまりにも多くの重大な変更があります。私はすべて改善のためですが、Xcodeポイントのリリースが出るたびにコードベースのかなりの部分を書き換えるのに時間を費やしたくありません。
グレッグブラウン

4
@Fogmeisterどのようにすれば明確になるかわかりません。Swiftを使用したいのですが、十分に安定しているようには思えません。私は過去に他の言語で広範囲に取り組んだことがあり、そのような短期間にそれほど多くの重大な変更に遭遇したことはありません。Appleは私たち全員にSwiftの採用を望んでいるように感じますが、彼らは本来あるべき以上に困難にしています。
グレッグブラウン

回答:


210

Swiftの作成者であるChris Lattnerによる、ここで完全な説明。ポイントを要約します。

  1. これは、Swiftの学習中に学ばなければならないもう1つの機能です。
  2. よりもはるかに短い x += 1
  3. SwiftはCではありません。Cプログラマを喜ばせるためだけにそれらを持ち越すべきではありません。
  4. その主な用途は、Cスタイルのforループfor i = 0; i < n; i++ { ... }であり、Swiftにはfor i in 0..<n { ... }(Cスタイルのforループも出ていく)など、より優れた代替案があります。
  5. たとえば、x - ++xまたはの値は何foo(++x, x++)ですか?
  6. クリス・ラットナーはそれが好きではありません。

興味のある人(リンクの腐敗を避けるため)にとって、ラトナーの言葉には次のようなものがあります。

  1. これらの演算子は、Swiftを最初のプログラミング言語として学習するための負担を増やします-または、別の言語からこれらの演算子をまだ知らないその他の場合。

  2. それらの表現上の利点は最小限です-x ++はx + = 1よりもはるかに短くありません。

  3. SwiftはすでにCから外れていますが、=、+ =、および他の代入のような演算は(いくつかの理由で)Voidを返します。これらの演算子はそのモデルと一致していません。

  4. Swiftには強力な機能があり、他の言語のCスタイルのforループで++ iを使用する一般的な理由の多くを排除するため、これらはよく書かれたSwiftコードで比較的まれに使用されます。これらの機能には、for-inループ、範囲、列挙、マップなどが含まれます。

  5. これらの演算子の結果値を実際に使用するコードは、多くの場合、コードのリーダー/メンテナーにとってわかりにくく、微妙です。彼らは、可愛くても理解しにくい「過度にトリッキー」なコードを奨励しています。

  6. Swiftの評価順序は明確に定義されていますが、それに依存するコード(foo(++ a、a ++)など)は、明確に定義されていても望ましくありません。

  7. これらの演算子は、比較的少数のタイプ(整数および浮動小数点スカラー、およびイテレーターのような概念)に適用できます。複素数、行列などには適用されません。

最後に、これらは「まだ持っていない場合、Swift 3に追加しますか?」というメトリックに失敗します。


54
実際の答えは6番です。つまり、私たち(以前のC、Java、...プログラマー)は十分な柔軟性を備えています:-)。一般に、現実の世界では、突然変異、交差、選択で十分です。私も、あなたも、クリスも、3人のオペレーターの結果です...
user3441734

5
ポイント5:これらは常にCでの実装に依存しており、どんな意味のある人もこれを行っていません。動作を定義するだけで慣れます。本当の理由なしに戻って完全に古き良きコードを変更しなければならないよりはましです。
エシェロン

3
私はポイント3が好きです。レガシーの契約に永遠に縛られることはできません。私はCが大好きですが、あなたは新しいプログラミング言語を作成しています。必要なだけスレートから始めるのが理にかなっています。
Nicolas Miari、

8
それは、Appleがあなたに彼らがそうであるように考えることを強いるのを好む原因です。私はそれは完全に素晴らしいと思い、変数をインクリメントまたはデクリメントするために必要な場所で使用されます。それはあなたが「学ぶ必要がある」ものではなく、それなしでうまくやります。そして#5は、私が見たことがないような、不十分に書かれたコードです。つまり#6です。それを剥がすだけで頭を掻いてグーグル検索をするのに十分なので、私の時間を無駄にしてくれたクリスに感謝します。
csga5000 2016年

4
@ csga5000本当に必要な場合は演算子を自分で定義できることを考えると、これは非常に弱い議論です。それは人々が彼らのように考えることを望んでいるアップルとは何の関係もありません。それは単に言語に適合しません。++がCスタイルの言語に存在しなかった場合、正しい考えの誰もがSwift 3.0の設計を見て、++演算子がそれに素晴らしい追加になるとは考えません。
オーバーアクター

37

このコメントは質問に答えるものではありませんが、これらのオペレーターを稼働させ続ける方法を探している人がいるかもしれません。そのような解決策は下部にあります。😇

個人的には++--演算子を好みます。それらが扱いにくいか、管理が難しいという意見には同意できません。開発者がこれらの演算子が何をするかを理解したら(そして、かなり単純なことについて話しています)、コードは非常に明確になるはずです。

演算子が非推奨になった理由の説明では、その主な用途はCスタイルのforループであったと述べています。私は他の人のことは知らないが、私は個人的に、すべてのCスタイルのループを使用していないとするとき、まだ他の多くの場所や状況がある++か、--オペレータが便利です。

私はまた、言及したいと思いvarName++、それはで使用できるように戻り値をreturn一方varName += 1ことはできません。

これらのオペレーターをここで機能させ続けることを望むすべての人にとって、解決策は次のとおりです。

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
}

私はあなたの好きではないreturn (x - 1)後置演算子の-彼らは返すこと(のコピー)セマンティクスを維持するために、私見のそれのクリーナー元の値ではなく、あなたがしなければ、あなたが得るものよりx + 1 - 1
オリオン座ゼータ星

私もそれは好きではありませんが、これを行う他の(より良い、よりクリーンな)方法については知りません。2番目の点がよくわかりません。
0101

1
なるほど、別の変数(この場合は定数)を作成するためだけにそれを実行したくありませんでした。私たちIntだけが話している場合、結果は(x + 1)オーバーフローして実行を中断し、実行result - 1されません。Doubleたとえば、他のデータ型は動作が異なりますので、調査する必要があります。
0101

3
deferこれにも使えます。defer { x += 1 }; return x
Tim Vermeulen

4
ジェネリックを使用して、数行でこれを書いてみませんか?
μολὼν.λαβέ

22

Appleはを削除++し、別の古い伝統的な方法でそれをはるかに簡単にしました。

の代わりに++、あなたが書く必要があります+=

例:

var x = 1

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

同様に、デクリメント演算子の--場合、次のように記述する必要があります-=

例:

var x = 1

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

for forループ:

増分の例:

の代わりに

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

あなたは書ける:

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

デクリメントの例:

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

あなたは書ける:

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

お役に立てれば!


彼らは何も置き換えていません。+=ずっとそこにいた。
Nicolas Miari

@NicolasMiariええ、もっと優れたフォーマットで編集しているだけです
Sohil R. Memon

@NicolasMiari今チェックしてください。
Sohil R. Memon 2016

3
何について++i--i
Zigii Wong 2016

7

Chris Lattnerが++および-との戦いに出かけました。「これらの演算子の結果値を実際に使用するコードは、コードのリーダー/メンテナーにとって、しばしば混乱し、微妙です。彼らはかわいいかもしれないが理解するのが難しい「過度にトリッキー」なコードを奨励します... Swiftは評価の順序を明確に定義していますが、それに依存するコード(foo(++ a、a ++)など)はそれが明確に定義されていました...「これらがまだない場合は、Swift 3に追加しますか?」というメトリックに失敗しました。

Appleは、すっきりとした、明確で、混乱のない、わかりやすい直言を迅速に維持したいと考えていました。そのため、彼らは++および-キーワードを廃止しました。


9
掃除?このコールバック地獄を見て、それをきれいに呼び出しますか?私は同意しません...そして追加します:++&-をそのままにします
mcatach

22
のようなもの、...for i in 0.stride(to: 10, by: 2)...または...for i in (1...10).reverse()...きれいですか?
mad_manny

6
同意する。「クリーン」な議論は、Swiftの他の部分と根本的に矛盾しています。客観的に不潔であるObjective-Cから来ているため、「クリーン」をApple言語の目標として受け入れることは非常に困難です。
エイドリアンバーソロミュー2016年

2
jsonとswiftを解析して、どれほどクリーンかを教えてください。
Nickthedude

6

警告のスクリーンショット

Fix-it featureXcodeののは、これに対する明確な答えを与えます。

警告の解決策

置き換え++ increment operator昔ながらでvalue += 1(短期手のオペレータ)と-- decrement operatorvalue -= 1


6

Swift 4の場合、++および--演算子をIntおよびその他のタイプの拡張として復元できます。次に例を示します。

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

それは、次のような、他のタイプのために同じように動作しUIIntInt8FloatDouble、など

これらの拡張機能をルートディレクトリの1つのファイルに貼り付けると、そこにある他のすべてのファイル内で使用できるようになります。

投稿してすぐに、ここで私の回答に対するいくつかの反対票に気づきました。私のコードがどのように機能するかについての批判ではなく、私はそれを哲学的な不一致とみなします。遊び場でチェックアウトすれば、完全に機能します。

私がこの回答を投稿したのは、コンピュータプログラミング言語を不必要に異なるものにすることには同意しないためです。

言語間で多くの類似点があると、人々が学習しやすく、ある言語から別の言語に切り替えることが容易になります。

開発者は通常、1つではなく複数のプログラミング言語を使用します。また、慣習や言語間での共通の標準化がない場合、ある言語から別の言語に切り替えるのは本当に面倒です。

言語間の構文の違いは、必要な分だけで、これ以上はないと思います。


言語が異なることに「挑戦」するときが大好きです。正直言って「C構文」言語は多すぎます。Cはかなり前に設計されました。50年以上の言語経験があります。賛成票。
user2864740

5

これは、これまでに投稿されたコードの一部の一般的なバージョンです。他の人と同じ懸念を表明します。Swiftではこれらを使用しないことがベストプラクティスです。これが将来あなたのコードを読む人を混乱させるかもしれないことに私は同意します。

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
}

これは、数値型の拡張として書くこともできます。


@discardableResultこれらの各関数に追加して、戻り値が未使用であるという警告を抑制しました。そうでなければ、まさに私が探していたもの。
Devin Lane

4

ドキュメントから:

Swiftのインクリメント/デクリメント演算子は、Cからの持ち越しとして、Swiftの開発の非常に早い段階で追加されました。これらはあまり考慮されずに追加され、それ以来あまり考えられていません。このドキュメントでは、それらの見た目が新しくなり、混乱を招き、重要度が低下するため、最終的には完全に削除することをお勧めします。


言い換えれば、この操作は高すぎるため使用できません。
Oleg Gordiichuk 2016

2
github.com/apple/swift-evolution/blob/master/proposals/…ここでそれについて読むことができますが、それは高価なためではなく、言語設計のためです。
ダニエル・ナギー

私アンデルセンスウィフトは、Cスタイルの機能のサポートをドロップしようように
オレグGordiichuk

2
@OlegGordiichukよく、彼らはSwiftがObjective-CのようなCのスーパーセットではないことを強調したいと思います。
ダニエル・ナギー

1
@mah言ったことの多くはまったく意味がありません。「既存の開発者向けではない」とはどういう意味ですか?JavaがPHP開発者向けではないのと同じように?「開発者である傾向がないかもしれないそれらに向けられる」か。ええ、そこにいる開発者以外のすべての人がプロトコル指向プログラミングとジェネリックで手を離しています。「優れた設計を可能にする方法」は、SOを見るだけで、どのプログラミング言語も「優れた設計を可能にする」ことができないことがわかります。
フォグマイスター、2016

0
var value : Int = 1

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

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

これは間違いなくマイナス面ですよね?


5
「Cプログラミング言語のすべての繊細さを覚えておく必要があります。それ以外の場合、最初の呼び出しで1または2が返されるかどうかはすぐにはわかりません」のようにエレガントです。ばかげた間違いによってバグの原因を見つけようとして頭をかき回すのに数分を費やすことと引き換えに、数行の余分なコードをすべて節約できると思います...
Nicolas Miari

0

Swiftでポインターを実際に操作することはないので、私の意見では++and --演算子を削除することは理にかなっています。しかし、それなしでは生きられない場合は、これらのSwift 5+演算子宣言をプロジェクトに追加できます。

@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

Swift 4.1では、次の方法で実現できます。



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


このソリューションはこの投稿の以前のソリューションと同様であるという事実にもかかわらず、Swift 4.1では機能しなくなり、この例では機能することに注意してください。また、+ =が++の置き換えであると上記で言及した人は、演算子を完全には理解していないことに注意してください。私の例では:var s = t++2つのことを行います。tの値をsに割り当て、tをインクリメントします。++が前にある場合、それは逆の順序で行われる同じ2つの操作です。私の意見では、この演算子を削除する理由についてのAppleの推論(以前の回答で述べた)は誤った推論であるだけでなく、それは嘘であると私は信じています。以前のバージョンでは問題が発生したため、あきらめました。「演算子を理解するには複雑すぎるため、削除されました」というロジックは明らかに嘘です。Swiftには、削除されなかったはるかに複雑であまり有用ではない演算子が含まれているためです。また、プログラミング言語の大部分はそれを持っています。JavaScript、C、C#、Java、C ++などなど。プログラマーは喜んでそれを使います。この演算子を理解するのが難しすぎる場合は、

Swiftの背後にある戦略は単純です。Appleはプログラマーが愚かであり、したがって適切に扱う必要があると信じています。

真実は、2014年9月に発売されたSwiftが今までどこか別の場所にあるはずだったということです。他の言語ははるかに速く成長しました。

参照によるものではなく値によって貼り付けられた配列などの深刻なものから、厄介なものまで、言語の多くの主要な間違いをリストできます。可変引数パラメーター関数は、その背後にある全体的な考えである配列を受け入れることができません。Appleの従業員がJavaのような他の言語を見ることさえ許されていないと私は思うので、彼らはAppleが光年遅れていることさえ知らない。Appleは言語としてJavaを採用できたかもしれませんが、最近の課題はテクノロジーではなく、エゴです。彼らがIntelliJを開いてJavaを書くとしたら、彼らはこの時点では追いつくことができず、追いつくことができないというビジネス上の理解を確実に閉じます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.