計算機語言可以以變數名作為類型判斷么?

以變數名做為判斷變數類型的語言在實際運用中會不會存在什麼問題?(如果已經有這種語言請告訴是啥?)。這樣的語言變數不允許直接改變對象類型

例如:變數名以『s_·』 開始的是字元類型,以『i_』 開始的是整數類型,以『f_』 開始的浮點數類型。

這樣好處是在用戶在編程時,能夠很快確定數據類型,編譯器編譯起來也會快一些。

考慮到的一個問題是類型轉換,比如將int 類型變數『i_tt』 轉化為float 類型,我們可以在語法上強制要求『轉換類型必須賦值給另一個對象』,比如f_tt = float(i_tt)。在內存管理上類似於python 的引用指針,只要沒有指向i_tt 的引用指針,就將那段內存釋放。


於是我想起了神奇的Fortran:

變數名以I, J, K, L, M or N開頭的變數都默認聲明為INTEGER類型的。不用顯式聲明,可直接用。呃…習慣了也挺順手的。

題主想要的是用匈牙利記法中的Systems Hungarian記法來直接聲明變數類型。我不知道有沒有這樣做的編程語言流行過,不過毫無疑問肯定有人試過這樣做,因為挺容易想到的。

題主的這個問題或許能吸引想到過同樣做法的人來一起討論。也挺有趣~

然而其實這並不會讓編譯器編譯得更快——一點也不會。

靜態類型語言的編譯器一般會在變數聲明處記錄下變數的類型,放到符號表裡;後面就可以通過符號表裡記錄的信息來做類型檢查和推導。

題主建議的做法只是讓本來編譯器可以自動記錄在符號表裡的信息散布在源碼里而已,編譯器(一般)還是需要符號表,要做的工作並沒有減少多少。

至於讓程序員在編程時能一眼就看出類型,這是蘿蔔青菜各有所愛,看看大家對匈牙利記法的討論就知道自己站在討論的哪邊了。相信不喜歡匈牙利記法的人是一定不會喜歡強制使用這種記法的編程語言的…

我自己是不喜歡匈牙利記法的。但這只是我自己的習慣,並非對題主的習慣做評論。

組織良好的代碼應該盡量讓變數聲明的位置和使用的位置接近,這樣在使用處要找到聲明處也很近。

在現代IDE的輔助下,要知道一個變數是啥類型只要讓滑鼠懸浮在變數名上即可,也不需要用匈牙利記法。

另外在泛型編程時變數類型本來就是參數化的,並非固定類型,標記它的類型缺乏意義。


早期BASIC語言的變數名A是integer型的,A$是string型的,而且只能這樣命名區分(沒有integer這樣的關鍵字或者變數聲明語句)

後來又增加了這些…

A#,Double型

A,Long型

A!,Single型

A@,Currency型


很特別的,在 Haskell 里,標識符首字母的大小寫的確是影響了這個標識符的意義。首字母小寫的情況下,這是一個變數名 (variable identifier);首字母大寫的情況下,這是一個構造器名 (constructor identifier)。構造器名可以想像成 OOP 里的 Class 名。雖然不是嚴格意義上的影響了類型,不過確實是影響了語義。

這也帶來一個副作用:大家所習慣的,使用全大寫的 CONST_MAGIC = 0xf00ba233 來表示常量的寫法,在 Haskell 里並不能使用,因為變數名必須是小寫開頭。於是我們會看到這樣的怪異寫法:iNADDR_ANY。(當然也並不是說我們完全不能用全大寫來表示常量了,GHC 7.8 引入的 PatternSynonyms 允許我們這麼寫:VK_BUFFER_CREATE )

匈牙利命名法的思想,在 Haskell 里確實也有所體現。像 monad transformer 喜歡叫 SomeT,fixpoint datatype 喜歡叫做 SomeF。當然了,這麼做主要並不是為了體現它們的類型,而是為了防止名字重複(比如 SomeF 後面通常會跟著一個

type Some = Fix SomeF

)。

事實上,Haskell 經常為人所詬病的一點也和變數命名相關。*極其*抽象的泛型變數應該如何命名?EdwardKmett 的 Lens 為我們上了一課:lens/Type.hs。相比之下還是 Tekmo 的 Pipes 更加友好一些,畢竟有圖來幫助理解:Haskell-Pipes-Library/Pipes.hs,但是還是很難懂。必須承認,這些命名雖然極為晦澀,但是只要搞明白了的話卻會發現它們很簡潔準確。

