<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Thinking more...-Boo</title>
<link>http://blog.roodo.com/thinkingmore/archives/cat_427853.html</link>
<description>Just thinking more...&amp;nbsp;訂閱 RSS














  google.load(&quot;jquery&quot;, &quot;1.2&quot;);
  google.setOnLoadCallback( function() {
    _uacct = &quot;UA-97150-7&quot;;
    urchinTracker();
    if( dp!=&#039;undefined&#039; ) {
      $(&quot;pre &gt; br&quot;).each( function() { $(this).replaceWith( &quot;\n&quot; ); } );
      $(&quot;textarea &gt; br&quot;).each( function() { $(this).replaceWith( &quot;\n&quot; ); } );
      dp.SyntaxHighlighter.ClipboardSwf = &#039;http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/clipboard.swf&#039;;
      dp.SyntaxHighlighter.HighlightAll(&#039;code&#039;);
    }
  } );

</description>
<language>zh-tw</language>
<generator>Roodo Blog System</generator>
<copyright>All Rights Reserved</copyright>
<atom:link href="http://blog.roodo.com/thinkingmore/archives/cat_427853.xml" rel="self" type="application/rss+xml" />
<item>
	<title>booish 與 booc 編譯後的執行結果不同?</title>
	<description><![CDATA[
			在Boo Programming Language網上論壇發現了這個討論串：Problems with BooPrimer
發問者表示同樣的程式在 booish 執行與用 booc 編譯後的執行結果不同，我大吃一驚，趕緊試試，發現真的是跟發問者講的一樣，心想完蛋，怎麼會這樣...


i = 0
while i < 5:
    print i
    i += 1 


隔了一天，有人(Stoo)回覆了，說 booish 在執行結束後，會再次印出 i 的值，並建議改成這樣，可以更能看出問題所在：

i = 0
while i < 5:
    print "i=${i}"
    i += 1 


果然，執行結果就如同他回覆所說的一樣：
i = 0
i = 1
i = 2
i = 3
i = 4
5 


		]]>
	</description>
	<content:encoded><![CDATA[
			在<a href="http://groups.google.com/group/boolang/">Boo Programming Language網上論壇</a>發現了這個討論串：<a href="http://groups.google.com/group/boolang/browse_thread/thread/dad38182b4dbfed7">Problems with BooPrimer</a>
發問者表示同樣的程式在 booish 執行與用 booc 編譯後的執行結果不同，我大吃一驚，趕緊試試，發現真的是跟發問者講的一樣，心想完蛋，怎麼會這樣...

<pre name="code" class="python">
i = 0
while i < 5:
    print i
    i += 1 
</pre>

隔了一天，有人(<a href="http://groups.google.com/groups/profile?enc_user=sJFSKRQAAAAaRAlLpkV5NELC-oW_ziylTltHAfOLnoeqka26WkCssg">Stoo</a>)回覆了，說 booish 在執行結束後，會再次印出 i 的值，並建議改成這樣，可以更能看出問題所在：
<pre name="code" class="python">
i = 0
while i < 5:
    print "i=${i}"
    i += 1 
</pre>

果然，執行結果就如同他回覆所說的一樣：<pre>
i = 0
i = 1
i = 2
i = 3
i = 4
5 
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/7095965.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/7095965.html</guid>
	<category>Boo</category>
	<pubDate>Tue, 02 Sep 2008 17:35:19 +0800</pubDate>
</item>
<item>
	<title>在 ASP.Net 裡使用 Boo</title>
	<description><![CDATA[
			方法很簡單，只要修改 web.config，然後把 Boo 相關的 assembly 放到 bin 目錄下即可：
&lt;configuration&gt;
	&lt;system.web&gt;
		&lt;compilation debug=&quot;true&quot;&gt;
			&lt;assemblies&gt;          
				&lt;add assembly=&quot;Boo.Lang.CodeDom&quot; /&gt;
			&lt;/assemblies&gt;
			&lt;compilers&gt;
				&lt;compiler language=&quot;Boo&quot; extension=&quot;.boo&quot; type=&quot;Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom&quot; compilerOptions=&quot;-ducky -utf8&quot;/&gt;
			&lt;/compilers&gt;
		&lt;/compilation&gt;
		&lt;customErrors mode=&quot;Off&quot;/&gt;
	&lt;/system.web&gt;
&lt;/configuration&gt;


要注意的是，如果你的應用程式不是 code behind 而且 Hosting 是 IIS 或是 .NET framework 內建的小 web server 時，會有問題。問題出在 Indent，Boo 對於 Indent 很敏感，不知道為甚麼，在 Microsoft.NET 下，Indent 就是會錯。使用Mono XSP的話，則沒有問題。
是故，你可以改使用 code behind 的方式繞過這問題。

會發現這問題，是因為有人在 boolang 討論群組裡問了這問題：boo on asp.net，我去試才知道的。最後提問者改用 xsp...

		]]>
	</description>
	<content:encoded><![CDATA[
			方法很簡單，只要修改 web.config，然後把 Boo 相關的 assembly 放到 bin 目錄下即可：<pre name="code" class="xml">
&lt;configuration&gt;
	&lt;system.web&gt;
		&lt;compilation debug=&quot;true&quot;&gt;
			&lt;assemblies&gt;          
				&lt;add assembly=&quot;Boo.Lang.CodeDom&quot; /&gt;
			&lt;/assemblies&gt;
			&lt;compilers&gt;
				&lt;compiler language=&quot;Boo&quot; extension=&quot;.boo&quot; type=&quot;Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom&quot; compilerOptions=&quot;-ducky -utf8&quot;/&gt;
			&lt;/compilers&gt;
		&lt;/compilation&gt;
		&lt;customErrors mode=&quot;Off&quot;/&gt;
	&lt;/system.web&gt;
&lt;/configuration&gt;
</pre>

要注意的是，如果你的應用程式不是 code behind 而且 Hosting 是 IIS 或是 .NET framework 內建的小 web server 時，會有問題。問題出在 Indent，Boo 對於 Indent 很敏感，不知道為甚麼，在 Microsoft.NET 下，Indent 就是會錯。使用<a href="http://www.mono-project.com/ASP.NET">Mono XSP</a>的話，則沒有問題。
是故，你可以改使用 code behind 的方式繞過這問題。

會發現這問題，是因為有人在 boolang 討論群組裡問了這問題：<a href="http://groups.google.com/group/boolang/browse_thread/thread/ea9bbfeb9985cc2a">boo on asp.net</a>，我去試才知道的。最後提問者改用 xsp...
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6859721.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6859721.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 20 Aug 2008 16:38:49 +0800</pubDate>
</item>
<item>
	<title>讓 Banshee 啟動時自動播放音樂之二</title>
	<description><![CDATA[
			每次都從第一首播放，實在太沒意思，所以在播放前切換為 Shuffle 模式，播放時，就會隨機挑選一首開始播放，然後再關閉 Shuffle 模式。


import System
import System.IO
import Banshee.ServiceStack
import Banshee.PlaybackController

def AutoPlay() as bool:
        ServiceManager.PlaybackController.ShuffleMode = PlaybackShuffleMode.Song
        ServiceManager.PlayerEngine.Play()
        ServiceManager.PlaybackController.ShuffleMode = PlaybackShuffleMode.Linear

def OnClientStarted( client as Client ):
        Hyena.Log.Information( "engine is playing now..." )
        GLib.Timeout.Add(1500, AutoPlay)
        Banshee.ServiceStack.Application.ClientStarted -= OnClientStarted

Hyena.Log.Information( "autoplay script is loaded." )

Banshee.ServiceStack.Application.ClientStarted += OnClientStarted


p.s. 上次有提到要作自動記錄播放與自動播放記錄曲目的功能，我的確是做了，只是在播放完指定曲目後，又跳回第一首，這表示我還得繼續研究原始碼才行，所以暫時不釋出。

		]]>
	</description>
	<content:encoded><![CDATA[
			每次都從第一首播放，實在太沒意思，所以在播放前切換為 Shuffle 模式，播放時，就會隨機挑選一首開始播放，然後再關閉 Shuffle 模式。

<pre name="code" class="python">
import System
import System.IO
import Banshee.ServiceStack
import Banshee.PlaybackController

def AutoPlay() as bool:
        ServiceManager.PlaybackController.ShuffleMode = PlaybackShuffleMode.Song
        ServiceManager.PlayerEngine.Play()
        ServiceManager.PlaybackController.ShuffleMode = PlaybackShuffleMode.Linear

def OnClientStarted( client as Client ):
        Hyena.Log.Information( "engine is playing now..." )
        GLib.Timeout.Add(1500, AutoPlay)
        Banshee.ServiceStack.Application.ClientStarted -= OnClientStarted

Hyena.Log.Information( "autoplay script is loaded." )

Banshee.ServiceStack.Application.ClientStarted += OnClientStarted
</pre>

p.s. 上次有提到要作自動記錄播放與自動播放記錄曲目的功能，我的確是做了，只是在播放完指定曲目後，又跳回第一首，這表示我還得繼續研究原始碼才行，所以暫時不釋出。
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6540335.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6540335.html</guid>
	<category>Boo</category>
	<pubDate>Tue, 22 Jul 2008 09:39:14 +0800</pubDate>
</item>
<item>
	<title>用 Boo 寫 Web Service</title>
	<description><![CDATA[
			必須先將以 Boo 寫的 Web Service 編譯為 Assembly，然後再製作一個以 c# 或 vb.net 寫的 asmx 繼承該 Web Service 類別才行。
否則會遇到 "The invoked member is not supported in a dynamic module." 的錯誤。

我是在遇到錯誤的時候，去參考 boo 源碼 examples/asp.net 下的 Math.asmx 與 Math.asmx.boo 才知道這件事情的。
本來我還在納悶，為甚麼 examples/asp.net 下會有一個用 c# 寫的 asmx，還以為是搞錯了呢～


// Math.asmx.boo
// 要先編譯好，放在 bin 目錄下：booc -t:library -out:bin/Math.dll Math.asmx.boo
import System.Web.Services

[WebService]
class Math:
        [WebMethod]
        def Add(a as int, b as int):
                return a+b

        [WebMethod]
        def Multiply(a as int, b as int):
                return a*b



&lt;%@WebService Class="MathService" Language="C#" %&gt;
// Math.asmx
public class MathService : Math  // 繼承用 Boo 寫的 Math 類別
{
}


		]]>
	</description>
	<content:encoded><![CDATA[
			必須先將以 Boo 寫的 Web Service 編譯為 Assembly，然後再製作一個以 c# 或 vb.net 寫的 asmx 繼承該 Web Service 類別才行。
否則會遇到 "The invoked member is not supported in a dynamic module." 的錯誤。

我是在遇到錯誤的時候，去參考 boo 源碼 examples/asp.net 下的 Math.asmx 與 Math.asmx.boo 才知道這件事情的。
本來我還在納悶，為甚麼 examples/asp.net 下會有一個用 c# 寫的 asmx，還以為是搞錯了呢～

<pre name="code" class="python">
// Math.asmx.boo
// 要先編譯好，放在 bin 目錄下：booc -t:library -out:bin/Math.dll Math.asmx.boo
import System.Web.Services

[WebService]
class Math:
        [WebMethod]
        def Add(a as int, b as int):
                return a+b

        [WebMethod]
        def Multiply(a as int, b as int):
                return a*b
</pre>

<pre name="code" class="c#">
&lt;%@WebService Class="MathService" Language="C#" %&gt;
// Math.asmx
public class MathService : Math  // 繼承用 Boo 寫的 Math 類別
{
}
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6506341.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6506341.html</guid>
	<category>Boo</category>
	<pubDate>Tue, 15 Jul 2008 14:08:11 +0800</pubDate>
</item>
<item>
	<title>讓 Banshee 啟動時自動播放音樂</title>
	<description><![CDATA[
			主要是利用上一篇介紹的 BooScript Extension，讓 Banshee 能在一開始就播放音樂...
BooScript Extension 在載入時，會檢查是否有 script 要執行，有的話，會進行編譯並執行，所以這個時候 Banshee 內部還有許多事情還沒初始完成，所以必須要將 AutoPlay 的動作排程到 Application.ClientStarted 裡，讓 Application 啟動之後去執行 AutoPlay 的動作。


import System
import System.IO
import Banshee.ServiceStack

def OnClientStarted( client as Client ):
	Hyena.Log.Information( "engine is playing now..." )
	ServiceManager.PlayerEngine.Play()

Hyena.Log.Information( "autoplay script is loaded." )

Banshee.ServiceStack.Application.ClientStarted += OnClientStarted


就這麼簡單，下次要加上自動記錄播放與自動播放記錄曲目的功能。

		]]>
	</description>
	<content:encoded><![CDATA[
			主要是利用上一篇介紹的 BooScript Extension，讓 <a href="http://banshee-project.org/">Banshee</a> 能在一開始就播放音樂...<br/>
BooScript Extension 在載入時，會檢查是否有 script 要執行，有的話，會進行編譯並執行，所以這個時候 <a href="http://banshee-project.org/">Banshee</a> 內部還有許多事情還沒初始完成，所以必須要將 AutoPlay 的動作排程到 Application.ClientStarted 裡，讓 Application 啟動之後去執行 AutoPlay 的動作。<br/>

<pre name="code" class="python">
import System
import System.IO
import Banshee.ServiceStack

def OnClientStarted( client as Client ):
	Hyena.Log.Information( "engine is playing now..." )
	ServiceManager.PlayerEngine.Play()

Hyena.Log.Information( "autoplay script is loaded." )

Banshee.ServiceStack.Application.ClientStarted += OnClientStarted
</pre>

就這麼簡單，下次要加上自動記錄播放與自動播放記錄曲目的功能。
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6319131.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6319131.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 04 Jul 2008 10:09:28 +0800</pubDate>
</item>
<item>
	<title>Boo(20)-Generator 函式</title>
	<description><![CDATA[
			Generator 函式其實就跟 C# 的 Iterator 一樣，利用 yield 關鍵字先把值傳回讓呼叫者使用。
使用 Generator/Iterator 最大的好處是可以讓函式只做必要的邏輯，而不需要把一些事情綁在迴圈裡面。
下面就是一個很標準的尋訪目錄樹的範例，尋訪的工作交給 walk，主程式則負責依據傳回的值作處理。


import System
import System.IO

def walk( path as string ):
  di = DirectoryInfo( path )
  for d in di.GetDirectories():
    yield d as FileSystemInfo
  for f in di.GetFiles():
    yield f as FileSystemInfo

for node in walk( "." ):
  if node isa DirectoryInfo:
    print "[${node.Name}]"
  elif node isa FileInfo:
    print node.Name


參考自：Generators

p.s. 這系列文章一定會持續寫到 macro 出現為止。

		]]>
	</description>
	<content:encoded><![CDATA[
			Generator 函式其實就跟 C# 的 Iterator 一樣，利用 yield 關鍵字先把值傳回讓呼叫者使用。
使用 Generator/Iterator 最大的好處是可以讓函式只做必要的邏輯，而不需要把一些事情綁在迴圈裡面。
下面就是一個很標準的尋訪目錄樹的範例，尋訪的工作交給 walk，主程式則負責依據傳回的值作處理。

<pre name="code" class="python">
import System
import System.IO

def walk( path as string ):
  di = DirectoryInfo( path )
  for d in di.GetDirectories():
    yield d as FileSystemInfo
  for f in di.GetFiles():
    yield f as FileSystemInfo

for node in walk( "." ):
  if node isa DirectoryInfo:
    print "[${node.Name}]"
  elif node isa FileInfo:
    print node.Name
</pre>

參考自：<a href="http://zh.wikibooks.org/w/index.php?title=%E7%A8%8B%E5%BA%8F%E8%A8%AD%E8%A8%88:BOO:Generators&amp;variant=zh-tw">Generators</a>

p.s. 這系列文章一定會持續寫到 macro 出現為止。
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6236271.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6236271.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 27 Jun 2008 14:08:30 +0800</pubDate>
</item>
<item>
	<title>Boo 的 currying</title>
	<description><![CDATA[
			拜讀了Jserv大的"以 C 語言實做 Functional Language 的 Currying"與Thinker大的"真 C 語言實做 Functional Language 的 Currying"以後，決定也來挖掘一下 Boo 的 currying 寫法，根據這篇文章：Boo Programming Language Languages Currying Def Return World，程式碼出乎意料的簡單：

//Currying:
plusX = { a as int | return { b as int | return a + b }}

print plusX(3)(4) 

就這樣。老實說，大概懂了，可是又不是很懂，也沒想到用途。

所以，就跟沒懂是一樣的。

		]]>
	</description>
	<content:encoded><![CDATA[
			拜讀了<a href="http://blog.linux.org.tw/~jserv/archives/002029.html">Jserv大的"以 C 語言實做 Functional Language 的 Currying"</a>與<a href="http://heaven.branda.to/~thinker/GinGin_CGI.py/show_id_doc/326">Thinker大的"真 C 語言實做 Functional Language 的 Currying"</a>以後，決定也來挖掘一下 <a href="http://boo.codehaus.org/">Boo</a> 的 currying 寫法，根據這篇文章：<a href="http://www.economicexpert.com/a/Boo:programming:language.htm">Boo Programming Language Languages Currying Def Return World</a>，程式碼出乎意料的簡單：
<pre name="code" class="python">
//Currying:
plusX = { a as int | return { b as int | return a + b }}

print plusX(3)(4) 
</pre>
就這樣。老實說，大概懂了，可是又不是很懂，也沒想到用途。

所以，就跟沒懂是一樣的。
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6206869.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6206869.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 20 Jun 2008 19:20:36 +0800</pubDate>
</item>
<item>
	<title>Boo(19)-例外處理</title>
	<description><![CDATA[
			例外處理的語法與 Python 相近，差別在於 Boo 使用 ensure，而 Python 使用 finally。
除此之外，Boo 統一使用 except 處理各種例外，而 Python 使用 else 處理無法處理的例外型態。


import System

class MyException(Exception):
  _msg as string
  def constructor( s as string ):
    _msg = s
  override def ToString() as string:
    return "MyException::${_msg}"

// 試著調整這兩個變數試試看
isExceptionHappen = false
isMyExceptionHappen = true

try:
  // .. do something ...
  if isExceptionHappen:
    raise Exception("Something wrong.")  // 提出例外情況
  // ...
  if isMyExceptionHappen:
    raise MyException("Hey!!")
except e as MyException:
  print e.ToString()
except e as Exception:
  print e.Message
ensure:
  print "不管有沒有錯誤，這裡都會被執行。"


參考：Boo Primer - 例外、Python tutorial - 8. Errors and Exceptions

		]]>
	</description>
	<content:encoded><![CDATA[
			例外處理的語法與 Python 相近，差別在於 Boo 使用 ensure，而 Python 使用 finally。<br/>
除此之外，Boo 統一使用 except 處理各種例外，而 Python 使用 else 處理無法處理的例外型態。<br/>

<pre name="code" class="python">
import System

class MyException(Exception):
  _msg as string
  def constructor( s as string ):
    _msg = s
  override def ToString() as string:
    return "MyException::${_msg}"

// 試著調整這兩個變數試試看
isExceptionHappen = false
isMyExceptionHappen = true

try:
  // .. do something ...
  if isExceptionHappen:
    raise Exception("Something wrong.")  // 提出例外情況
  // ...
  if isMyExceptionHappen:
    raise MyException("Hey!!")
except e as MyException:
  print e.ToString()
except e as Exception:
  print e.Message
ensure:
  print "不管有沒有錯誤，這裡都會被執行。"
</pre>

參考：<a href="http://zh.wikibooks.org/wiki/%E7%A8%8B%E5%BA%8F%E8%A8%AD%E8%A8%88:BOO:%E4%BE%8B%E5%A4%96">Boo Primer - 例外</a>、<a href="http://docs.python.org/tut/node10.html">Python tutorial - 8. Errors and Exceptions</a>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6183075.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6183075.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 16 Jun 2008 17:29:18 +0800</pubDate>
</item>
<item>
	<title>Boo(18)-命名空間</title>
	<description><![CDATA[
			.NET上的語言幾乎都導入命名空間了，Boo 無法置身事外...

命名的方式，則是在原始檔第一行加上： namespace 命名空間名稱
撇開註解不算，命名空間的宣告，無論如何都要是程式碼的第一行，否則會有錯誤發生。

引用時，則是使用 import 關鍵字，例如：
import System

Console.WriteLine( "Hello world!" )

// 為甚麼要引用命名空間？因為這樣寫很累...
System.Console.WriteLine( "Hello again." )


你也可以指明組件(Assembly)的名稱，所以這幾種寫法也行：
import System.Data from System.Data
import Gtk from "gtk-sharp"


對了，組件不需要特別加上 ".dll"

		]]>
	</description>
	<content:encoded><![CDATA[
			.NET上的語言幾乎都導入命名空間了，Boo 無法置身事外...<br/>
<br/>
命名的方式，則是在原始檔第一行加上： namespace 命名空間名稱<br/>
撇開註解不算，命名空間的宣告，無論如何都要是程式碼的第一行，否則會有錯誤發生。<br/>
<br/>
引用時，則是使用 import 關鍵字，例如：<pre name="code" class="python">
import System

Console.WriteLine( "Hello world!" )

// 為甚麼要引用命名空間？因為這樣寫很累...
System.Console.WriteLine( "Hello again." )
</pre>

你也可以指明組件(Assembly)的名稱，所以這幾種寫法也行：<pre name="code" class="python">
import System.Data from System.Data
import Gtk from "gtk-sharp"
</pre>
<br/>
對了，組件不需要特別加上 ".dll"<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6172525.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6172525.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 13 Jun 2008 16:47:29 +0800</pubDate>
</item>
<item>
	<title>Boo(17)-結構與列舉</title>
	<description><![CDATA[
			結構(struct)跟類別很類似，最明顯的差別在於 class 被換成 struct 了，類別的一些特性也可以在結構上使用。
其他的差別：無法繼承類別、結構，只能實作 Interface﹔結構是值型別，在複製實體時，是整個克隆(Clone)而不是像類別一樣，只做參考。

struct Dog:
  def constructor( name ):
    _name=name
  [property(Name)]
  _name as string
emptydog=Dog()
print "emptydog.Name=${emptydog.Name}"  // 什麼都沒印出
lucky=Dog("Lucky")
print "lucky.Name=${lucky.Name}"  // 印出 Lucky


列舉(enum)，如果你有用過 C/C++/C# 的話，應該不陌生：

// 宣告列舉
enum Day:
    Sunday
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Sunday
// 也可以指定數值
enum Task:
    TODO=100
    FIXME=101
// 列印
print Day.Sunday
// 尋訪列舉型別裡所有元素
for s in Enum.GetNames(Day):
    print s
// 另一種
for n,v in array( zip( Enum.GetNames(Task), Enum.GetValues(Task)) ):
    print "${n}=${v}"


		]]>
	</description>
	<content:encoded><![CDATA[
			結構(struct)跟類別很類似，最明顯的差別在於 class 被換成 struct 了，類別的一些特性也可以在結構上使用。
其他的差別：無法繼承類別、結構，只能實作 Interface﹔結構是值型別，在複製實體時，是整個克隆(Clone)而不是像類別一樣，只做參考。
<pre name="code" class="python">
struct Dog:
  def constructor( name ):
    _name=name
  [property(Name)]
  _name as string
emptydog=Dog()
print "emptydog.Name=${emptydog.Name}"  // 什麼都沒印出
lucky=Dog("Lucky")
print "lucky.Name=${lucky.Name}"  // 印出 Lucky
</pre>

列舉(enum)，如果你有用過 C/C++/C# 的話，應該不陌生：
<pre name="code" class="python">
// 宣告列舉
enum Day:
    Sunday
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Sunday
// 也可以指定數值
enum Task:
    TODO=100
    FIXME=101
// 列印
print Day.Sunday
// 尋訪列舉型別裡所有元素
for s in Enum.GetNames(Day):
    print s
// 另一種
for n,v in array( zip( Enum.GetNames(Task), Enum.GetValues(Task)) ):
    print "${n}=${v}"
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6140389.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6140389.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 06 Jun 2008 14:21:53 +0800</pubDate>
</item>
<item>
	<title>Boo(16)-Class</title>
	<description><![CDATA[
			Boo 的類別(Class)，跟 Python 很像，基本上不複雜。

class Animal:
  pass

class Dog(Animal):
  def constructor():
    pass
  def constructor( name ):
    _name=name
  def destructor():
    pass
  def Bark():
    print "${_name} is barking..."
  [property(Name)]
  _name = "Anonymous"
spot=Dog( "spot" )
whity=Dog( Name:"whity" )
print spot.Name
whity.Bark()


class 跟 C# 一樣，可以加上 public、protected、internal、protected internal、private、abstract、final 等修飾詞，預設是 public。
繼承的話，就是在類別名稱後面加上小括號，並在括號內放置欲繼承的類別。
建構子與解構子分別是 constructor 與 destructor，可寫可不寫。
方法的宣告其實跟前面提到的函數很像，都是使用 def ，def 的前面還可以加上 abstract、static、virtual、override 等修飾詞。
最後是欄位，通常就跟寫運算式一樣，給定一個值就行了，像這樣：_name=""，前面的 [property()] 是 attribute，是一個偷懶的寫法，實際上是 get/set 的組合體：

class Cat(Animal):
  def constructor():
    pass
  def constructor( name ):
    _name=name
  def destructor():
    pass
  def Meow():
    print "${_name} is meowing..."
  Name as string:
    get:
      return _name
    set:
      _name=value
  _name = "Anonymous"


看到這裡，你有發現到這行嗎？whity=Dog( Name:"whity" )。咦，莫非在建構時可以直接指定屬性的值，沒錯，這寫起程式來方便很多啊～

參考資料：Boo Primer - 類別Boo Primer - 方法Boo Primer - 多型與繼承

		]]>
	</description>
	<content:encoded><![CDATA[
			Boo 的類別(Class)，跟 Python 很像，基本上不複雜。
<pre name="code" class="python">
class Animal:
  pass

class Dog(Animal):
  def constructor():
    pass
  def constructor( name ):
    _name=name
  def destructor():
    pass
  def Bark():
    print "${_name} is barking..."
  [property(Name)]
  _name = "Anonymous"
spot=Dog( "spot" )
whity=Dog( Name:"whity" )
print spot.Name
whity.Bark()
</pre>
<br/>
class 跟 C# 一樣，可以加上 public、protected、internal、protected internal、private、abstract、final 等修飾詞，預設是 public。<br/>
繼承的話，就是在類別名稱後面加上小括號，並在括號內放置欲繼承的類別。<br/>
建構子與解構子分別是 constructor 與 destructor，可寫可不寫。<br/>
方法的宣告其實跟前面提到的函數很像，都是使用 def ，def 的前面還可以加上 abstract、static、virtual、override 等修飾詞。<br/>
最後是欄位，通常就跟寫運算式一樣，給定一個值就行了，像這樣：_name=""，前面的 [property()] 是 attribute，是一個偷懶的寫法，實際上是 get/set 的組合體：
<pre name="code" class="python">
class Cat(Animal):
  def constructor():
    pass
  def constructor( name ):
    _name=name
  def destructor():
    pass
  def Meow():
    print "${_name} is meowing..."
  Name as string:
    get:
      return _name
    set:
      _name=value
  _name = "Anonymous"
</pre>
<br/>
看到這裡，你有發現到這行嗎？whity=Dog( Name:"whity" )。咦，莫非在建構時可以直接指定屬性的值，沒錯，這寫起程式來方便很多啊～<br/>
<br/>
參考資料：<ul><li><a href="http://zh.wikibooks.org/wiki/%E7%A8%8B%E5%BA%8F%E8%A8%AD%E8%A8%88:BOO:%E9%A1%9E%E5%88%A5">Boo Primer - 類別</a></li><li><a href="http://zh.wikibooks.org/wiki/%E7%A8%8B%E5%BA%8F%E8%A8%AD%E8%A8%88:BOO:%E6%96%B9%E6%B3%95">Boo Primer - 方法</a></li><li><a href="http://zh.wikibooks.org/wiki/%E7%A8%8B%E5%BA%8F%E8%A8%AD%E8%A8%88:BOO:%E5%A4%9A%E5%9E%8B%E8%88%87%E7%B9%BC%E6%89%BF">Boo Primer - 多型與繼承</a></li></ul>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6122051.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6122051.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 02 Jun 2008 15:34:28 +0800</pubDate>
</item>
<item>
	<title>Boo(15)-內建函數：容器操作</title>
	<description><![CDATA[
			join()、map()、array()、matrix()、iterator()、enumerate()、range()、reversed()、zip()、cat()

這一類的函式還...蠻多的，大多都與 python 相容。

join()，把 Enumerator 裡面每個元素轉成字串，最後串成一個字串傳回。你也可以加上第二個引數，他會自動幫你加上，例如：join( [1,2,3,4,5], ":" ) 會得到 "1:2:3:4:5" 的字串。
map()，對 Enumerator 裡面每個元素施行指定的函式。
array()，傳入一個 Enumerator 回傳一個陣列。
matrix()，建立多維陣列。
iterator()，取得物件的 IEnumerable 介面，如果物件沒有 IEnumerable 介面，但有繼承 TextReader 的話，則改用 TextReaderEnumerator.lines() 取得 IEnumerable。這個函數在內部非常頻繁地被這裡提到的其他函數使用到。
enumerate()，先取得物件的 IEnumerable 介面，然後傳回類似 (index, value ) 的 Enumerator，舉例來說，List( enumerate( [ "a", "b", "c", "d" ] ) ) 的結果會是：[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]。
range() 很容易理解，傳入數值，會回傳有循序數值的 Enumerator，你也可以傳入起始與結束的數值或是傳入起始、結束與遞增數。
reversed()，將 Enumerator 裡面的元素以相反順序擺放，內部是使用 ReversedListEnumerator 類別來完成這件事情。
zip()，傳入多個 Enumerator，它會把每個 Enumerator 的第 0 個元素放到一起、第 1 個元素放到一起...以此類推，最後再傳回一個 Enumerator。這個函數看例子會比較容易了解，array(zip(['a','b','c'],[4,5,6],['aa','bb','cc'])) 的結果會是 (('a', 4, 'aa'), ('b', 5, 'bb'), ('c', 6, 'cc'))。老實說，我還沒想到要怎麼用...
cat()，跟 join 有點像，不過不會傳回字串，而是把傳入的 Enumerator 串接起來成一個 Enumerator 再傳回。

這裡有的函數我沒舉例，要看例子的話，可以參考Boo Primer中文版對內建函數的說明。

		]]>
	</description>
	<content:encoded><![CDATA[
			join()、map()、array()、matrix()、iterator()、enumerate()、range()、reversed()、zip()、cat()<br />
<br />
這一類的函式還...蠻多的，大多都與 python 相容。<br />
<br />
join()，把 Enumerator 裡面每個元素轉成字串，最後串成一個字串傳回。你也可以加上第二個引數，他會自動幫你加上，例如：join( [1,2,3,4,5], ":" ) 會得到 "1:2:3:4:5" 的字串。<br />
map()，對 Enumerator 裡面每個元素施行指定的函式。<br />
array()，傳入一個 Enumerator 回傳一個陣列。<br />
matrix()，建立多維陣列。<br />
iterator()，取得物件的 IEnumerable 介面，如果物件沒有 IEnumerable 介面，但有繼承 TextReader 的話，則改用 TextReaderEnumerator.lines() 取得 IEnumerable。這個函數在內部非常頻繁地被這裡提到的其他函數使用到。<br />
enumerate()，先取得物件的 IEnumerable 介面，然後傳回類似 (index, value ) 的 Enumerator，舉例來說，List( enumerate( [ "a", "b", "c", "d" ] ) ) 的結果會是：[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]。<br />
range() 很容易理解，傳入數值，會回傳有循序數值的 Enumerator，你也可以傳入起始與結束的數值或是傳入起始、結束與遞增數。<br />
reversed()，將 Enumerator 裡面的元素以相反順序擺放，內部是使用 ReversedListEnumerator 類別來完成這件事情。<br />
zip()，傳入多個 Enumerator，它會把每個 Enumerator 的第 0 個元素放到一起、第 1 個元素放到一起...以此類推，最後再傳回一個 Enumerator。這個函數看例子會比較容易了解，array(zip(['a','b','c'],[4,5,6],['aa','bb','cc'])) 的結果會是 (('a', 4, 'aa'), ('b', 5, 'bb'), ('c', 6, 'cc'))。老實說，我還沒想到要怎麼用...<br />
cat()，跟 join 有點像，不過不會傳回字串，而是把傳入的 Enumerator 串接起來成一個 Enumerator 再傳回。<br />
<br />
這裡有的函數我沒舉例，要看例子的話，可以參考<a href="http://zh.wikibooks.org/wiki/%E7%A8%8B%E5%BA%8F%E8%A8%AD%E8%A8%88:BOO:%E5%87%BD%E6%95%B8#.E5.85.A7.E5.BB.BA.E5.87.BD.E6.95.B8">Boo Primer中文版對內建函數的說明</a>。<br />
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6106269.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6106269.html</guid>
	<category>Boo</category>
	<pubDate>Thu, 29 May 2008 13:49:50 +0800</pubDate>
</item>
<item>
	<title>Boo(14)-內建函數：輸入與輸入</title>
	<description><![CDATA[
			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 來處理。

		]]>
	</description>
	<content:encoded><![CDATA[
			print、gets、prompt<br/>
<br/>
print 就是調用 Console.WriteLine() 而已，官方建議使用 print macro，而不要使用這個函數。<br/>
gets 從標準輸入取得一個字串，實際上就是調用 Console.ReadLine()。<br/>
prompt 是 Console.ReadLine() + Console.Write() 的組合技，在印出你給的提示訊息之後，會接著從標準輸入取得字串。<br/>
<br/>
從標準輸入取得字串的意思就是，畫面會停住，等你輸入字元，直到你按下 Enter 之後，才把你輸入的字元放到字串裡傳回。<br/>
<br/>
<pre name="code" class="python">
print("Hello")
s = gets()
print s
s = prompt("Please input something:")
print s
</pre>
<br/>
當然，除了這些函數以外，你還是可以直接使用 .NET Framework 裡的 System.IO 來處理。<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6070927.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6070927.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 23 May 2008 09:48:06 +0800</pubDate>
</item>
<item>
	<title>Boo(13)-內建函數：shell 類</title>
	<description><![CDATA[
			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", "" )


		]]>
	</description>
	<content:encoded><![CDATA[
			shell()、shellp()、shellm() <br/>
顧名思義，就是執行外部的程式。<br/>
<br/>
shell() 會等待外部程式執行完成以後，回傳一個字串，字串裡是執行的結果。<br/>
shellp() 不會等待外部程式執行完成，會直接回傳 Process 物件，事實上，shell() 也呼叫了這個函數，只是 shell() 拿到 Process 物件以後，利用 Process.StandardOutput() 去讀取執行結果，並使用 Process.WaitForExit() 等待程序執行完成。<br/>
shellm() 也是執行外部程式，但這個外部程式必須是 Managed，也就是 .NET 應用程式。老實說，看了 boo 源碼以後，我不是很懂。源碼裡面是建立一個新的 AppDomain，載入指定的程式，然後找到 EntryPoint 並執行。我猜想，這樣的作法主要用來避免再次建立新程序、啟動 CLR，在 CPU、記憶體使用上會比較有效率。如果你的外部程式正好也是 .NET 應用程式的話，就用 shellm()，我想會比較好。<br/>

<pre name="code" class="python">
input = shell( "booc.exe", "" )
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6059285.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6059285.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 21 May 2008 14:31:33 +0800</pubDate>
</item>
<item>
	<title>booc 的 49 道工法</title>
	<description><![CDATA[
			從 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 -&gt; CompileToMemory -&gt; Compile -&gt; ResolveExpressions -&gt; Parse
只應用了繼承的威力...

		]]>
	</description>
	<content:encoded><![CDATA[
			從 Visual Studio debugger 裡面截出來的...想不到編譯需要這麼多步驟...
<pre>
-		_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}
</pre>
<br/>
第 0 步由 Boo.Lang.Compiler.Pipelines.Parse (src\Boo.Lang.Compiler\Pipelines\Parse.cs) 加入。<br/>
第 1～27 步由 Boo.Lang.Compiler.Pipelines.ResolveExpressions (src\Boo.Lang.Compiler\Pipelines\ResolveExpressions.cs) 加入。<br/>
第 28～46 步由 Boo.Lang.Compiler.Pipelines.Compile (src\Boo.Lang.Compiler\Pipelines\Compile.cs)加入。<br/>
第 47 步由 Boo.Lang.Compiler.Pipelines.CompileToMemory (src\Boo.Lang.Compiler\Pipelines\CompileToMemory.cs) 加入。<br/>
第 48 步由 Boo.Lang.Compiler.Pipelines.CompileToFile (src\Boo.Lang.Compiler\Pipelines\CompileToFile.cs)加入。<br/>
<br/>
這些步驟都是利用繼承的關係建立起來的：CompileToFile -&gt; CompileToMemory -&gt; Compile -&gt; ResolveExpressions -&gt; Parse<br/>
只應用了繼承的威力...<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6049291.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6049291.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 19 May 2008 14:30:22 +0800</pubDate>
</item>
<item>
	<title>Boo(12)-函數</title>
	<description><![CDATA[
			函數定義方法很簡單，比較特別的就是不定個數變數。

// 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 來用就行了。

		]]>
	</description>
	<content:encoded><![CDATA[
			函數定義方法很簡單，比較特別的就是不定個數變數。<br/>
<pre name="code" class="python">
// 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)
</pre>
as string、as int...等，其實都可以省略不寫，別忘了 Boo 會自動判定。<br/>
然後有看到 Say() 定義了三次嗎？是的，Boo 支援多載(overloading)。<br/>
不定個數變數，定義的方法比較特別，要加上 *，然後用法就當作是 enumerator 來用就行了。<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6033657.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6033657.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 16 May 2008 16:55:38 +0800</pubDate>
</item>
<item>
	<title>switch-case in boo</title>
	<description><![CDATA[
			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 其實是用不到的。

		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://boo.codehaus.org/">Boo</a>本身並沒有類似 switch-case 語法，但是可以藉著 macro 來做到，<a href="http://code.google.com/p/boo-extensions/">Boo extensions</a>這個專案已經寫好了。<br/>
由於這個專案沒有釋出二進位碼，所以你需要自己 checkout 並編譯。<br/>
<br/>
編譯以後，用法也很簡單，一看就能懂了。
<pre name="code" class="python">
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 )
</pre>

未來 <a href="http://code.google.com/p/boo-extensions/">Boo extensions</a> 會包進 <a href="http://boo.codehaus.org/">Boo</a> 嗎？很難說...<a href="http://code.google.com/p/boo-extensions/">Boo extensions</a> 目前仍然很具實驗性...<br/>
<br/>
P.S. <ul><li>編譯<a href="http://code.google.com/p/boo-extensions/">Boo extensions</a>前，請下載最新的 <a href="http://boo.codehaus.org/">Boo</a>，然後解壓縮以後，放到跟 boo-extensions 同一層。再切換到 boo-extensions/extensions 下執行 <a href="http://nant.sourceforge.net">nant</a> 即可。</li><li>如果 <a href="http://code.google.com/p/boo-extensions/">Boo extensions</a> 無法編譯成功，試著修改 extensions/default.build 將編譯 .Test.dll 的幾個地方註解掉，再次編譯即可。這些 .Test.dll 其實是用不到的。</li></ul>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6023571.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6023571.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 14 May 2008 16:20:17 +0800</pubDate>
</item>
<item>
	<title>Boo(11)-Hash</title>
	<description><![CDATA[
			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 吧～

		]]>
	</description>
	<content:encoded><![CDATA[
			Hash 的用法很簡單，同樣地，跟 array、List 一樣，可以用很簡潔的方式來表示，也就是大括號 { }<br/>
或者，也可以將符合 key、value 格式的有 IEnumerable 介面的變數傳入 Hash() 函數來取得。<br/>
<br/>
<pre name="code" class="python">
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) ] )
</pre>
<br/>
沒有 Generic 版本的 Hash 可以參考 src/boo.lang/Hash.cs，它其實是繼承自 Hashtable﹔有 Generic 版本的，就直接參考 System.Collections.Generic 裡面的 Hash 吧～
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/6014469.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/6014469.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 12 May 2008 16:34:12 +0800</pubDate>
</item>
<item>
	<title>Boo(10)-Array</title>
	<description><![CDATA[
			陣列的定義方法主要有兩種：使用小括號 (,) 來定義。使用函數： array()、matrix() 來取得。
要得到陣列的大小，則可以使用 len (參考原始碼 tests/testcases/integration/primitives/len-1.boo)，直接來看範例吧：

a0 = (,) // 空的陣列
a1 = ( 1, 2, 3, 4, 5 )  // 都是整數的陣列
a2 = array( range(5) )  // 同樣也是得到整數陣列
a3 = matrix( typeof(int), 2, 3 ) // 得到一個 2x3 的陣列，也可以多傳幾個，製造一個瘋狂的多維陣列
a4 = array( typeof(int), 5 )  // 也是得到一個整數陣列
a3[0,0] = 1
a3[1,0] = 2
print "len(a3,0)=" + len(a3,0)  // 得到 a3 第一維的大小
print "len(a3,1)=" + len(a3,1)  // 得到 a3 第二維的大小
for i in a3:
  print i
a4 = ( 1, 'a', 2, 'b' )  // 雖然陣列要求都是相同型別，但是這樣寫也可以，只是得到型別都是 object 的陣列
// 輸出結果
// 1
// 0
// 0
// 2
// 0
// 0
// len(a3,0)=2
// len(a3,1)=3


陣列也可以用 Generic 語法(參考原始碼 tests/testcases/parser/array_list_hash_literals.boo)，只是我覺得並不是像 List 那麼的必要就是了～：

 a5=(of int: 1,2,3)


		]]>
	</description>
	<content:encoded><![CDATA[
			陣列的定義方法主要有兩種：<ul><li>使用小括號 (,) 來定義。</li><li>使用函數： array()、matrix() 來取得。</li></ul>
要得到陣列的大小，則可以使用 len (參考原始碼 tests/testcases/integration/primitives/len-1.boo)，直接來看範例吧：
<pre name="code" class="python">
a0 = (,) // 空的陣列
a1 = ( 1, 2, 3, 4, 5 )  // 都是整數的陣列
a2 = array( range(5) )  // 同樣也是得到整數陣列
a3 = matrix( typeof(int), 2, 3 ) // 得到一個 2x3 的陣列，也可以多傳幾個，製造一個瘋狂的多維陣列
a4 = array( typeof(int), 5 )  // 也是得到一個整數陣列
a3[0,0] = 1
a3[1,0] = 2
print "len(a3,0)=" + len(a3,0)  // 得到 a3 第一維的大小
print "len(a3,1)=" + len(a3,1)  // 得到 a3 第二維的大小
for i in a3:
  print i
a4 = ( 1, 'a', 2, 'b' )  // 雖然陣列要求都是相同型別，但是這樣寫也可以，只是得到型別都是 object 的陣列
// 輸出結果
// 1
// 0
// 0
// 2
// 0
// 0
// len(a3,0)=2
// len(a3,1)=3
</pre>

陣列也可以用 Generic 語法(參考原始碼 tests/testcases/parser/array_list_hash_literals.boo)，只是我覺得並不是像 List 那麼的必要就是了～：
<pre name="code" class="python">
 a5=(of int: 1,2,3)
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5994715.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5994715.html</guid>
	<category>Boo</category>
	<pubDate>Thu, 08 May 2008 15:20:22 +0800</pubDate>
</item>
<item>
	<title>偵測 .Net/Mono 安裝目錄與 CLR 版本</title>
	<description><![CDATA[
			參考自：How to determine the .NET installation directory and CLR version

env=System.Runtime.InteropServices.RuntimeEnvironment()
print env.GetRuntimeDirectory()
print env.GetSystemVersion()
print env.SystemConfigurationFile
// 輸出結果 (Ubuntu 8.04 + Mono 1.2.6)
// /usr/lib/mono/2.0
// v2.0.50727
// /etc/mono/2.0/machine.config


		]]>
	</description>
	<content:encoded><![CDATA[
			參考自：<a href="http://blogs.msdn.com/kirillosenkov/archive/2008/05/07/how-to-determine-the-net-installation-directory-and-clr-version.aspx">How to determine the .NET installation directory and CLR version</a>
<pre name="code" class="python">
env=System.Runtime.InteropServices.RuntimeEnvironment()
print env.GetRuntimeDirectory()
print env.GetSystemVersion()
print env.SystemConfigurationFile
// 輸出結果 (Ubuntu 8.04 + Mono 1.2.6)
// /usr/lib/mono/2.0
// v2.0.50727
// /etc/mono/2.0/machine.config
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5994219.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5994219.html</guid>
	<category>Boo</category>
	<pubDate>Thu, 08 May 2008 13:21:31 +0800</pubDate>
</item>
<item>
	<title>Boo(9)-List</title>
	<description><![CDATA[
			Boo的 List 並不是使用 .Net/Mono 的 List，而是自己實作。
使用的方法很簡單，用中括號或是使用List函數。

l1=[ 1, 2, 3, 4, "a", "b", "c" ]
l2=List( range(10) )
l1.Add( "d" )
l2.Add( "d" )
print l1
print l2
l1.Remove( "d" )
// 輸出結果
// [1, 2, 3, 4, "a", "b", "c", "d"]
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "d"]
// [1, 2, 3, 4, "a", "b", "c"]


除了正常 List 的操作 Add()、Remove() 以外，還提供了 Push()、Pop()，這意味著可以把 List 當 Stack 來使用。

如果你想知道更多 List 的操作，可以在 booish 裡面使用 dir()，來查看。

&gt;&gt;&gt;l=[]
&gt;&gt;&gt;dir(l)


由於 dir() 會傳回一個 IEnumerator，所以你也可以用下面的程式把每個項目輸出。

l=[]
for m in dir(l):
	print m


或者，直接參考 Boo 的原始碼 src/boo.lang/list.cs 。

隨著 .Net framework 2.0 推出，Boo 也支援了 Generic 語法，語法可以參考這篇的說明：Boo Generic Syntax

import System.Collections.Generic

l = List[of int]()
l.Add( 10 )
l.Add( 20 )
for i in l:
  print i
l.Add( "hello" )  // 這行將會發生錯誤，告訴你不可以加入字串型別


首要的一件事，就是先 import System.Collections.Generic，表明要使用 Generic，否則之後的程式會無法執行。接著使用 [of Type] 的語法，表示 List 要使用指定 Type 的泛型。

使用泛型最明顯的好處是省去轉型的麻煩，因為 List 裡面預設都是使用 object 型別，改用 Generic 以後，可以預先指定好 List 裡面的元素要使用什麼型別。

		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://boo.codehaus.org/">Boo</a>的 List 並不是使用 .Net/Mono 的 List，而是自己實作。<br/>
使用的方法很簡單，用中括號或是使用List函數。<br/>
<pre name="code" class="python">
l1=[ 1, 2, 3, 4, "a", "b", "c" ]
l2=List( range(10) )
l1.Add( "d" )
l2.Add( "d" )
print l1
print l2
l1.Remove( "d" )
// 輸出結果
// [1, 2, 3, 4, "a", "b", "c", "d"]
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "d"]
// [1, 2, 3, 4, "a", "b", "c"]
</pre>

除了正常 List 的操作 Add()、Remove() 以外，還提供了 Push()、Pop()，這意味著可以把 List 當 Stack 來使用。<br/>
<br/>
如果你想知道更多 List 的操作，可以在 booish 裡面使用 dir()，來查看。
<pre>
&gt;&gt;&gt;l=[]
&gt;&gt;&gt;dir(l)
</pre>
<br/>
由於 dir() 會傳回一個 IEnumerator，所以你也可以用下面的程式把每個項目輸出。
<pre name="code" class="python">
l=[]
for m in dir(l):
	print m
</pre>
<br/>
或者，直接參考 <a href="http://boo.codehaus.org/">Boo</a> 的原始碼 src/boo.lang/list.cs 。<br/>
<br/>
隨著 .Net framework 2.0 推出，Boo 也支援了 Generic 語法，語法可以參考這篇的說明：<a href="http://blogs.chayachronicles.com/sonofnun/archive/2007/06/25/250.aspx">Boo Generic Syntax</a>
<pre name="code" class="python">
import System.Collections.Generic

l = List[of int]()
l.Add( 10 )
l.Add( 20 )
for i in l:
  print i
l.Add( "hello" )  // 這行將會發生錯誤，告訴你不可以加入字串型別
</pre>
<br/>
首要的一件事，就是先 import System.Collections.Generic，表明要使用 Generic，否則之後的程式會無法執行。接著使用 [of Type] 的語法，表示 List 要使用指定 Type 的泛型。<br/>
<br/>
使用泛型最明顯的好處是省去轉型的麻煩，因為 List 裡面預設都是使用 object 型別，改用 Generic 以後，可以預先指定好 List 裡面的元素要使用什麼型別。<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5983853.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5983853.html</guid>
	<category>Boo</category>
	<pubDate>Tue, 06 May 2008 16:51:50 +0800</pubDate>
</item>
<item>
	<title>求1到50之間所有偶數的平方值總和</title>
	<description><![CDATA[
			剛好看到：求1到50之間所有偶數的平方值總和，於是順手寫一寫：

//
// Sum all even in 1~50
//
import System

sum = 0
for i in range(1,51):
 if i%2==0:
  sum+=i*i
print sum

		]]>
	</description>
	<content:encoded><![CDATA[
			剛好看到：<a href="http://blog.roodo.com/justinlove/archives/5937583.html">求1到50之間所有偶數的平方值總和</a>，於是順手寫一寫：
<pre name="code" class="python">
//
// Sum all even in 1~50
//
import System

sum = 0
for i in range(1,51):
 if i%2==0:
  sum+=i*i
print sum
</pre>				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5966103.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5966103.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 02 May 2008 23:07:57 +0800</pubDate>
</item>
<item>
	<title>Boo(8)-迴圈</title>
	<description><![CDATA[
			基本上迴圈有兩種：for 與 while。

for 與一般語言的 for 不太一樣，反而與 foreach 比較類似，為了要能得到一個 Enumerator，通常都搭配 range()：

// 印出 0 到 4
for i in range(5):
  print i


while 也沒什麼特別的：

// 同樣印出 0 到 4
i=0
while i
		]]>
	</description>
	<content:encoded><![CDATA[
			基本上迴圈有兩種：for 與 while。<br/>

for 與一般語言的 for 不太一樣，反而與 foreach 比較類似，為了要能得到一個 Enumerator，通常都搭配 range()：
<pre name="code" class="python">
// 印出 0 到 4
for i in range(5):
  print i
</pre>

while 也沒什麼特別的：
<pre name="code" class="python">
// 同樣印出 0 到 4
i=0
while i<4:
  print i
  i=i+1
</pre>

<a href="http://boo.codehaus.org/Boo+Primer">Boo Primer</a>還有提出所謂的 do-while，但實際上是運用 while + break + unless修飾詞來達成的：
<pre name="code" class="python">
// 也是印出 0 到 4
i=0
while true:
  print i
  i=i+1
  break unless i<4
</pre>

有 break，當然也有 continue：
<pre name="code" class="python">
// 印出 1 3 5 7 9
for i in range(10):
  continue if i%2==0
  print i
</pre>

另外再提一個關鍵字，就是 pass，這用來表示程式區塊內不做事情：
<pre name="code" class="python">
// 不會輸出任何結果，因為被 pass 掉了...
i=2
if i%2==0:
  pass
else:
  print "i!=2"
</pre>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5955257.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5955257.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 30 Apr 2008 16:34:09 +0800</pubDate>
</item>
<item>
	<title>Boo and Split</title>
	<description><![CDATA[
			剛好遇到這種狀況，要依據字串的某字元然後做出陣列。所以很直覺地，就可以寫出這樣的代碼。

    splitter = ( char(','), char('\n') )
    fields = inputText.Split( splitter )


不過這段代碼足以讓人搞半天了，boo 會不讓你執行。
非常感謝Google 網上論壇 的Boo Programming Language群組：Splithow do I use Split?
正好解答了我的問題，原來要這樣寫：

    splitter = ( char(','), char('\n') )
    fields = inputText.Split( *splitter )


這真是太隱晦不明了...

		]]>
	</description>
	<content:encoded><![CDATA[
			剛好遇到這種狀況，要依據字串的某字元然後做出陣列。所以很直覺地，就可以寫出這樣的代碼。
<pre name="code" class="python">
    splitter = ( char(','), char('\n') )
    fields = inputText.Split( splitter )
</pre>

不過這段代碼足以讓人搞半天了，boo 會不讓你執行。<br/>
非常感謝<a href="http://groups.google.com/group/boolang/">Google 網上論壇 的Boo Programming Language群組</a>：<ul><li><a href="http://groups.google.com/group/boolang/browse_thread/thread/24415891ea06f6a0/15770a77108d61c5?lnk=gst&q=Split#15770a77108d61c5">Split</a></li><li><a href="http://groups.google.com/group/boolang/browse_thread/thread/ebcba890cc561297/690381b2859fb7aa?lnk=gst&q=Split#690381b2859fb7aa">how do I use Split?</a></li></ul>
正好解答了我的問題，原來要這樣寫：
<pre name="code" class="python">
    splitter = ( char(','), char('\n') )
    fields = inputText.Split( *splitter )
</pre>
<br/>
這真是太隱晦不明了...
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5952383.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5952383.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 30 Apr 2008 01:13:21 +0800</pubDate>
</item>
<item>
	<title>Boo(7) - if-elif-else、unless</title>
	<description><![CDATA[
			Boo 的 if 述句與 python 相似：

i=5
if i>5:
	print "i大於5"
elif i==5:
	print "i等於5"
else:
	print "i小於5"


很簡單。這邊額外要提到程式區塊的概念，像 C# 是用 { }，Pascal 用 begin end，Python 與 Boo 是用縮排來決定程式區塊，所以縮排使用的字元很重要，千萬不要混雜使用，否則你會錯的莫名其妙，在開發時，最好一開始就決定好要使用 tab 字元或是特定數目的空白字元。

運算式，可以使用 and, or 來作連接，或是使用 not 來表示需要相反的條件式。

i=7
if i>=5 and i
		]]>
	</description>
	<content:encoded><![CDATA[
			Boo 的 if 述句與 python 相似：
<pre name="code" class="python">
i=5
if i>5:
	print "i大於5"
elif i==5:
	print "i等於5"
else:
	print "i小於5"
</pre>
<br/>
很簡單。這邊額外要提到程式區塊的概念，像 C# 是用 { }，Pascal 用 begin end，Python 與 Boo 是用縮排來決定程式區塊，所以縮排使用的字元很重要，千萬不要混雜使用，否則你會錯的莫名其妙，在開發時，最好一開始就決定好要使用 tab 字元或是特定數目的空白字元。<br/>
<br/>
運算式，可以使用 and, or 來作連接，或是使用 not 來表示需要相反的條件式。
<pre name="code" class="python">
i=7
if i>=5 and i<=10:
	print "i 介於 5~10 之間"
else:
	print "超出範圍"
if not i==5:
	print "i不等於5"
</pre>
<br/>
如果你沒接觸過 perl/python/ruby/php 的話，以下的用法應該會讓你感到新奇：
<pre name="code" class="python">
s="sad"
unless s=="sad":
	print "Hello world!"
print "Hello world!" unless s=="sad"
print "I am sad" if s=="sad"
</pre>
<br/>
unless 是反面的 if，把它想成 if not 就對了，所以第三行並不會被執行。<br/>
此外，unless 與 if 也可以用來修飾前面的述句﹔以第四行來說，unless s=="sad"用來修飾前面的 print "Hello world!"﹔以第五行來說，if s=="sad"用來修飾前面的print "I am sad"﹔當條件符合時，才會印出。<br/>
因此第四行的 "Hello world!" 不會被印出，而第五行的 "I am sad" 則會被印出。<br/>
<br/>
這些用法會讓人覺得程式也很口語化～<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5935747.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5935747.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 28 Apr 2008 17:46:12 +0800</pubDate>
</item>
<item>
	<title>Boo(6)-變數</title>
	<description><![CDATA[
			Boo 的變數宣告方法很簡單，就跟大多數的 script 語言一樣，指定即用。
比較特別的地方有三個：在第一次指定以後，該變數型別就確定了，之後若指定其他型別的值給它，會發生錯誤。這邊的行為跟 Python、Ruby、Javascript等 script 語言不同，要特別注意。這也證明了 Boo 具有靜態語言的特性。字串裡可以用 ${var_name} 的方式，會直接把 var_name 的值放到變數裡面去。字串有三種定義方法：雙引號，如"Hello"單引號：跟雙引號的不同處，在於單引號字串不解釋 ${}，所以 print '${var}' 會印出 ${var}，而不是 var 變數的值。三個雙引號，如 """Hello"""，跟前兩者的差別在於可以跨越多行。這跟 python 一樣。

// var.boo
i = 100
s = "Hello world ${i} times!!"
print s

// 如果把 100 指派給 s，就會發生錯誤
// s = 100
// Boo Primer 說可以像下面這樣寫，但經過我試驗，是不行的。
// s as int = 200
// 但這樣寫，卻是可以的
o as object = 300
print o
o = "I am object"
print o

print """Hello
Line1
Line2
Line3"""


Boo 官方建議不要特別花心思去寫 &lt;variable&gt; as &lt;type&gt; = &lt;value&gt; 這樣的語法，盡量使用 &lt;variable&gt; = &lt;value&gt;。
經過編譯(booc -target:exe var.boo)以後，再用 reflector 去反組譯，產出的C#代碼如下：private static void Main(string[] argv)
{
    int num = 100;
    Console.WriteLine(new StringBuilder("Hello world ").Append(num).Append(" times!!").ToString());
    object obj2 = 300;
    Console.WriteLine(obj2);
    obj2 = "I am object";
    Console.WriteLine(obj2);
    Console.WriteLine("Hello\r\nLine1\r\nLine2\r\nLine3");
}


從反組譯出來的結果看來，Boo都幫你自動處理好了，的確是不用特別花心思去寫。

		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://boo.codehaus.org/">Boo</a> 的變數宣告方法很簡單，就跟大多數的 script 語言一樣，指定即用。<br/>
比較特別的地方有三個：<ul><li>在第一次指定以後，該變數型別就確定了，之後若指定其他型別的值給它，會發生錯誤。這邊的行為跟 Python、Ruby、Javascript等 script 語言不同，要特別注意。這也證明了 Boo 具有靜態語言的特性。</li><li>字串裡可以用 ${var_name} 的方式，會直接把 var_name 的值放到變數裡面去。</li><li>字串有三種定義方法：<ol><li>雙引號，如"Hello"</li><li>單引號：跟雙引號的不同處，在於單引號字串不解釋 ${}，所以 print '${var}' 會印出 ${var}，而不是 var 變數的值。</li><li>三個雙引號，如 """Hello"""，跟前兩者的差別在於可以跨越多行。這跟 python 一樣。</ol></li></ul>

<pre name="code" class="python">// var.boo
i = 100
s = "Hello world ${i} times!!"
print s

// 如果把 100 指派給 s，就會發生錯誤
// s = 100
// Boo Primer 說可以像下面這樣寫，但經過我試驗，是不行的。
// s as int = 200
// 但這樣寫，卻是可以的
o as object = 300
print o
o = "I am object"
print o

print """Hello
Line1
Line2
Line3"""
</pre>

<a href="http://boo.codehaus.org/">Boo</a> 官方建議不要特別花心思去寫 &lt;variable&gt; as &lt;type&gt; = &lt;value&gt; 這樣的語法，盡量使用 &lt;variable&gt; = &lt;value&gt;。<br/>
經過編譯(booc -target:exe var.boo)以後，再用 reflector 去反組譯，產出的C#代碼如下：<pre name="code" class="csharp">private static void Main(string[] argv)
{
    int num = 100;
    Console.WriteLine(new StringBuilder("Hello world ").Append(num).Append(" times!!").ToString());
    object obj2 = 300;
    Console.WriteLine(obj2);
    obj2 = "I am object";
    Console.WriteLine(obj2);
    Console.WriteLine("Hello\r\nLine1\r\nLine2\r\nLine3");
}
</pre>
<br/>
從反組譯出來的結果看來，<a href="http://boo.codehaus.org/">Boo</a>都幫你自動處理好了，的確是不用特別花心思去寫。<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5911025.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5911025.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 23 Apr 2008 17:33:10 +0800</pubDate>
</item>
<item>
	<title>Boo(5) - Console.ReadKey()</title>
	<description><![CDATA[
			承接上篇的討論，經過 Hack 之後，發現原因就出在 Console.ReadKey()。

booish 與 IronPython 為了要能達到自己的需求，所以並不使用 Console.ReadLine()，而是使用 Console.ReadKey() 自行處理收到的按鍵並輸出。
為了要知道為甚麼會有問題，我試著寫了一個小程式，想知道相似的方式，是否也會有同樣的問題發生：
// Program: readkey.cs
// How to compile: gmcs /target:exe readkey.cs
using System;
public class Hello {
	public static void Main( string[] args ) {
		Console.TreatControlCAsInput = true;
		ConsoleKeyInfo keyInfo;
		do
		{
			keyInfo = Console.ReadKey( true );
			Console.Write( keyInfo.KeyChar );
		} while( keyInfo.Key!=ConsoleKey.Escape );
	}
}


這個小程式編譯以後，使用 .NET 來執行，一切正常，但使用Mono Windows 版來執行，就硬是會 echo 出兩次。
經過用Reflector比對以後，發現Mono的 Console.ReadKey() 的迴圈條件式有問題。
如果將該條件式修正為：

	// } while( record.EventType != 1 && !record.KeyDown); // original
	} while( !(record.EventType==1 && record.KeyDown ) );

	// 附帶一提，這是 Windows .NET 的版本的變形，多判斷了 Character=='\0' 與 VirtualKeyCode 不是 Ctrl、alt、shift、numlock、caplock、scrolllock 的情況
	//} while( !(record.EventType==1 && record.KeyDown ) || record.Character=='\0' && ( ((record.VirtualKeyCode0x12) && record.VirtualKeyCode!=0x14 && record.VirtualKeyCode!=0x90 ) ? (record.VirtualKeyCode==0x91) : true ) );

就可以解決問題，我想這可能是因為寫作 WindowsConsoleDriver.cs 的人對 ReadConsoleInput() 不夠清楚的緣故，不過其實我也是看了 source code 才知道要這樣去判斷。
總之，一切就此水落石出。

等等，可是為甚麼 Console.ReadLine() 沒有問題呢？嗯嗯，這邊的原因也很簡單，因為不管是 .NET 的 CLR 或是 Mono，都是調用 stdin 進行處理，所以就沒有這樣的問題了。

解決方法，目前並沒有，應急的方法是自行下載原始碼，修正Console.ReadKey()(在class/corlib/System/WindowsConsoleDriver.cs)以後，再編譯。不急的話，是先上Mono Buzilla去找找看是否有人回報過此問題，如果沒有再回報上去。
晚點要去找找看，然後回報上去，希望下個版本能解決。

		]]>
	</description>
	<content:encoded><![CDATA[
			承接上篇的討論，經過 Hack 之後，發現原因就出在 Console.ReadKey()。<br/>
<br/>
booish 與 <a href="http://www.codeplex.com/IronPython">IronPython</a> 為了要能達到自己的需求，所以並不使用 Console.ReadLine()，而是使用 Console.ReadKey() 自行處理收到的按鍵並輸出。<br/>
為了要知道為甚麼會有問題，我試著寫了一個小程式，想知道相似的方式，是否也會有同樣的問題發生：
<pre name="code" class="csharp">// Program: readkey.cs
// How to compile: gmcs /target:exe readkey.cs
using System;
public class Hello {
	public static void Main( string[] args ) {
		Console.TreatControlCAsInput = true;
		ConsoleKeyInfo keyInfo;
		do
		{
			keyInfo = Console.ReadKey( true );
			Console.Write( keyInfo.KeyChar );
		} while( keyInfo.Key!=ConsoleKey.Escape );
	}
}
</pre>

這個小程式編譯以後，使用 .NET 來執行，一切正常，但使用<a href="http://www.mono-project.com">Mono</a> Windows 版來執行，就硬是會 echo 出兩次。<br/>
經過用<a href="http://www.aisto.com/roeder/dotnet/">Reflector</a>比對以後，發現<a href="http://www.mono-project.com">Mono</a>的 Console.ReadKey() 的迴圈條件式有問題。<br/>
如果將該條件式修正為：
<pre name="code" class="csharp">
	// } while( record.EventType != 1 && !record.KeyDown); // original
	} while( !(record.EventType==1 && record.KeyDown ) );

	// 附帶一提，這是 Windows .NET 的版本的變形，多判斷了 Character=='\0' 與 VirtualKeyCode 不是 Ctrl、alt、shift、numlock、caplock、scrolllock 的情況
	//} while( !(record.EventType==1 && record.KeyDown ) || record.Character=='\0' && ( ((record.VirtualKeyCode<0x10 || record.VirtualKeyCode>0x12) && record.VirtualKeyCode!=0x14 && record.VirtualKeyCode!=0x90 ) ? (record.VirtualKeyCode==0x91) : true ) );
</pre>
就可以解決問題，我想這可能是因為寫作 WindowsConsoleDriver.cs 的人對 ReadConsoleInput() 不夠清楚的緣故，不過其實我也是看了 source code 才知道要這樣去判斷。<br/>
總之，一切就此水落石出。<br/>
<br/>
等等，可是為甚麼 Console.ReadLine() 沒有問題呢？嗯嗯，這邊的原因也很簡單，因為不管是 .NET 的 CLR 或是 <a href="http://www.mono-project.com">Mono</a>，都是調用 stdin 進行處理，所以就沒有這樣的問題了。<br/>
<br/>
解決方法，目前並沒有，應急的方法是自行下載原始碼，修正Console.ReadKey()(在class/corlib/System/WindowsConsoleDriver.cs)以後，再編譯。不急的話，是先上<a href="http://www.mono-project.com/Bugzilla">Mono Buzilla</a>去找找看是否有人回報過此問題，如果沒有再回報上去。<br/>
晚點要去找找看，然後回報上去，希望下個版本能解決。<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5895705.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5895705.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 21 Apr 2008 14:34:32 +0800</pubDate>
</item>
<item>
	<title>Boo(4) - booi 與 booish</title>
	<description><![CDATA[
			Boo 有兩個很方便的工具：booi 與 booish

booi 可以用來直接執行你寫好的 script，而不必事先編譯。
而 booish 則可以讓你直接輸入指令，立即就能看到結果。

類比其他語言的話，booi 用法就像是執行 wscript your_script 或是 python your_script：booi your_script。
booish 就像是單獨執行 Python 或 ruby 是一樣的，執行以後，會出現訊息以及提示符號。
booish 的提示符號是 &gt;&gt;&gt; ，與 Python 一樣，使用方法也很類似。

使用 booish 的時候，我發現很詭異的地方，就是使用 Mono 包進來的 booish 與 ipy (IronPython) 時，輸入任何字元，都會自動出現兩次以上...
boo 官方網站所提供的 booish 就沒有這個問題，這讓我很納悶。
有時間來找找這問題發生的原因。

		]]>
	</description>
	<content:encoded><![CDATA[
			Boo 有兩個很方便的工具：booi 與 booish<br />
<br />
booi 可以用來直接執行你寫好的 script，而不必事先編譯。<br />
而 booish 則可以讓你直接輸入指令，立即就能看到結果。<br />
<br />
類比其他語言的話，booi 用法就像是執行 wscript your_script 或是 python your_script：booi your_script。<br />
booish 就像是單獨執行 <a href="http://www.python.org">Python</a> 或 <a href="http://www.ruby-lang.org/">ruby</a> 是一樣的，執行以後，會出現訊息以及提示符號。<br />
booish 的提示符號是 &gt;&gt;&gt; ，與 <a href="http://www.python.org">Python</a> 一樣，使用方法也很類似。<br />
<br />
使用 booish 的時候，我發現很詭異的地方，就是使用 <a href="http://www.mono-project.com">Mono</a> 包進來的 booish 與 ipy (IronPython) 時，輸入任何字元，都會自動出現兩次以上...<br />
<a href="http://boo.codehaus.org/">boo 官方網站</a>所提供的 booish 就沒有這個問題，這讓我很納悶。<br />
有時間來找找這問題發生的原因。<br />
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5881295.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5881295.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 18 Apr 2008 17:25:11 +0800</pubDate>
</item>
<item>
	<title>Boo(3) - ildasm</title>
	<description><![CDATA[
			使用 ildasm 有兩個目的：比較print macro 與 print 函數的差別比較 booc 編譯出來的可執行檔與 c# 編譯出來的可執行代碼

print macro 與 print 函數算是差別很大吧。
print 函數會調用 Boo.Lang.Builtins 類別裡的 print 函數，雖然實際上此函數的內容也是使用 Console.WriteLine()，但是除了你需要多附上 Boo.Lang.dll 之外，你還需要負擔 CLR 執行時動態把 Boo.Lang.dll 載入的成本。
IL_0005:  call       void [Boo.Lang/*23000001*/]Boo.Lang.Builtins/*01000001*/::print(object) /* 0A000001 */
使用 print macro 的話，就只是把 Console.WriteLine 替換進去，以編譯出來的結果而言，這會比較有效率，但如果作為 script 執行時，我想應該會有些損失。
IL_0005:  call       void [mscorlib/*23000001*/]System.Console/*01000001*/::WriteLine(string) /* 0A000001 */
這就是為甚麼BOO Primer建議使用 print macro 的原因。

booc 編譯出來的結果與使用 gmcs (我使用 Mono 的 c# 2.0 編譯器)編譯出來的結果非常接近，都同樣直接呼叫 System.Console.WriteLine，可以視為一樣。
p.s. 我也看過以 csc 編譯出來的結果了，實際上也非常相近，不過反組譯出來的IL代碼裡面的編排有些許不同。

		]]>
	</description>
	<content:encoded><![CDATA[
			使用 ildasm 有兩個目的：<ol><li>比較print macro 與 print 函數的差別</li><li>比較 booc 編譯出來的可執行檔與 c# 編譯出來的可執行代碼</li></ol><br />
<br />
print macro 與 print 函數算是差別很大吧。<br />
print 函數會調用 Boo.Lang.Builtins 類別裡的 print 函數，雖然實際上此函數的內容也是使用 Console.WriteLine()，但是除了你需要多附上 Boo.Lang.dll 之外，你還需要負擔 CLR 執行時動態把 Boo.Lang.dll 載入的成本。<br />
<blockquote>IL_0005:  call       void [Boo.Lang/*23000001*/]Boo.Lang.Builtins/*01000001*/::print(object) /* 0A000001 */</blockquote><br />
使用 print macro 的話，就只是把 Console.WriteLine 替換進去，以編譯出來的結果而言，這會比較有效率，但如果作為 script 執行時，我想應該會有些損失。<br />
<blockquote>IL_0005:  call       void [mscorlib/*23000001*/]System.Console/*01000001*/::WriteLine(string) /* 0A000001 */</blockquote><br />
這就是為甚麼<a href="http://boo.codehaus.org/Boo+Primer">BOO Primer</a>建議使用 print macro 的原因。<br />
<br />
booc 編譯出來的結果與使用 gmcs (我使用 <a href="http://www.mono-project.com">Mono</a> 的 c# 2.0 編譯器)編譯出來的結果非常接近，都同樣直接呼叫 System.Console.WriteLine，可以視為一樣。<br />
p.s. 我也看過以 csc 編譯出來的結果了，實際上也非常相近，不過反組譯出來的IL代碼裡面的編排有些許不同。<br />
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5869723.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5869723.html</guid>
	<category>Boo</category>
	<pubDate>Wed, 16 Apr 2008 14:40:54 +0800</pubDate>
</item>
<item>
	<title>BOO(2) - Hello world!</title>
	<description><![CDATA[
			接下來的系列文章，大致會照著BOO Primer的章節來作介紹。

是的，永遠的 Hello world!

BOO 的 Hello world! 非常簡單：// 把 print 當 macro 使用，什麼是 macro ??日後再說明
print "Hello world!"
// 或者是拿 print 當函數使用
print("Hello world!")


官方建議使用 print macro 的版本，我想是效率上的考量，macro 在執行時會展開為真正的代碼，而不是以函數呼叫的方式來處理。不過我覺得這見仁見智，差別不是很大。另一個好處應該是很像 Python 吧～

		]]>
	</description>
	<content:encoded><![CDATA[
			接下來的系列文章，大致會照著<a href="http://boo.codehaus.org/Boo+Primer">BOO Primer</a>的章節來作介紹。<br/>
<br/>
是的，永遠的 Hello world!<br/>
<br/>
BOO 的 Hello world! 非常簡單：<pre name="code" class="python">// 把 print 當 macro 使用，什麼是 macro ??日後再說明
print "Hello world!"
// 或者是拿 print 當函數使用
print("Hello world!")
</pre>
<br/>
官方建議使用 print macro 的版本，我想是效率上的考量，macro 在執行時會展開為真正的代碼，而不是以函數呼叫的方式來處理。不過我覺得這見仁見智，差別不是很大。另一個好處應該是很像 <a href="http://www.python.org">Python</a> 吧～<br/>
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5859319.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5859319.html</guid>
	<category>Boo</category>
	<pubDate>Mon, 14 Apr 2008 15:16:49 +0800</pubDate>
</item>
<item>
	<title>BOO (1)</title>
	<description><![CDATA[
			BOO是一個兼具動態語言特性與靜態語言特性的語言，比IronPython、IronRuby還要早誕生，但是使用的人卻不多，我對他會有興趣的原因是因為他很接近 Python，而且可以編譯為 exe/dll、定義出屬於自己的 Domain-specific language(使用 macro)。

Q:哪裡可以取得？
A:你可以到 BOO 官方下載網頁 下載。

Q:如何安裝？
A:解開下載來的壓縮檔即可，除此之外，你還需要安裝 .Net framework 2，這可以用 Windows Update 裝起來。此外，你也可以透過安裝Mono或是SharpDevelop 2.x的方式來取得。

Q:跟其他 .Net 語言，如 c#, vb.net 等，有什麼不一樣？
A:最大的不同點在於BOO可以當作 script 來使用，你可以使用 booi 直接執行程式，或是像Python一樣，當作 SHELL 來使用 (booish)。

Q:如何使用？
A:當作 shell 來使用：解開之後，你可以在 bin 目錄下找到 booish.exe，點選以後執行。執行 script：在命令提示字元下切換目錄到 boo_path/bin 以後，輸入 booi your_script.boo編譯為 dll/exe：在命令提示字元下切換目錄到 boo_path/bin 以後，輸入 booc -target:[exe|library|winexe] -o:輸入檔名 your_script.boo

Q:有哪些文件可以參考？
A:官方網站的 Tutorials 列出了相當多的文件，我自己主要是參考Boo Primer。

		]]>
	</description>
	<content:encoded><![CDATA[
			<a href="http://boo.codehaus.org/">BOO</a>是一個兼具動態語言特性與靜態語言特性的語言，比<a href="http://www.codeplex.com/IronPython">IronPython</a>、<a href="http://www.ironruby.net/">IronRuby</a>還要早誕生，但是使用的人卻不多，我對他會有興趣的原因是因為他很接近 Python，而且可以編譯為 exe/dll、定義出屬於自己的 <a href="http://en.wikipedia.org/wiki/Domain-specific_programming_language" title="Domain-specific programming language - Wikipedia, the free encyclopedia">Domain-specific language</a>(使用 macro)。<br />
<br />
Q:哪裡可以取得？<br />
A:你可以到 <a href="http://boo.codehaus.org/Download">BOO 官方下載網頁</a> 下載。<br />
<br />
Q:如何安裝？<br />
A:解開下載來的壓縮檔即可，除此之外，你還需要安裝 <a href="http://www.microsoft.com/netframework/">.Net framework 2</a>，這可以用 Windows Update 裝起來。此外，你也可以透過安裝<a href="http://www.mono-project.com">Mono</a>或是<a href="http://www.icsharpcode.com/OpenSource/SD/">SharpDevelop 2.x</a>的方式來取得。<br />
<br />
Q:跟其他 .Net 語言，如 c#, vb.net 等，有什麼不一樣？<br />
A:最大的不同點在於<a href="http://boo.codehaus.org/">BOO</a>可以當作 script 來使用，你可以使用 booi 直接執行程式，或是像<a href="http://python.org">Python</a>一樣，當作 SHELL 來使用 (booish)。<br />
<br />
Q:如何使用？<br />
A:<ul><li>當作 shell 來使用：解開之後，你可以在 bin 目錄下找到 booish.exe，點選以後執行。</li><li>執行 script：在命令提示字元下切換目錄到 boo_path/bin 以後，輸入 booi your_script.boo</li><li>編譯為 dll/exe：在命令提示字元下切換目錄到 boo_path/bin 以後，輸入 booc -target:[exe|library|winexe] -o:輸入檔名 your_script.boo</li></ul><br />
<br />
Q:有哪些文件可以參考？<br />
A:官方網站的 <a href="http://boo.codehaus.org/Tutorials">Tutorials</a> 列出了相當多的文件，我自己主要是參考<a href="http://boo.codehaus.org/Boo+Primer">Boo Primer</a>。<br />
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/5843991.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/5843991.html</guid>
	<category>Boo</category>
	<pubDate>Fri, 11 Apr 2008 13:18:42 +0800</pubDate>
</item>
<item>
	<title>Boo hack(2)</title>
	<description><![CDATA[
			回頭看 Boo.Lang.Compiler.CompilerParameters (就是前面提到的 _parser.Parameters)，發現裡面做的事情並不是放參數那麼簡單。
除了 Input 之外，他還負責初始化必要的東西，例如載入預設的 Assembly：mscorlib、System、Boo.Lang.Builtins、Boo.Lang.Compiler～

回到正題，BooCompiler.Run() (前面提到的_parser) 起始 CompilerContext之後，再把 context 傳給 CompilerParameters.Pipeline.Run() 去執行。
_parser.Parameters.Pipeline 早在 AbstractInterpreter 時，就已經初始：Pipelines.Parse.NewParserStep()。

p.s.可以學學素心如何天上月 (Yong Sun's Blog)剖析SunPinyin的系列文章，這樣 trace 起來會比較清楚。加上適當 UML Diagram 也是好主意，不過傳圖有點麻煩。

		]]>
	</description>
	<content:encoded><![CDATA[
			回頭看 Boo.Lang.Compiler.CompilerParameters (就是前面提到的 _parser.Parameters)，發現裡面做的事情並不是放參數那麼簡單。<br />
除了 Input 之外，他還負責初始化必要的東西，例如載入預設的 Assembly：mscorlib、System、Boo.Lang.Builtins、Boo.Lang.Compiler～<br />
<br />
回到正題，BooCompiler.Run() (前面提到的_parser) 起始 CompilerContext之後，再把 context 傳給 CompilerParameters.Pipeline.Run() 去執行。<br />
_parser.Parameters.Pipeline 早在 AbstractInterpreter 時，就已經初始：Pipelines.Parse.NewParserStep()。<br />
<br />
p.s.<ul><li>可以學學<a href="http://blogs.sun.com/yongsun/">素心如何天上月 (Yong Sun's Blog)</a>剖析SunPinyin的系列文章，這樣 trace 起來會比較清楚。</li><li>加上適當 UML Diagram 也是好主意，不過傳圖有點麻煩。</li></ul><br />
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4314259.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4314259.html</guid>
	<category>Boo</category>
	<pubDate>Tue, 16 Oct 2007 17:10:10 +0800</pubDate>
</item>
<item>
	<title>Boo hack(1)</title>
	<description><![CDATA[
			從 booish 開始，我想會比較快吧～
這個互動的 shell，你可以像 BASIC 一樣，打指令以後，立刻就可以看到結果。

booish 本身是一個很簡單的小程式，產生 InteractiveInterpreter2(在Boo.Lang.Interpreter下) 的 Instance 以後，調用 ConsoleLoopEval() 來等待使用者輸入程式並執行。
等使用者按下 enter 的時候，就試著呼叫 TryRunCommand() 看是不是內建的指令。
不是的話，就調用 InternalLoopEval()，而 InternalLoopEval() 則是呼叫父類別:AbstractInterpreter.Eval()。

AbstractInterpreter.Eval() 簡單的把字串參數轉換為 StringInput (繼承 ReaderInput，ReaderInput再繼承 ICompilerUnit)，再讓 EvalCompilerInput() 去呼叫 Parse()。 (註1)
Parse() 則是先把 _parser 的輸入參數清空，把 ICompilerUnit 參數放到 _parser 的輸入參數(Parameters.Input)裡面，執行 _parser.Run()。

_parser 的型別是 BooCompiler，至此，要開始看 Boo.Lang.Compiler.BooCompiler 了。
所以，看起來 Boo.Lang.Interpreter 是用 Boo.Lang.Compiler 命名空間裡的類別在做事。

註：想不到可以這樣用：return EvalCompilerInput(StringInput("input${++_inputId}", code))，Boo 可以讓變數直接帶入字串，如： "${_inputId}"，但我不知道裡面還可以作運算，如："${++_inputId}"

		]]>
	</description>
	<content:encoded><![CDATA[
			從 booish 開始，我想會比較快吧～<br />
這個互動的 shell，你可以像 BASIC 一樣，打指令以後，立刻就可以看到結果。<br />
<br />
booish 本身是一個很簡單的小程式，產生 InteractiveInterpreter2(在Boo.Lang.Interpreter下) 的 Instance 以後，調用 ConsoleLoopEval() 來等待使用者輸入程式並執行。<br />
等使用者按下 enter 的時候，就試著呼叫 TryRunCommand() 看是不是內建的指令。<br />
不是的話，就調用 InternalLoopEval()，而 InternalLoopEval() 則是呼叫父類別:AbstractInterpreter.Eval()。<br />
<br />
AbstractInterpreter.Eval() 簡單的把字串參數轉換為 StringInput (繼承 ReaderInput，ReaderInput再繼承 ICompilerUnit)，再讓 EvalCompilerInput() 去呼叫 Parse()。 (註1)<br />
Parse() 則是先把 _parser 的輸入參數清空，把 ICompilerUnit 參數放到 _parser 的輸入參數(Parameters.Input)裡面，執行 _parser.Run()。<br />
<br />
_parser 的型別是 BooCompiler，至此，要開始看 Boo.Lang.Compiler.BooCompiler 了。<br />
所以，看起來 Boo.Lang.Interpreter 是用 Boo.Lang.Compiler 命名空間裡的類別在做事。<br />
<br />
註：<ol><li>想不到可以這樣用：<blockquote>return EvalCompilerInput(StringInput("input${++_inputId}", code))</blockquote>，Boo 可以讓變數直接帶入字串，如： "${_inputId}"，但我不知道裡面還可以作運算，如："${++_inputId}"</li></ol><br />
				]]>
	</content:encoded>
	<link>http://blog.roodo.com/thinkingmore/archives/4120541.html</link>
	<guid>http://blog.roodo.com/thinkingmore/archives/4120541.html</guid>
	<category>Boo</category>
	<pubDate>Tue, 11 Sep 2007 12:21:05 +0800</pubDate>
</item>
</channel>
</rss>