為什麼Swift和Python要拋棄++\--?

簡單好用的++、--

說到自增(++)\自減(--)運算符,小夥伴們應該都不會陌生,在很多編程語言的代碼中,都經常出現它們的身影。

  • 比如常用的for語句
  • <code>for (int i = 0; i < n; i++) {
        // TODO
    }/<code>
  • 比如經典的一行代碼實現字符串拷貝
  • <code>// 將src的內容拷貝至dest
    void strcpy(char *dest, char *src) {
        while (*dest++ = *src++);
    }
    
    int main() {
        char s1[10], *s2 = "xmg_mj";
        strcpy(s1, s2);
        printf("%s", s1); // xmg_mj
        return 0;
    }/<code>

    使用得當的話,自增(++)\自減(--)運算符的確可以讓代碼簡潔又優雅。


    但是

    2大熱門編程語言SwiftPython並不支持自增(++)、自減(--)運算符,這是為什麼呢?

    這裡先給出幾個參考鏈接,有興趣的小夥伴可以自行去閱讀一下:

    • Swift之父Chris Lattner的說明
      • 從Swift3開始不支持++、--
      • https://github.com/apple/swift-evolution/blob/master/proposals/0004-remove-pre-post-inc-decrement.md
    • 來自Stack Overflow的一個問答
      • Why are there no ++ and -- operators in Python?
      • https://stackoverflow.com/questions/3654830
    • 來自Google研發總監(Director of Research)Peter Norvig的觀點
      • The Python IAQ: Infrequently Answered Questions
      • http://norvig.com/python-iaq.html

    這裡只列出幾個顯而易見的理由

  • 有了強大又簡潔的for-infor語句中可以完全不需要++、--
  • <code>// C++
    for (int i = 0; i /<code>
  • 儘管while (*d++ = *s++);看起來似乎簡單而優雅,但對於初學者來說絕非簡單,會增加學習成本。而SwiftPython更傾向於希望任何人都能快速上手這門編程語言。
  • 當混合使用前綴和後綴的++、--時
      • 會降低代碼的可讀性,比如while (n++ > --k),經驗豐富的程序員也必須停下來思考一下代碼的具體含義是什麼
      • 運行結果可能會有不確定性


    運行結果的不確定性

    下面列出2段代碼,變量b的結果是什麼呢?(值得一提的是:實際開發中我們並不會這麼寫,這裡把它列出來僅僅是為了討論一些技術細節)

    <code>int a, b;
    
    // 第1段代碼
    a = 1;
    b = a++ + ++a + a++ + ++a;
    
    // 第2段代碼
    a = 1;
    b = a++ + a++ + a++ + a++;/<code>

    實際上,上面的C語言代碼在MSVC、MinGW編譯器下得出的結果是不完全一致的

    • MSVC:微軟出品
    • MinGW:GNU出品(可以理解為Windows版本的GCC)

    第1段代碼:結果一致,符合絕大部分人的預期,所以就不展開討論了

    <code>a = 1;
    b = a++ + ++a + a++ + ++a;
    // MSVC:b = 1 + 3 + 3 + 5 = 12
    // MinGW:b = 1 + 3 + 3 + 5 = 12/<code>


    第2段代碼:結果不一致

    • MSVC的結果是1 + 1 + 1 + 1 = 4
    • MinGW的結果是1 + 2 + 3 + 4 = 10
    <code>a = 1;
    b = a++ + a++ + a++ + a++;
    // MSVC:b = 1 + 1 + 1 + 1 = 4
    // MinGW:b = 1 + 2 + 3 + 4 = 10/<code>

    你可能好奇:你怎麼知道MinGW的計算過程是1 + 2 + 3 + 4呢?根據最終結果10反推回去猜出來的麼?NO!如果是這樣做的話,那就有點侮辱了程序員這個職業了。


    像這種不太容易從表面去理解的代碼,你若想知道它的真正本質,那就要搬出強有力且精準的武器了,它就是

    彙編語言(Assembly Language)


    簡單說明一下使用彙編語言的理由:

    • 眾所周知,C語言代碼最終都會被編譯為機器語言代碼(也叫做機器指令,只由0和1組成)
    • 那通過研究最終的機器指令來探索C語言代碼的本質?由於機器指令極其晦澀難懂,因此,對一般人來說,這並不是一種高效的辦法
    • 最佳的辦法是:研究一下介於C語言機器語言之間的彙編語言代碼
      • C語言彙編語言機器語言
      • 彙編語言代碼比機器指令可讀性高很多
      • 每一條機器指令都有與之對應的彙編語言代碼
      • 因此,你研究彙編語言代碼,基本就等同於研究機器指令,可讀性+精準性兼具


    看看MSVC環境下的彙編代碼

    為什麼Swift和Python要拋棄++\--?

    紅框代碼:將4個a相加的結果賦值給b,由於a的初始值是1,所以b = 1 + 1 + 1 + 1 = 4

    綠框代碼:讓a執行4次自增1的操作,相當於執行4次a += 1

    看看MinGW環境下的彙編代碼

    為什麼Swift和Python要拋棄++\--?

    為了保證能基本看懂這段彙編代碼,建議你可以理解為[rbp-0x4]代表變量a,[rbp-0x8]代表變量b

    綠框代碼:讓a執行自增1的操作,相當於執行a += 1

    紅框代碼:將a每次自增1之前的值累加起來,最後賦值給b

    可以看到,綠框、紅框代碼是交替執行的,所以最終b = 1 + 2 + 3 + 4 = 10

    最後2段代碼

    最後再放2段代碼出來,在MSVC和MinGW下的結果也是不一致的

    <code>a = 1;
    b = ++a + ++a + ++a + ++a;
    // MSVC:b = 5 + 5 + 5 + 5 = 20
    // MinGW: b = 3 + 3 + 4 + 5 = 15
    
    a = 1;
    b = ++a + ++a + a++ + a++;
    // MSVC:b = 2 + 3 + 3 + 4 = 12
    // MinGW:b = 3 + 3 + 3 + 4 = 13/<code>

    根據前面的一些講解,相信你現在可以推斷出MSVC的結果了。

    但MinGW的結果可能還是會讓人感覺到奇怪:它其實是先讓最前面的2個++a執行a自增1的操作,後面的2個++a\a++就照常處理,所以最終b = 3 + 3 + ...

    好了,就此打住,建議不要去糾結這些細節了,因為本來就不推薦這種寫法。你只需要知道:多個前綴、後綴的自增自減一起使用時,結果具有不確定性。


    總的來說,++、--是把雙刃劍,再者,它並非是編碼過程中必不可缺的,所以被SwiftPython拋棄也是正常的事。


    分享到:


    相關文章: