對于開發(fā)者而言,開發(fā)語言就是工具,中途換工具一般需要付出的成本。本文是一篇開發(fā)者自述,講述了自己是如何從C/C++改投D語言門下,并介紹了D語言相對C/C++的衍生功能和優(yōu)勢。
作為開發(fā)人員,換開發(fā)語言其實是一件需要很高成本的事,本文主要講講我是怎么從C語言轉(zhuǎn)投D語言的。
其實我的經(jīng)歷和許多系統(tǒng)程序員的故事差不多。曾經(jīng)有一段時間,C是大多數(shù)程序員的首選語言。有一天,我意識到我的大多數(shù)C程序都在重新實現(xiàn)C++中的東西:動態(tài)數(shù)組、更好的字符串、多態(tài)類等等。所以我嘗試使用C++,起初我很喜歡它。RAII、類、泛型等新的組件和概念讓編程再次變得有趣起來。
我曾經(jīng)想象過,如果我把所有關(guān)于C ++的書籍都看一遍,并掌握了模板元編程之類的東西,我說不定會成為系統(tǒng)編程的全能之神,我寫的代碼會讓人大吃一驚。但事后看來,學(xué)習(xí)也可能最終會產(chǎn)生更多相反的效果: 我寫出的代碼實際上變得更糟。
總之全能之神當不上了,我很傷心。
我記得我讀過Scott Meyer著名的《Effective C ++》,這本書其實更多講的是指出低效率的C ++編程的問題,我發(fā)現(xiàn)自己寫的大多數(shù)C++代碼都對上了號。讓我們面對現(xiàn)實吧:C可能很難用,但它確實足夠“優(yōu)雅”,而提到C++,你很難跟“優(yōu)雅”搭上邊。
很多前C ++程序員最終都用回了C。就我而言,我發(fā)現(xiàn)了D語言。其實D也不完美,但是我使用它因為它讓我感覺更像是C++應(yīng)該有的樣子(C+=1)。比如以下面這個簡單的C程序為例(一加一等于幾?):
#include
如果使用C++標準庫,代碼是這樣的:
#include
如果使用D語言,代碼是這樣的:
import std.stdio;void main(){ writef("1 + 1 = %d! ", 1 + 1);}
這個例子雖然淺顯,但它體現(xiàn)出了C++和D之間背后理念的一些區(qū)別。
這篇關(guān)于C ++成員函數(shù)指針的文章也是對D的起源的一個很好的解釋。如果你酷愛編程,這篇文章是一個很好的解讀, 但我的解讀是:C++成員函數(shù)指針應(yīng)該是感覺像是一個低級功能(就像普通函數(shù)指針一樣),但其實現(xiàn)的復(fù)雜性和多樣性說明它們真的很“高級”。
這些指針的實現(xiàn)過程很復(fù)雜,因為關(guān)于它們能做什么/不能做什么的規(guī)則是很微妙的。作者解釋了幾個C ++編譯器的實現(xiàn),包括優(yōu)雅而簡單的Digital Mars C ++實現(xiàn),即DMC。DMC編譯器是由Walter Bright編寫的,他是“D語言”的發(fā)明者。
D具有C ++的類和模板以及其他核心功能,但設(shè)計者花費了大量時間思考C ++規(guī)范,以及如何讓設(shè)計和編程變得更簡單。Walter曾經(jīng)說過,他在部署C ++模板的痛苦經(jīng)歷,讓他考慮過根本不把該功能納入D,后來他意識到,這個過程本來不需要那么復(fù)雜。
下面對D語言的功能和特點進行一番大概的介紹,其實可以把D視作一個“改進版”的C語言。介紹中時刻少不了和C/C++的對比。
-betterC開關(guān)
D編譯器支持-betterC開關(guān),該開關(guān)可以啟用/禁用D運行時以及依賴于它的所有高級功能。上面的C代碼可以直接轉(zhuǎn)換為betterC:
import core.stdc.stdio;extern(C):int main(){ printf("1 + 1 = %d! ", 1 + 1); return 0;}
$ dmd -betterC example.d$ ./example1 + 1 = 2!
生成的二進制文件看起來很像等效的C二進制文件。事實上,如果你在betterC中重寫了一個C庫,仍然可以鏈接到已經(jīng)對C版本編譯的代碼,無需修改就可立即使用。
實際上,如果只是要在D語言中編寫類似C的代碼,并不需要-betterC開關(guān)。只有在沒有D Runtime的特殊情況下才需要使用。
靜態(tài)assert()
這個功能允許開發(fā)者在編譯時驗證一些假設(shè)。
static assert(kNumInducers<16);
系統(tǒng)代碼通常對對齊或結(jié)構(gòu)大小或其他事物做出假設(shè)。使用靜態(tài)assert不僅可以記錄這些假設(shè),而且如果有人通過添加struct成員或其他東西來破壞假設(shè),則會觸發(fā)編譯錯誤。
Slices
典型的C代碼中存在大量的“指針/長度”參數(shù)對,一個常見bug就是二者的不同步。對于由指針和長度定義的一系列內(nèi)存,Slice是一種簡單且超級有用的抽象表示?,F(xiàn)在不必使用這樣的代碼:
buffer_p += offset;buffer_len -= offset; // Got to update both
而可以用下邊這種更不容易出bug的代碼:
buffer = buffer[offset..$];
Slice 其實就是具備優(yōu)秀語法功能的指針/長度對。
編譯時間函數(shù)估計 (CTFE)
許多函數(shù)都可以用編譯時間來評估。
long factorial(int n) pure{ assert (n >= 0 && n <= 20); long ret = 1; foreach (j; 2..n+1) ret *= j; return ret;}// Statically allocated array// Size is calculated at compile timePermutation[factorial(kNumThings)]permutation_table;
scope Guards
函數(shù)的一部分中的代碼通常會在后續(xù)部分帶上一段清理代碼。一個常見的錯誤來源是未能正確匹配該代碼,(尤其是涉及多個控制流路徑時)。D的scope guards設(shè)定使得這個問題變得不再困難:
p = malloc(128);// free() will be called when thecurrent scope exitsscope (exit) free(p);// Put whatever if statements, or loops,or early returns you like here
你甚至可以在作用域中使用多個scope,或嵌套使用scope。清理代碼將在需要時以正確的順序被調(diào)用。
D語言還利用結(jié)構(gòu)析構(gòu)函數(shù)支持RAII。
常量和不可變量
有一個流行的說法是,C和C++中的const對編譯器優(yōu)化很有用。不過D的作者表示,每當他想到一個新的基于const的C++優(yōu)化時,最終都發(fā)現(xiàn)它在實際代碼中并不起作用。所以他對D的const語義做了一些修改,并添加了不可變量。可以在D const FAQ中閱讀更多內(nèi)容。
函數(shù)純度
可以實施函數(shù)純度功能。我之前寫過關(guān)于pure關(guān)鍵字的一些好處。
@Safe
SafeD是D的一個部分,禁止使用指針類型轉(zhuǎn)換和內(nèi)聯(lián)匯編等高風險語言功能。標記為@safe的代碼由編譯器強制執(zhí)行,不使用這些功能,因此高風險代碼可以僅限需要這些功能的應(yīng)用程序的一小部分。
元編程
如前所述,元編程在一些C ++程序員中名聲不好。但是D中的元編程具備一些沒那么有趣的優(yōu)點,程序員一般傾向于只在必要時才用,而不是一個有趣的謎題。
需要將枚舉類型的名稱作為數(shù)組?容易!
enum State{ stopped, starting, running, stopping,}string[] state_names =[__traits(allMembers, State)];
沒有預(yù)處理器
好吧,這其實是一個“非功能”,但D沒有相當于C的預(yù)處理器的功能。所有理智的用例都被替換為本機語言功能,如清單常量和模板。這包括適當?shù)哪K支持,這意味著D可以擺脫舊#include黑客的限制。
-
C語言
+關(guān)注
關(guān)注
180文章
7614瀏覽量
137505 -
編程
+關(guān)注
關(guān)注
88文章
3637瀏覽量
93924 -
C++
+關(guān)注
關(guān)注
22文章
2114瀏覽量
73811
原文標題:開發(fā)者自述:我為什么從C語言轉(zhuǎn)投了D語言?
文章出處:【微信號:AI_era,微信公眾號:新智元】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論