Boo(14)-內建函數:輸入與輸入

print、gets、prompt

print 就是調用 Console.WriteLine() 而已,官方建議使用 print macro,而不要使用這個函數。
gets 從標準輸入取得一個字串,實際上就是調用 Console.ReadLine()。
prompt 是 Console.ReadLine() + Console.Write() 的組合技,在印出你給的提示訊息之後,會接著從標準輸入取得字串。

從標準輸入取得字串的意思就是,畫面會停住,等你輸入字元,直到你按下 Enter 之後,才把你輸入的字元放到字串裡傳回。

print("Hello")
s = gets()
print s
s = prompt("Please input something:")
print s

當然,除了這些函數以外,你還是可以直接使用 .NET Framework 裡的 System.IO 來處理。

Boo(13)-內建函數:shell 類

shell()、shellp()、shellm()
顧名思義,就是執行外部的程式。

shell() 會等待外部程式執行完成以後,回傳一個字串,字串裡是執行的結果。
shellp() 不會等待外部程式執行完成,會直接回傳 Process 物件,事實上,shell() 也呼叫了這個函數,只是 shell() 拿到 Process 物件以後,利用 Process.StandardOutput() 去讀取執行結果,並使用 Process.WaitForExit() 等待程序執行完成。
shellm() 也是執行外部程式,但這個外部程式必須是 Managed,也就是 .NET 應用程式。老實說,看了 boo 源碼以後,我不是很懂。源碼裡面是建立一個新的 AppDomain,載入指定的程式,然後找到 EntryPoint 並執行。我猜想,這樣的作法主要用來避免再次建立新程序、啟動 CLR,在 CPU、記憶體使用上會比較有效率。如果你的外部程式正好也是 .NET 應用程式的話,就用 shellm(),我想會比較好。

input = shell( "booc.exe", "" )

電影流水帳(2008/05/14~2008/05/20)

每年推的片子應該都超過百部吧~假設每部片子都到電影院去看早場,早場票價是200元,那麼這樣的花費就會是 100*200 = 20000 元;看二輪片,而二輪片票價是 110 元兩部片子的話,則是 50*110 = 5500 元;至於 DVD,百視達新片一片 80 元的話,100*80 = 8000 元。無聊的計算?!

  • 明日的記憶。這部片子非常適合作為阿茲海默症的宣導片子,幾乎把所有可能發生的情況都演出來了,很容易讓人理解患病之後,會發生什麼事情。說來,老年痴呆症(阿茲海默症,另類的絕症!)真的是很令人無力啊~我的外公在晚年也罹患了這種疾病,舅舅照顧得很辛苦~在前年的時候,外公走了,從病痛中解脫。嗯嗯,照這樣看來,我也有阿茲海默症的可能性,是不是該及早做好準備呢?
  • 劇場版「NARUTO-ナルト-疾風伝」(Wikipedia),火影忍者-疾風傳。嗯嗯,就是卡通啦,沒什麼特別好說的。

P.S. 印象中二輪片票價是 110 元,我已經有超過五年以上沒去看過了吧,所以這票價是五、六年前的票價。

booc 的 49 道工法

從 Visual Studio debugger 裡面截出來的…想不到編譯需要這麼多步驟…

