程式語言的發展趨勢:從沒有分號,到DSL

慕課網 發佈 2022-12-08T06:07:15.538934+00:00

本文首發自「慕課網」,想了解更多IT乾貨內容,程式設計師圈內熱聞,歡迎關注!作者| 慕課網精英講師 liuyubobobo一直以來,我有一個觀點:隨著軟體行業的逐漸成熟,算法將慢慢不再成為軟體行業工作者必備的知識(但一定是信息學相關專業必學的知識)。

本文首發自「慕課網」,想了解更多IT乾貨內容,程式設計師圈內熱聞,歡迎關注!

作者| 慕課網精英講師 liuyubobobo

一直以來,我有一個觀點:隨著軟體行業的逐漸成熟,算法將慢慢不再成為軟體行業工作者必備的知識(但一定是信息學相關專業必學的知識)。因為算法將被越來越多地封裝和直接使用。這就好比資料庫,近乎是每一個軟體項目都必備的需求,但近乎每一個軟體項目都不會選擇重新實現一個資料庫。有太多現成的資料庫工具唾手可得,我們只需要學會怎麼使用它們就好了。而怎麼使用它們,比重新實現一個資料庫,簡單不止 100 倍。

事實上,計算機行業的任何一個細分領域,都在上演著這樣的 「進化過程」:很多在以前看來是必學的知識,從現代開發的角度看,不一定是必備的。所以,大家會覺得面試造核彈,上班擰螺絲。

如果你曾在十五年前,就嘗試做一個網頁;做一個桌面 app(那時還根本沒有移動 app);做一個遊戲;你就會明白我在說什麼。一個非常顯然的事實是:在十五年前,做一個網頁,做一個桌面 app,做一個遊戲,相應的成本都是現在的 100 倍以上,而最終得到的成果,搞不好不足現在的百分之一。這一萬倍的差距,不是因為今天的我們更聰明了,而是因為行業在發展。今天的我們,不僅僅是 「站在巨人的肩膀上」,更是 「站在了幾百萬個巨人的肩膀上」。

所以,我經常提醒自己,我能實現這麼多複雜的功能,不是因為我有多聰明,而是因為編程現如今竟是如此簡單。任何一個技術,如果能被大規模地應用,除了它足夠有用之外,還必須具備一個必要的因素 —— 它足夠簡單。計算機技術在我們這個時代被越來越多、越來越廣泛地使用,是因為計算機技術越來越簡單。

在這篇文章中,我想從計算機語言的角度,聊聊程式語言的 「演化」。這本身是一個很大的話題,甚至有很多學者做專門的相關研究。因此,這篇文章的討論角度也是極其有限的。大家通過文章標題就可以看出來,這篇文章將聊到 DSL 為止。但除了 DSL,我們確實還有很多維度去探討這個話題。以後有機會,我會再逐漸補充我的觀點:)

1. 從沒有分號,到給人看的程式語言

學習計算機的同學一定了解:分號在計算機程式語言中,有著舉足輕重的地位。如果你學習的第一門語言是 C,或是 C++,或是 Java,那麼你一定曾經犯過忘記寫分號的錯誤。

但是,如果多接觸幾門程式語言,就會發現:大多數 「現代」 程式語言,是完全不需要寫分號的。比如 Python,比如 Swift,比如 Go。為什麼?原因很簡單,在大多數情況下,分號是給機器看的,而不是給人看的。寫分號,本質是我們人類在遷就編譯器。畢竟,機器是很傻的。

有意思的是,即使是同樣一定需要分號的語言,Java 也比更底層的 C++ 需要的分號少。比如,下面的例子中,我們同樣聲明一個學生類。

C++ 語言:

class Student{
public:
string name;
}; // 注意,在 C++ 語言中,這裡必須有一個分號。

Java 語言:

public class Student{
public string name;
} // 注意,對於 Java 語言,這裡不需要分號!

可以看到,在類聲明結束的時候,C++ 語言這個老古董,還需要加上一個分號,但是 Java 語言不需要。顯然,Java 語言的語法規則更加合理。在這裡,大括號的結束已經完全可以表示類聲明的結束了,多一個分號,對人類來說,是一個額外的 「語法負擔」。

隨著程式語言的逐漸演化,這樣的語法負擔都將被剔除。如果你學習過 Python 語言,就會知道,何止是分號消失了,連大括號都消失了。為什麼? 就是因為大括號也是給機器看的。告訴機器,類聲明結束了。從 Python 的角度看,「舊式語言」 有太多的語法規則,使用了過多的字符,來告訴機器如何解析程序,比如分號,比如大括號。這使得這些語言猛地看上去,包含一大堆和程序本身所表達的邏輯完全無關的字符。所以,Python 在努力減少這樣的語法。

但與此同時,Python 在另一些語法中,卻在添加更多的字符。最典型的就是三目運算符 「?:」,在 Python 中沒有了。為什麼?三目運算符雖然形式更簡單,但這個 「簡單的形式」 也是給機器看的,不是給人看的。

比如我們要根據 score 這樣一個變量的值,返回 「Perfect」 或者 「Not Perfect」 這樣的字符串,在 C++ 或者 Java 這樣的語言中,我們寫出的邏輯大概是這樣的:

return score == 100 ? "Perfect" : "Not Perfect";

但是,在 Python 語言中,是這樣的:

return "Perfect" if score == 100 else "Not Perfect"

顯然,三目運算符比 if-else 的形式更簡潔,但在邏輯表意上,更加複雜,不夠直觀。而 Python 的寫法,更接近自然語言,任何人,即使沒有計算機背景,也能一眼看懂這句話的意思。所以,三目運算符被 Python 直接摒棄了。類似的,++, – 這類所謂更 「簡潔」 的語法,也被 Python 摒棄了,也是這個原因。

這類語法的棄用,絕不僅僅是 Python 一門語言的選擇,比如蘋果幾年前剛發布的新語言 Swift,也是如此。程式語言的發展趨勢之一,就是越來越向著給人看的方向發展,而不是給機器看。

2. 去除和邏輯無關的語法

程式語言的另一個發展趨勢,就是摒棄和業務邏輯無關的語法規則。 最典型的例子,就是現代大多數語言都不再有顯示聲明指針的語法。

相信對於大多數同學,如果學習過 C 或者 C++ 語言,在學習 int*, int**, int&, 等等這些語法規則的時候,都是一團漿糊。甚至可能很多同學畢了業,都沒有特別搞清楚 C/C++ 語言中的指針和引用到底是怎麼回事。

相信對於絕大多數同學(至少對於我是如此),在剛接觸 C 語言的時候,連使用 scanf,都是一場噩夢。

int a;
scanf("%d", &a); 
// 我們先不提 %d 是怎麼回事,a 前面為什麼一定要有個&????

// 但是,如果a是一個char[]的話...
char s[80];
scanf("%s", s);
// 咦?怎麼s前又不需要&了?

這段代碼中,這個 & (C/C++ 中是地址符),就是和業務邏輯無關的語法規則。在這裡,我不詳細的介紹 C/C++ 中的這個語法規則了。其實,如果你不使用 C/C++,對於現代程式語言,你完全不需要理解這其中有什麼區別,在什麼時候應該使用哪個語法。

相較而言,比如 Java 語言的控制台輸入,是使用 Scanner 類,寫出來大概是這樣的。

Scanner myScanner = new Scanner(System.in); 
int a = myScanner.nextInt();
String s = myScanner.nextLine();

同樣,對於 C++ 語言,寫出來大概是這樣的:

int a;
cin >> a;

string s;
cin >> s;

雖然,對於 Java 和 C++ 的 IO 部分的語法設計(或者說類設計),還是有很多吐槽和更好的建議,但很明顯,高級語言在努力摒棄掉諸如 % d, % s, &, 等等語法規則。因為,這些語法規則和具體邏輯無關。

對於指針這個概念同理。對於大多數高級語言,和指針相關的語法都被隱藏起來了。當然,現階段,對於程式設計師,還是必須要理解清楚指針這個概念的(在 Java,Python 等語言中,其實就是引用)。但是,從語法的角度,這個概念 「消失」 了。這顯然對初學者更友好。初學者不需要糾結,什麼時候用 *,什麼時候用 &。語言的使用者,將更多地精力,集中在邏輯表達上,而非語法細節上。

3. 自動垃圾回收

說到剔除邏輯無關的規則,最為典型的,就是現代語言在大多數情況下,不再需要程序編寫者處理垃圾回收相關的邏輯了。很多語言,即使本來需要手動處理垃圾回收邏輯,在版本升級的過程中,也改為了自動垃圾回收機制。這也是因為,垃圾回收是和我們要表達的邏輯無關,是關於機器怎麼執行的邏輯。這裡,最典型的例子,就是 OC 語言。

我是 iOS 4 時代開始接觸 iOS 開發的。那個時候,OC 語言是需要進行手動垃圾回收的(和 C/C++ 語言一樣)。但是從 iOS 5 開始,OC 語言引入了自動垃圾回收機制,被稱為 ARC。雖然嚴格意義上,ARC 和 Java 的 GC 還不一樣(這是因為這兩種語言本身的內存管理模型有所不同),但是他們的目的都是相同的:讓程式設計師更多地專注於業務邏輯代碼的編寫,而不是專注於垃圾回收這樣只有機器才關注的問題。 如果你嘗試使用過需要手動處理垃圾回收機制的語言編寫較大的項目,如 C/C++/OC,就會明白:你很有可能會花費 50% 的時間,來保證整個系統的垃圾回收是沒有問題的。但是,使用 「現代」 程式語言,這些時間都可以用來精進你所要實際表達的代碼邏輯。

對於現代程式語言,自動垃圾回收機制,近乎是標配。這也使得越來越多的程式設計師根本不了解內存管理,也不需要了解內存管理,就可以勝任大多數工作。在這方面,我一直喜歡舉發生在我身邊的一個 iOS 程式設計師的例子。我的這位朋友,文科生出身,在 iOS 5 的時代開始接觸 iOS 開發。他接觸 iOS 開發,完全是因為在那個時代對蘋果產品的瘋狂著迷,愛屋及烏,也想要開發屬於自己的 iOS App。結果,竟然在那個大多數程式設計師都還不太接觸 iOS 開發的年代,他無意中轉行進入了 IT 行業,並且抓住了風口,在短短一年的時間裡,成為了國內某著名品牌的 iOS 事業部負責人。在那個年代,大多數碩士畢業的研究生,在大廠的工資也就是 10 萬每年。他一個文科生,本科學歷轉行計算機,藉助 iOS 開發的契機,竟在那時就達到了 30 萬每年的薪水。

對於這個案例,除了佩服他的興趣,感嘆時代和機遇的力量,以及佩服他的執著和努力之外,我也常常想:或許,這和 OC 語言本身在 iOS 5 開始,開發者不再需要處理內存管理,也是分不開的。否則,對於文科生來說,理解內存管理,學習曲線真的太陡峭了。

蘋果每年都會在自己的發布會上聲稱,iOS 開發生態中,有多麼多么小的開發者,或者多麼多麼老的開發者。是因為這個年代的人們突然都是天才了嗎?不是。因為開發真的越來越簡單。

4. DSL

上面舉的例子,不論是分號、大括號、三目運算符、指針、地址符、垃圾回收,等等等等,這些功能在程式語言中的演化,本質其實都是:程式語言在逐漸剔除和業務邏輯無關的語法,從而讓開發者更多地關注在業務邏輯自身上,而不是機器怎麼執行這些邏輯上。簡單的總結,可以理解成:現代語言的發展趨勢是:編程的主要任務越來越多的是告訴機器要做什麼(what),而不是怎麼做(how)。

正是因為這個方向的指引,越來越多的 DSL 語言被發展出來。

DSL,是 Domain Specific Language 的縮寫,翻譯成中文,就是 「特定領域語言」。 其實,對於 DSL 語言,我們都不陌生,最典型的 DSL,就是 SQL。大家體會一下下面的這段 SQL 代碼:

SELECT name FROM Student WHERE score = 100

大家想想,這段代碼所表示的邏輯,用其他語言怎麼寫?在大多數語言中,大概是這樣的:(偽碼)

names = []
for student in students:    
    if student.score == 100:        
        names.append(student.name)    
        
return names

看了這兩段代碼,不知道大家是不是能夠理解,什麼叫告訴機器 what,而不是 how。對於 SQL 語言來說,我們的代碼近乎就是用自然語言說:我們要把分數是 100 分的學生姓名拿出來。而對於其他大多數語言(C++, Java 等等),我們還需要循環 (for),需要條件判斷 ( if ),需要考慮拿回來的學生姓名怎麼存儲(數組?集合?),還要手動把一個一個符合條件的學生姓名添加進去(append)。顯然,這段代碼更多的涉及 how,而不僅僅是 what。

當然了,SQL 語言這種 「簡潔性」 是有代價的,這個代價就是 DSL 中所謂的 Domain Specific, 即領域相關。使用 SQL,我們只能處理和數據存儲相關的內容(通常所說的增刪改查)。但我們不能用 SQL 做移動 app;不能用 SQL 做後端業務邏輯;不能用 SQL 做前端;也不能用 SQL 做動畫、做遊戲、做人工智慧。但是,只要是和存儲相關的東西,掌握 SQL 這麼一個簡單的工具就夠了。