————————————————

以上是口胡。

從程序員的角度來看,我還是認為變數名應該人性化一些,要做到簡潔準確,其它的功能(顯示類型,跳轉定義,改名,移動,等等)還是應該交給 IDE 來處理,畢竟代碼主要的意義還是給人看的。


現在你覺得int不太好,想改成float,咋辦呢?

如果是int i,直接改成float i就行了。

但如果是i_i,你得打開ide,搜索所有i_i,替換成f_i,而且還要進行正則表達式匹配,避免i_item被替換成f_item。

累不累?

現在匿名回答都有次數限制了,我也是醉了。。


匈牙利命名法就是按你說這麼搞,然並卵,那個命名法僅對記事本純手碼用戶有意義。


可以,但是這是中學生的思路:即,隨性發明新的特殊規則。一般來說,特殊規則越多的語言越下品


技術上完全做得到。

但是編譯速度真的不差那麼一點點。而且編譯器如果每次遇到變數都對變數名做字元串前綴的解析來獲得類型的話,我認為應該會比現在處理的速度要慢。

另外,就說實際使用,問題也有很多:

  1. 對於struct/union/class等自定義類型怎麼辦?
  2. 如果某變數一開始是int,後來發現會溢出而需要改為int64_t,需要大量的全文替換。
  3. 接上一條,如果同時存在i_a和i_a_tmp,現在只需要改i_a的話,恐怕還不能簡單的用編輯器的文本替換功能(起碼得是正則)。


Tcl/Tk裡面首字母大寫的變數是局部函數/變數,小寫開頭的是全局函數/變數

OCaml裡面只有module可以開頭大寫


這樣做是可以的,也確實在某種意義上可以讓閱讀者更一目了然,但是並不會有更快的編譯速度。

因為編譯的實際過程中,有一個構造符號表的階段,在這一步,編譯器確定變數的類型,然後填充符號表,在以後的過程中,都是查找符號表獲取變數的類型信息,而不是再去掃描源代碼獲取變數的類型信息。

所以,一般地,形如int a,b,c;的語句。當編譯器讀到int這裡的時候,就知道接下來的變數都是int類型,只需要一下子掃描完然後填充符號表即可,不需要分割變數名(當然其實是有一個判斷變數名是否重複的階段)。

而如果採用題主的方式,當讀到i_a的時候,編譯器需要停下來,看看開頭是什麼,然後確定變數類型,填充符號表然後繼續掃描。顯然,不會提升編譯的速率,更有可能的是有一點微小的下降。

在並沒有顯著提升的時候還帶來了什麼問題呢?

一方面是更多的不自由,這是顯然的,不要多講。

另一方面,是重構火葬場。

當想改變某些變數的類型的時候,以前只需要在聲明的地方做更改即可,現在卻需要做大範圍的全局替換,誰也不知道這樣粗暴的全局替換會不會出什麼大婁子。


實現起來沒問題,但是沒必要

你現在也完全可以寫 int i_a = 1 / float f_a = 1.5