-		_items	{維度:[64]}	object[]
+		[0]	{Boo.Lang.Parser.BooParsingStep}	object {Boo.Lang.Parser.BooParsingStep}
+		[1]	{Boo.Lang.Compiler.Steps.InitializeTypeSystemServices}	object {Boo.Lang.Compiler.Steps.InitializeTypeSystemServices}
+		[2]	{Boo.Lang.Compiler.Steps.PreErrorChecking}	object {Boo.Lang.Compiler.Steps.PreErrorChecking}
+		[3]	{Boo.Lang.Compiler.Steps.ExpandAstLiterals}	object {Boo.Lang.Compiler.Steps.ExpandAstLiterals}
+		[4]	{Boo.Lang.Compiler.Steps.MergePartialClasses}	object {Boo.Lang.Compiler.Steps.MergePartialClasses}
+		[5]	{Boo.Lang.Compiler.Steps.InitializeNameResolutionService}	object {Boo.Lang.Compiler.Steps.InitializeNameResolutionService}
+		[6]	{Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces}	object {Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces}
+		[7]	{Boo.Lang.Compiler.Steps.TransformCallableDefinitions}	object {Boo.Lang.Compiler.Steps.TransformCallableDefinitions}
+		[8]	{Boo.Lang.Compiler.Steps.BindTypeDefinitions}	object {Boo.Lang.Compiler.Steps.BindTypeDefinitions}
+		[9]	{Boo.Lang.Compiler.Steps.BindGenericParameters}	object {Boo.Lang.Compiler.Steps.BindGenericParameters}
+		[10]	{Boo.Lang.Compiler.Steps.BindNamespaces}	object {Boo.Lang.Compiler.Steps.BindNamespaces}
+		[11]	{Boo.Lang.Compiler.Steps.BindBaseTypes}	object {Boo.Lang.Compiler.Steps.BindBaseTypes}
+		[12]	{Boo.Lang.Compiler.Steps.BindAndApplyAttributes}	object {Boo.Lang.Compiler.Steps.BindAndApplyAttributes}
+		[13]	{Boo.Lang.Compiler.Steps.ExpandMacros}	object {Boo.Lang.Compiler.Steps.ExpandMacros}
+		[14]	{Boo.Lang.Compiler.Steps.IntroduceModuleClasses}	object {Boo.Lang.Compiler.Steps.IntroduceModuleClasses}
+		[15]	{Boo.Lang.Compiler.Steps.NormalizeStatementModifiers}	object {Boo.Lang.Compiler.Steps.NormalizeStatementModifiers}
+		[16]	{Boo.Lang.Compiler.Steps.NormalizeTypeAndMemberDefinitions}	object {Boo.Lang.Compiler.Steps.NormalizeTypeAndMemberDefinitions}
+		[17]	{Boo.Lang.Compiler.Steps.BindTypeDefinitions}	object {Boo.Lang.Compiler.Steps.BindTypeDefinitions}
+		[18]	{Boo.Lang.Compiler.Steps.BindGenericParameters}	object {Boo.Lang.Compiler.Steps.BindGenericParameters}
+		[19]	{Boo.Lang.Compiler.Steps.BindEnumMembers}	object {Boo.Lang.Compiler.Steps.BindEnumMembers}
+		[20]	{Boo.Lang.Compiler.Steps.BindBaseTypes}	object {Boo.Lang.Compiler.Steps.BindBaseTypes}
+		[21]	{Boo.Lang.Compiler.Steps.BindMethods}	object {Boo.Lang.Compiler.Steps.BindMethods}
+		[22]	{Boo.Lang.Compiler.Steps.ResolveTypeReferences}	object {Boo.Lang.Compiler.Steps.ResolveTypeReferences}
+		[23]	{Boo.Lang.Compiler.Steps.BindTypeMembers}	object {Boo.Lang.Compiler.Steps.BindTypeMembers}
+		[24]	{Boo.Lang.Compiler.Steps.ProcessInheritedAbstractMembers}	object {Boo.Lang.Compiler.Steps.ProcessInheritedAbstractMembers}
+		[25]	{Boo.Lang.Compiler.Steps.CheckMemberNames}	object {Boo.Lang.Compiler.Steps.CheckMemberNames}
+		[26]	{Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping}	object {Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping}
+		[27]	{Boo.Lang.Compiler.Steps.PreProcessExtensionMethods}	object {Boo.Lang.Compiler.Steps.PreProcessExtensionMethods}
+		[28]	{Boo.Lang.Compiler.Steps.UnfoldConstants}	object {Boo.Lang.Compiler.Steps.UnfoldConstants}
+		[29]	{Boo.Lang.Compiler.Steps.OptimizeIterationStatements}	object {Boo.Lang.Compiler.Steps.OptimizeIterationStatements}
+		[30]	{Boo.Lang.Compiler.Steps.BranchChecking}	object {Boo.Lang.Compiler.Steps.BranchChecking}
+		[31]	{Boo.Lang.Compiler.Steps.CheckIdentifiers}	object {Boo.Lang.Compiler.Steps.CheckIdentifiers}
+		[32]	{Boo.Lang.Compiler.Steps.StricterErrorChecking}	object {Boo.Lang.Compiler.Steps.StricterErrorChecking}
+		[33]	{Boo.Lang.Compiler.Steps.CheckAttributesUsage}	object {Boo.Lang.Compiler.Steps.CheckAttributesUsage}
+		[34]	{Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions}	object {Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions}
+		[35]	{Boo.Lang.Compiler.Steps.ProcessAssignmentsToValueTypeMembers}	object {Boo.Lang.Compiler.Steps.ProcessAssignmentsToValueTypeMembers}
+		[36]	{Boo.Lang.Compiler.Steps.ExpandProperties}	object {Boo.Lang.Compiler.Steps.ExpandProperties}
+		[37]	{Boo.Lang.Compiler.Steps.RemoveDeadCode}	object {Boo.Lang.Compiler.Steps.RemoveDeadCode}
+		[38]	{Boo.Lang.Compiler.Steps.CheckMembersProtectionLevel}	object {Boo.Lang.Compiler.Steps.CheckMembersProtectionLevel}
+		[39]	{Boo.Lang.Compiler.Steps.NormalizeIterationStatements}	object {Boo.Lang.Compiler.Steps.NormalizeIterationStatements}
+		[40]	{Boo.Lang.Compiler.Steps.ProcessSharedLocals}	object {Boo.Lang.Compiler.Steps.ProcessSharedLocals}
+		[41]	{Boo.Lang.Compiler.Steps.ProcessClosures}	object {Boo.Lang.Compiler.Steps.ProcessClosures}
+		[42]	{Boo.Lang.Compiler.Steps.ProcessGenerators}	object {Boo.Lang.Compiler.Steps.ProcessGenerators}
+		[43]	{Boo.Lang.Compiler.Steps.ExpandVarArgsMethodInvocations}	object {Boo.Lang.Compiler.Steps.ExpandVarArgsMethodInvocations}
+		[44]	{Boo.Lang.Compiler.Steps.InjectCallableConversions}	object {Boo.Lang.Compiler.Steps.InjectCallableConversions}
+		[45]	{Boo.Lang.Compiler.Steps.ImplementICallableOnCallableDefinitions}	object {Boo.Lang.Compiler.Steps.ImplementICallableOnCallableDefinitions}
+		[46]	{Boo.Lang.Compiler.Steps.CheckNeverUsedMembers}	object {Boo.Lang.Compiler.Steps.CheckNeverUsedMembers}
+		[47]	{Boo.Lang.Compiler.Steps.EmitAssembly}	object {Boo.Lang.Compiler.Steps.EmitAssembly}
+		[48]	{Boo.Lang.Compiler.Steps.SaveAssembly}	object {Boo.Lang.Compiler.Steps.SaveAssembly}

第 0 步由 Boo.Lang.Compiler.Pipelines.Parse (src\Boo.Lang.Compiler\Pipelines\Parse.cs) 加入。
第 1~27 步由 Boo.Lang.Compiler.Pipelines.ResolveExpressions (src\Boo.Lang.Compiler\Pipelines\ResolveExpressions.cs) 加入。
第 28~46 步由 Boo.Lang.Compiler.Pipelines.Compile (src\Boo.Lang.Compiler\Pipelines\Compile.cs)加入。
第 47 步由 Boo.Lang.Compiler.Pipelines.CompileToMemory (src\Boo.Lang.Compiler\Pipelines\CompileToMemory.cs) 加入。
第 48 步由 Boo.Lang.Compiler.Pipelines.CompileToFile (src\Boo.Lang.Compiler\Pipelines\CompileToFile.cs)加入。

這些步驟都是利用繼承的關係建立起來的:CompileToFile -> CompileToMemory -> Compile -> ResolveExpressions -> Parse
只應用了繼承的威力…

Boo(12)-函數

函數定義方法很簡單,比較特別的就是不定個數變數。

// Say
def Say( s as string):
print s
// 也是 Say
def Say( i as int):
print i
// 不定個數
def Say(*args as (object)):
print "len(args)=${len(args)}"
for arg in args:
print arg
// 求平方
def pow( i as int ) as int:
return i*i
Say( "Hello world!" )
Say( 20 )
Say( pow( 2 ) )
Say( 1, "s", join(range(10)) )
a = (5, 8, 1, "end")
Say(*a)