DSL 還有很多,在現代的環境下,近乎每一個程式設計師都一定會接觸那麼幾個 DSL。再比如說,正則表達式也是一種 DSL,正則表達式只可以進行模式匹配。但是,對於模式匹配,再複雜,使用正則表達式解決,也比自己寫模式匹配算法或者模式匹配工具要強。

HTML 和 CSS 也屬於 DSL,雖然,這兩種語言本質上處理的不是邏輯(CSS 越來越強大,也已經有了 「邏輯引擎」),但是,如果學習過 HTML 和 CSS 的同學一定了解,這兩種語言都是上手極快的(當然,上手和精通是兩回事兒)。我們可以很快地就使用這兩種語言來做出頁面,而且看上去還不錯。這就是 DSL 的意義 —— 可以更快地,更簡潔地,去讓哪怕是 「計算機科學的外行」,用編程的方式,去做特定領域的事情,而不用去糾結過多 「計算機科學」 相關的內容。

在這個年代,做科研工作,近乎一定要編程,並且大多數科研相關的編程工作是和數據相關的。因為各個領域的前沿研究,都需要在領域相關的大量數據中,尋找新的突破和發現。可能有很多同學知道,Python 和 R 是現今最主流的兩種用於數據處理的語言。如果你身邊有非計算機領域的博士同學,或者研究工作者,去問問他們,你會驚訝的發現,大多數非計算機專業的研究工作者,更常用 R 語言,而非 Python 語言。為什麼?因為,相較 Python 語言,R 語言更像一個 DSL。當然,R 語言本身也很強大,但是遠沒有 Python 強大。R 語言本身近乎就是為數據科學設計的語言,大多數數據科學所需要的功能,R 語言或者本身從語法層面支持,或者在標準庫中內置好了。所以,對於非計算機專業的人士而言,R 語言是更加友好,上手更快的。使用 R 語言,可以儘量少地去接觸和 「計算機科學」 相關的知識,就能上手複雜的數據處理任務。

相較於 SQL,正則表達式,CSS,HTML,R 等等這些 DSL,計算機專業的同學通常需要努力學習的,諸如 C++, Java, Python 等語言,被稱為 GPPL,是 General Purpose Programming Language 的簡稱。也就是所謂的 「通用目標語言」。 顧名思義,通用目標語言沒有把功能限制在特定領域中,相較 DSL 更靈活,可以完成更多的事情,甚至可以說是任意邏輯(嗯,這句話細究起來,又可以寫一篇新文章了),但代價就是:語言本身操作起來更靈活,也更複雜。

整體而言,越來越多的 DSL 的出現,也是程式語言發展的一大趨勢。 比如,現在大火的人工智慧界,很多人就認為,使用現有的語言做人工智慧算法,太麻煩了。人工智慧專家要花很多時間,來處理和人工智慧算法無關的邏輯。發明一個人工智慧領域專有的 DSL,近乎是必然。很有可能,我們在未來,還將看到醫學領域特定的 DSL、生物學領域特定的 DSL、化工領域特定的 DSL、物理學領域特定的 DSL,等等等等。

另一方面,在未來,使用 GPPL 的工程師們 —— 也就是真正計算機專業的同學們,一個很重要的任務,就是開發 DSL。開發出的這些 DSL,是給其他領域的專家,或者業務專員使用的。「分工」 本身就是經濟學的基礎概念之一,是我們這個世界能夠良性運轉逐漸發展的諸多核心規則之一。 這種 GPPL 和 DSL 越來越清晰的分層,也是 「分工」 這一經濟學概念在程式語言界的體現:)

當然,對於 GPPL,也有很多發展趨勢。比如動態性,比如對函數式編程的支持,比如對並發的支持,等等等等。有機會,我再向大家總結:)

對於計算機專業的同學來說,語言只是一種工具而已。學習語言的目的,不是對細微的語言特性和語法糖如數家珍,關鍵還是要應用語言,解決實際的場景問題。

很多同學會問,十年後,什麼語言最火?很有可能,十年後最火的語言,現在還沒出現呢:)

大家加油!:)

歡迎關注「慕課網」,發現更多IT圈優質內容,分享乾貨知識,幫助你成為更好的程式設計師!

關鍵字: