System.Text.UTF8Encoding

在用 SmartIRC4Net 寫 irc 程式的時候發現,如果把 encoding 設成 System.Text.Encoding.UTF8 會導致無法連上 irc server。

很好奇的看了 SmartIRC4Net 的 code 結果沒什麼收穫,用的是一般的 StreamWriter 的初始化方法;如果改用 System.Text.UTF8Encoding 就可以正確連上了,而且這是 StreamWriter 預設的 encoding。

到底 Encoding.UTF8 和 UTF8Encoding 兩個有什麼不一樣呢?看了一下 mono 的實做方法,使用上這兩個都是 用 UTF8Encoding 的 instance,只是 Encoding.UTF8 是有 BOM 的,UTF8Encoding 則預設沒有。

就是因為那個多出來的 BOM 導致 irc server 無法認出正確的指令(因為不是 vaild ascii code),在一般使用上也要注意這兩者的差別。

Nemerle – Redefining symbols

在 nemerle 裡面,可以用

def a = 123;

這樣的格式來定義一個 immutable 的變數

然而,這樣的寫法也是 vaild 的

def a = 123;
def a = "123";

雖然看起來像是給 immutable 的 a assign 了兩次不同的值,實際上兩者有完全不同的意義,所以

def (x, y) = (1, 3);
def (x, y) = (y, x);

也都是被接受的語法。

詳細:Side note: redefining symbols

.NET – Program Glue

C 的 stdio.h 有 popen/pclose 可以用,python 有 popen/popen2… ,perl 可以把程式當作檔案代號直接開啟執行,這些都可以做到程式間黏合、互動,那 .NET 要怎麼作呢?

可以用 System.Diagnostics.Process 來做到一樣的功能:

using System;
using System.Diagnostics;

public module T {
    public Main (args: array[string]) : void
    {
        def proc = Process ();
        def proc_info = ProcessStartInfo (args[0]);

        proc_info.CreateNoWindow = true;
        proc_info.UseShellExecute = false;
        proc_info.RedirectStandardInput = true;
        proc_info.RedirectStandardOutput = true;
        proc_info.RedirectStandardError = true;
        proc.StartInfo = proc_info;

        proc.Start ();
        while (true) {
            proc.StandardInput.WriteLine (Console.ReadLine ());
            Console.WriteLine (proc.StandardOutput.ReadLine ());
        }
    }
}

.NET – Load Plugins

寫 c/c++ 的時候,可以用 dlopen 來讀入 .so/.dll 檔當作 plugin 用,寫 perl 的時候用 require 就可以把另一個 perl module 讀到記憶體,elisp 也有類似的用法,.NET 則提供了 System.Reflection.Assembly 類別來處理這樣的事。

首先為了統一 Plugin 的介面,我們可以定義幾個 Plugin 專用的 interface:

// PluginInterfaces.dll
namespace Plugin.Interfaces
    public interface IPlugin
        Calculate (input: int) : int

然後 Plugin 的實做寫在另一個 Assembly:

// Plugins.dll
using Plugin.Interfaces
namespace Plugin.Test
    public class Test1 : IPlugin
        public Calculate (input: int) : int
            input * 2
    public class Test2 : IPlugin
        public Calculate (input: int) : int
            input + 3

然後主程式就可以把這些 plugins 動態的讀近來:

// Run.exe
using System
using System.Reflection
using Plugin.Interfaces
public module R
    public Main (args: array[string]) : void
        def p = Assembly.LoadFile (args[0]).CreateInstance (args[1]) :> IPlugin
        Console.WriteLine (p)
        Console.WriteLine (p.Calculate (100))

實際執行的結果:

$ ncc PluginInterfaces.n -out:PluginInterfaces.dll -target:library
$ ncc Plugins.n -ref:PluginInterfaces.dll -out:Plugins.dll -target:library
$ ncc Run.n -ref:PluginInterfaces.dll -out:Run.exe
$ ./Run.exe Plugins.dll Plugin.Test.Test1
Plugin.Test.Test1
200
$ ./Run.exe Plugins.dll Plugin.Test.Test2
Plugin.Test.Test2
103

嗯,大概就是這樣 😉

TODO

最近什麼事都沒做,還要講什麼什麼的,真是很不好意思 :-/

有一些事情希望能在寒假做完…

  • 把 OV-Win32 的建構方法弄完整一點
  • 看能不能吸收一些 ChewingIME 的功力
  • 微調微調…

說來說去,就是要繼續改 OV 啦 😉

阿,不過應該要開始忙專題的事了。

書太多

明明已經克制不要買書了,可是課本加上一些暑假買的書(err…),還有從圖書館借了不少… 已經沒有地方可以放了 XD

改天要去採購書櫃才行,不然堆的地板上,書桌上到處都是,這樣很難引起要閱讀的慾望阿 <囧>

迷之聲:還有某目錄裡的「書」….

用 meld 來做 merge

今天在把 libchewing 的 utf8 branch merge 到 trunk 去,發現 meld 用起來真的很方便。

首先因為我是用 svk 來管理的,所以先 export SVKMERGE=meld,這樣 svk 在需要 merge 的時候就會自動呼叫 meld。

然後 svk smerge //mirror/chewing/libchewing/branches/utf8 就會開始自動 merge,碰到 orig 跟 trunk 還有 branch 都不一樣的時候就會呼叫 meld 出來做 3 way merge,我只需要用滑鼠點選要使用哪一個 branch 的更動就可以了,不用辛苦的比對。

受傷了

昨天去打壘球中資盃,真是累死了。我想大家都一樣吧,回家倒頭就睡,現在才醒起來 blog 紀錄一下。第二場比賽,我才上場守備(投手)投沒幾球,就被對手第四棒的強勁滾地球命中右腳脛骨處… 那球速度飛快,我根本來不及反應就命中了,雖然馬上使用冷凍劑還是腫起來了。緊急調換學弟上場,沒想到第一次投大比賽的學弟很快就穩下來,投出幾球精彩的三振。比賽結束後到台中醫院掛急診,醫生說這一兩天都要冰敷,還要多喝水幫助排毒,另外開了消炎藥給我。看來要辛苦一陣子了。