as string、as int…等,其實都可以省略不寫,別忘了 Boo 會自動判定。
然後有看到 Say() 定義了三次嗎?是的,Boo 支援多載(overloading)。
不定個數變數,定義的方法比較特別,要加上 *,然後用法就當作是 enumerator 來用就行了。

ILMerge

這工具可以讓你把 .Net 不同語言編譯出來的 Assembly (組件)合併在一起。
官方網址:ILMerge
安裝以後,用法很簡單:

"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:library /out:[輸出檔名] /lib:[Assembly搜索路徑] [要合併的 Assembly 1] [要合併的 Assembly 2] ...

只想給客戶一個可執行檔,不想給一堆其他組件的時候,這樣作也行:

"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:[exe或winexe] /out:[輸出檔名] /lib:[Assembly搜索路徑] [執行檔] [要合併的 Assembly 1] [要合併的 Assembly 2] ...

對,合併以後,檔案絕對變大,然後千萬不要忘記了,要測試。另外,ILMerge 文件(ILMerge.doc)裡面有些限制以及問題,甚至是用法都有詳細描述,要記得閱讀…

switch-case in boo

Boo本身並沒有類似 switch-case 語法,但是可以藉著 macro 來做到,Boo extensions這個專案已經寫好了。
由於這個專案沒有釋出二進位碼,所以你需要自己 checkout 並編譯。

編譯以後,用法也很簡單,一看就能懂了。

import Boo.PatternMatching  // match 與 case 這兩個 macro 都在這裡面
def getEnglish( i as int ) as string:
s = ""
match i:
case 0:
s = "zero"
case 1:
s = "one"
case 2:
s = "two"
case 3:
s = "three"
otherwise:
s = "unknown"
return s
l = array( typeof(int), range( 5 ) )
for item in l:
print getEnglish( item )

未來 Boo extensions 會包進 Boo 嗎?很難說…Boo extensions 目前仍然很具實驗性…

P.S.

  • 編譯Boo extensions前,請下載最新的 Boo,然後解壓縮以後,放到跟 boo-extensions 同一層。再切換到 boo-extensions/extensions 下執行 nant 即可。
  • 如果 Boo extensions 無法編譯成功,試著修改 extensions/default.build 將編譯 .Test.dll 的幾個地方註解掉,再次編譯即可。這些 .Test.dll 其實是用不到的。

電影流水帳(2008/05/03~2008/05/13)

Eva Green真的正,The Golden Compass裡又再次與Daniel Craig合作,只是沒有對手戲…

  • The Golden Compass(IMDB, Wikipedia),中譯:黃金羅盤。Eva Green還是一樣很正啊,IMDB上說她有演過Arsène Lupin呢,不知道好不好看~言歸正傳,說到這部片子…嗯~或許小說會很好看吧~
  • Untraceable(IMDB, Wikipedia),中譯:Live殺人網站。誠如我老妹所說,的確是普普通通。以技術上來說,要能做到這樣的 live 網站,視訊部份可能需要 P2P TV 的技術,這樣應該可以得到一定的流暢度;以 Blog 來說,要能不被塞爆,恐怕是比較難,會需要比較多台機器…只是,要封一個網站會有多難呢?聯絡ICANN之類的單位把該網域給封了,或是跟這些單位要資訊去查 IP 來源,應該很快就能找到人了吧~這故事算是在騙不懂網路的人吧~

Boo(11)-Hash

Hash 的用法很簡單,同樣地,跟 array、List 一樣,可以用很簡潔的方式來表示,也就是大括號 { }
或者,也可以將符合 key、value 格式的有 IEnumerable 介面的變數傳入 Hash() 函數來取得。

h1 = { 'a': 65, 'b': 66, 'c': 67 }
print h1['a']
h2 = Hash( ( ('a',65), ('b',66), ('c',67) ) )
h3 = Hash( [ ('a',65), ('b',66), ('c',67) ] )

沒有 Generic 版本的 Hash 可以參考 src/boo.lang/Hash.cs,它其實是繼承自 Hashtable﹔有 Generic 版本的,就直接參考 System.Collections.Generic 裡面的 Hash 吧~