(當然只能靠自律當成你的一種代碼規範

至於名字改變語義的話,除了 @方澤圖 說的 Haskell 之外類似的還有 Prolog 和 Erlang


這應該是一種代碼規範,雖然沒有人強迫你用,但你自己用起來很舒適,簡直assert都不需要

看到變數名就知道是什麼類型多好,雖然長了些,但是對值進行控制,值的!!


首先,我覺得lz說的編譯器會編譯的快一些,我並不認同。

比如說c語言,變數怎麼命名應該對編譯並不產生影響。

lz的意思貌似是在輸入變數的時候不指定類型,讓編譯器自己根據前綴來判斷,那也就是不屬於上面我說的語言這種,需要聲明的時候指定類型的語言,如果我理解的對,lz其實應該把這一點說清楚。

其實lz這個想法有點繁瑣,想在編碼的時候順便幫編譯器解決點麻煩,另外也能保證程序的閱讀性。所以lz平時應該是int i這種程序員,又不想敲這個int。

現在開發語言的方向,一般是兩種,一種是老式的,需要指定類型,比如說c,vb,Java,另外一種是根本弱化類型的,比如說python。

lz大可以用python,按照你的命名規範來寫程序就是了,好能讓人一眼看出來,你是一個從其他老式語言轉過來的人,就像別人看我一樣,呵呵呵。

我覺得你如果喜歡一種命名規範,或者有自己的命名規範,客觀條件也允許,例如公司不強制要求,那你就去做好了,完全不用上綱上線,非得找出別的理由。

而且像python這種,弱化類型的概念,有完善的隱式類型轉換機制,其實已經在暗示作者的意圖。

你既然有這個想法,是可以自己開創流派的,何必非得拿武當的心法練崑崙的招式。

程序怎麼寫,只要符合規定的語法,編譯器是不care的,對它來說基本是一樣的。

弱化類型的語言,一般也是在賦值的這一步分析類型的。

或者你站在更高的角度來看,類型只是人為的為了好理解而增加的概念,便於控制值域等等,編譯成二進位,還不都是一樣。

一切都只是內存。


很有想法;然而僅看到了狹小的局部,忘了抬頭看看。

這是缺乏足夠項目經驗者的通病。

他們往往只能看到一時的利好;卻不知道,具有一定複雜度的軟體項目,其基礎部分並不是僵死的、如同建築基石、支柱一樣的東西;而是活的、會隨著項目進展而延伸、影響整個項目演變方向的。

這就導致,局部看似「無傷大雅」的修改,很容易衍變出意想不到的問題。

拿這個問題來說,應該這樣分析。

1、先看局部

直接綁定變數類型到變數名之中,的確可以做到「類型綁定到變數名」,於是隨處皆可直接訪問。

然後,考慮「傳統」的符號表式實現,需要按照變數作用域維護幾個符號表;遇到變數名,查表,確定類型,然後生成代碼;其中這個查表動作,複雜度為logN——對數複雜度。

題主的實現,相當於用變數首幾位字元作為索引,查一個較小的 字元-類型 表,從而避免到稍微大一些的符號表中搜索。這個動作,如果實現的很好,複雜度同樣是logN。

鑒於類型表往往可能比符號表略小;那麼 確定變數類型 這個動作,平均來說的確是可以比搜索符號表少執行幾步。

然而,這個分析實在是太過局部了。我們不妨想深一步。比如,這個問題:「確定變數類型」並不是編譯所需的全部動作。

這意味著,即便知道了變數類型,我們仍然不得不搜索符號表。否則無以確定某個變數是局部變數還是全局變數、以及確定它最初被映射在內存的哪個位置。

這一步是絕繞不過去的。

——變數名只是個助記符,它最終一定要變成目標代碼中的一個固定的內存地址。這是常識。

「傳統」方案里,我們可以把變數類型一起存在符號表中—— 一旦找到了變數 var8899 在符號表中對應的條目,那麼該條目的欄位1可能是它的內存地址、欄位2可能就是變數類型。

那麼,既然已經查詢符號表了,顯然直接讀相關行的第二個元素便能取得數據類型,開銷為0;而題主的方案,藉助變數名首幾個字元去查類型,複雜度卻是O(logN)——換句話說,傳統方案中,「解析變數數據類型」並無額外開銷;而題主方案反而引入了一個查表開銷。

綜上,這個方案看似一個局部優化;但哪怕只是想深一步,就會發現它反而不僅要多維護一個 首字元-類型 表、還必須考慮大量變數類型如何在「開頭幾個字元」這個含混區域內正確區分和識別等棘手問題、因而白白增加了實現複雜度,還額外增加而不是減少了執行開銷。

這顯然不是一個聰明的方案。

——不要過早優化這句忠告,並不是前人拍腦袋拍出來的。

2、還是讓我們把眼光放的稍微長遠一些吧

雖然這個方案連局部分析都過不去;但對常規項目來說,前面的分析還是太過具體了,壓根就沒觸及這種錯誤思路真正的要害

那麼,不妨假設題主的方案的確在局部起到了良好作用;現在,我們嘗試站在更高一些的位置,看看這個修改會帶來什麼。

身為軟體用戶時,我們一般把類似「自動聯動」的行為叫做「自動化」「傻瓜化」,並不必深入考慮太多。

然而,身為軟體工程師時,面對任何「聯動」相關的東西,我們腦中必須馬上閃過一個詞。

沒錯,就是「耦合」。

題主的方案,實質上就是讓 變數類型 和 變數名首字元 發生耦合。

合格的軟體工程師,一旦瞥見「耦合」二字,恐怕都不免菊花一緊。

當然,「耦合」未必全都是壞事。比如python把 縮進 和 邏輯區分代碼塊 耦合起來,效果似乎還不錯(雖然頗有爭議)。

但,絕大多數情況下,尤其是底層/基礎部分,「耦合過重」幾乎已經可以和「項目失敗」划上等號了——而且還是「代碼量暴增、項目曠日持久、邏輯錯綜複雜,最後不堪重負嬌喘微微然後過勞死」這種最憋屈的失敗。

回到這個話題。

一旦變數類型和變數名出現了耦合,那麼,必然的:

a、難以支持泛型或可變類型

b、難以支持用戶自定義類型,至少也會使得自定義類型變數的名字變得冗長、聲明語法怪異

c、難以支持類-繼承體系(尤其是實現了多個介面的類),相關代碼必然變得晦澀、怪異

d、由於用戶自定義類型的加入,如MyClass、MyClass1(前綴相同的不同類)、MyClass_Extend1(繼承自MyClass的類)、MyClass_Object1(MyClass的實例)等等命名,顯然太過隨意,不可能用程序正確處理了。

於是,你就必須想辦法制定個複雜的命名/解析規則,要求用戶遵守——現在,變數命名居然會命名出語法錯誤了。

再讓我們考慮最簡單的一種方案吧:比如,你可以把"_"當成類似關鍵字的東西來處理,規定它僅允許用於區隔變數類型,不允許用戶隨意使用它——就好像「傳統」方案里空格的用法一樣。

那麼,這種做法,在事實上已經蛻變成了「用戶必須不厭其煩的、在每一次用到變數時聲明它,而編譯器則必須能夠識別哪是真正的變數聲明、哪些只是變數的引用」——編譯器實現者累,它的用戶,更累。

但你得到的,只不過是「變數聲明/使用時,必須全部用類似變數聲明的語法,只是用_替代空格,以便讓它看起來像個變數名」而已——除了怪異、容易出錯,讓使用者摸不著頭腦,沒有半點好處。

當然,僅僅耦合變數命名和變數類型這兩個概念,後果還不算太嚴重,仍在可控範圍之內(尤其如其他答案提到的、極其有限範圍內的「語法糖式」用法案例,是沒有太大問題的);可一旦如此隨意的耦合十數個概念……

再說一遍:軟體設計,尤其是基礎設施的設計里,「耦合」是必須盡量避免的東西。

換句話說:所有偏底層偏複雜的項目里,和初學者幻想的相反,耦合若干個基礎概念以得到某種便利的想法,最終都會被證明是「撿了芝麻丟了西瓜」——別說故意耦合了,你就是理解稍有不到位、沒能正確完成基本概念的正交分解工作,最終寫出來的東西就不可能有很大的復用價值。這就是庫設計要比應用軟體設計難得多得多的原因。

——高內聚,低耦合,這可是軟體工程最為基礎的設計原則哦。


匈牙利命名法,你會想燒死自己的。

在現代完全沒必要這麼做,但是萬一想這麼做的話,一定要從一而終,在自定義類型上設置異端裁判所,不符合主教誨的統統燒死。


看了各家答案。

天地初開,型名不分。

過三十載,型前名後。

又三十載,名前型後。


defint a-z


php和perl不就是這樣嗎


我見過的所有fortran代碼都有一句implicit none


不考慮任何效率問題,也會造成更高的耦合

爸爸,我真的很怕耦合啊

不過題主能提出這個問題,雖然不可行,但是可見題主很有想法,贊


並不會減少什麼編譯階段的工作,建議題主有空的時候學習一下編譯原理


推薦閱讀:

大學的軟體工程比技校強在哪裡?
在計算機中utility應該怎麼翻譯?
要理解王垠的研究,就數學上而言,需要達到什麼層次?
有哪些值得一看的數學家、物理學家或者計算機科學家的傳記?
數學不好能深入學習計算機嗎?

TAG:計算機 | 計算機科學 | 計算機專業 | 編譯原理 | 計算機語言 |