關於using及foreach的一點看法,及其他
firelong雄文又起,其中的觀點很多我看得不太懂,某些看懂的地方(如單向連結串列和List<T>的遍歷效能)感覺又不太對。不過firelong還有一些觀點我是明白的,便是對於增加using和foreach這樣的語言特性表示不滿,覺得這是讓語言變得臃腫,像foreach這樣的設計模式,應該有類庫提供。那麼我們現在就來討論一下這方面的問題吧。
using關鍵字
首先是using關鍵字,using關鍵字的作用是對IDisposable資源作管理,保證不會發生洩漏等問題。例如:
using (var stream = new FileStream("", FileMode.Create)) { // do something}
那麼,它又是怎麼做的呢?其實效果是這樣的:
var stream = new FileStream("", FileMode.Create); try { // do something } finally { if (stream != null) { stream.Dispose(); } }
看程式碼不說話。我想了解一下,您是喜歡直接寫第二段程式碼,還是寫using程式碼呢?
foreach關鍵字
foreach關鍵字是配合IEnumerable作遍歷時使用的,比如這樣的程式碼:
foreach(var i in source) { Console.WriteLine(i); }
其實等價於:
using (var etor = source.GetEnumerator()) { while (etor.MoveNext()) { Console.WriteLine(etor.Current); } }
咦,看上去並不複雜啊,只是多了一級縮排而已。不過您注意到沒有,這裡居然用到了“臃腫”的using關鍵字,所以說,這裡的程式碼理應是這樣寫的:
var etor = source.GetEnumerator(); try{ while (etor.MoveNext()) { Console.WriteLine(etor.Current); } } finally { if (etor != null) { etor.Dispose(); } }
看程式碼不說話。我想了解一下,您是喜歡直接寫第二段程式碼,還是寫foreach程式碼呢?如果有兩層foreach巢狀呢?
評價
firelong同學在文章中提到,用語言支援模式是一個設計上的錯誤,模式應該通過框架或類庫來支援。這點我保留看法,因為在我看來,模式一定程度上是為了彌補語言特性不足而設計的。因此,面嚮物件語言有面向物件語言的模式(如著名的GoF23),函數語言程式設計也有函數語言程式設計的模式(例如monad應該可以算吧)。在C#,Python,Ruby裡很少談工廠方法模式,為什麼?因為它們可以將函式作為方法的引數進行傳遞,不需要建立一個抽象類以及多個實現。同樣的,策略模式等等也是一樣。因此,如果一個語言特性簡化模式的使用,且這個模式非常常用,如using和foreach,那麼這個語言特性很有價值。
firelong同學在文章中回覆到:“如果使用這種思路,那麼Visitor模式,Adaptor模式等等難道也要加進來嗎”,我覺得不能這樣考慮問題,這有點類似“常見邏輯謬誤”裡的“滑坡謬誤”,比如這種說法:
動物實驗有損對生命的尊重。如果不尊重生命,即可能越來越容忍諸如戰爭及殺人等等暴力行為。那麼,社會將很快就會淪為戰場,人人都會時刻擔憂自己的生命。這將是文明的末日。為了防止出現這種可怕結果,應當立即宣佈動物實驗為非法。
類比一下:
新增支援模式的語法有損語言的緊湊性。如果不考慮緊湊性,即可能越來越容忍諸如支援Visitor模式等等愚蠢行為。那麼,語言很快就會淪為垃圾場,人人都會時刻擔憂自己的程式碼。這將是程式的末日。為了防止出現這種可怕後果,應該立即廢除對模式的語法支援。
其實每一個語法增加都是要權衡利弊的,例如using和foreach的確會大大簡化開發,於是我很歡迎這個語法功能,而且如Iterator模式的確是非常常用的。這點看一下您程式碼中有多少foreach便知道了——當然,有了LINQ之後,foreach用的很少,但是我很擔心firelong同學是否會支援LINQ所基於的多種語法特性。還有一方面,便是能否在語法上支援Visitor等模式,我沒有想明白該怎麼設計這個語法。我同樣想不明白的是,firelong同學說的,用框架類庫來支援模式,就拿foreach和using來說,該怎麼做才能像現在這樣優雅呢?
其實foreach等功能都是現代語言的“標配”,Python,Ruby連Java都有支援Iterator的語法(如Python等還有如yield等Iterator生成器),而且在Java 7裡,也已經加入像C#裡using這樣的自動資源管理(Automatic Resource Management,ARM)功能,所以其實我不是很理解firelong所說的:用框架類庫支援模式才是“正途”。我希望firelong同學能夠補充更多理由。
至於yield和事件的設計,我將會在自己的部落格上討論,因為這不是三句兩句話能寫清楚地內容。
其他
好吧,我要說一些其他內容了,因為光說這些內容顯得不夠地道,而在一篇技術文章最後談談,可能大家更容易容忍一些。
我實在不是很清楚,為什麼firelong同學要針對我做反面例子,這次我在回覆“Iterator實在太常見了,而且yield的幫助無窮大”,又被說成是“拿著一個new feature 撫摸來,撫摸去的新cool程式設計師”。以前的文章說的更難聽,都說我敗壞社群風氣,騙取眼球,他見不得.NET社群這樣沉淪下去,決定寫博吶喊。沒錯,我是喜歡語言,但是您如果仔細看我的文章,就會發現我討論的究竟是什麼。我討論的東西不是簡單的語法功能,而是程式設計理念。我比較C#和Java,也是提到程式設計理念。我不斷強調,我不會關注最普通的語法特性,而是考慮到引入語法以後,是否對程式設計思路有重要改進。我也不光在乎C#語法,我接觸很多語言,要說我“拿個新Feature撫摸來撫摸去”,您看到我在反覆強調C# 4.0的新特性嗎?
firelong同學很注重效能,於是不知怎麼就說我不重視效能了。事實上,效能相關的東西我寫過很多,例如《重談字串連線效能》系列,《陣列排序方法的效能比較》系列,《併發環境下的快取容器效能優化》系列,《程式碼執行效率》系列,還有“基礎效能相關”文章(如《計算機體系結構和程式效能》等等),累計幾十篇。我不是不重視效能,相反我覺得我都在把效能相關的各個方面已經談遍了。談了很多,事實上我還一直在考慮該從哪個角度入手繼續討論,只是沒有好的題材而已。而且,我強調的最多的還是基礎,我不斷強調演算法和資料結構,還有一些如作業系統等基礎課程,這從《老趙書託》裡便可以得知。在談每一塊時我都希望儘可能客觀、正確、完整。這方面我談的比任何人少過嗎?當然,我的確沒有天天強調效能,我覺得沒有必要,可能這也和我沒有在這方面效能問題上栽過跟頭的緣故。
所以,我想對firelong同學說:您為什麼總是說我重視語法,即便是我在您文章後面的評論中強調某個語言特性的作用,那不也是在您“討論語法”的環境中進行的嗎?您不喜歡被人扣屎盆子,己所不欲勿施於人,我也不想被扣——更何況,似乎我沒有扣您什麼東西吧。