2013年1月10日 星期四

C++ enum member function

之前重構公司的程式碼,發現一個需求:希望 enum 能有 member function

現有的程式碼:

class PrimitiveKind {
    enum kind {
        VOID,
        BOOL,
        INT8, INT16, INT32, INT64,
        FLOAT32, FLOAT64,
        FUNCTION, OBJECT, ...
        ...
    };

    static bool isBool();
    static bool isInterger();
    static bool isFloat();
};

整理了一下使用到的情況,大概可以分成三種:

1. 判斷 isBool, isInterger, isFloat...

void f(PrimitiveKind::kind v) {
    if(PrimitiveKind::isBool(v)) {
        ...
    } else if (PrimitiveKind::isInteger(v)) {
        ...
    }
    ...
}

2. enum 的值互相比較

PrimitiveKind::kind promote(PrimitiveKind::kind a, PrimitiveKind::kind b) {
    if (a <= FLOAT64 && b <= FLOAT64) {
    if( a > b ) return a;
    else return b;
    } else {
        ...
    }
}

3. switch case

void g(PrimitiveKind::kind v) {
    switch(v) {
    case PrimitiveKind::VOID: ...
    case PrimitiveKind::INT8: ...
    case PrimitiveKind::INT16: ...
    }
}

這個 class PrimitiveKind 其實沒有任何 data member,她的角色比較像是 namespace。只是把跟 PrimitiveKind 有關的宣告集合起來。

我希望能避開 PrimitiveKind::isBool(v) 這種呼叫 static member function 的寫法,直接寫 v.isBool()。

第一個想法,很直覺想到可以讓 PrimitiveKind 變成一個 wrapper class,持有一個 PrimitiveKind::kind,並且把 static member function isBool() 改成 non-static member function isBool()。這樣我就可以滿足第一個狀況,可以直接呼叫 isBool(), isInteger(), isFloat()。但是卻沒辦法滿足後兩種狀況。因為 wrapper class 沒有 <, >, =, != 等等的 operator,也無法放進 switch。

第二個想法,我幫 PrimitiveKind 加上 operator overloading,讓他支援一整組的 relational operator,就可以也滿足第二個情況。

但這個時候我想了想,我應該先列出所有我需要滿足的需求,再來回顧我的設計。整理了一下,我希望我的 wrapper class 滿足以下條件:

1. 有 non-static member function 可以使用
2. wrapper 之間可以互相 assign,也可以被 raw enum value 直接 assign
3. wrapper 之間可以互相比較,也可以和 raw enum value 之間互相比較
4. 可以使用在 switch 裡面

其實最好是可以取代所有需要用到 raw enum 的地方。

其實前三條都很容易滿足(雖然很煩),但最後一條才是關鍵,為了讓他可以被用在 switch 裡面,我想我需要 overload 一個 cast operator(對,C++ 可以自己定義 cast operator,很少用到,但其實有這種功能 http://www.learncpp.com/cpp-tutorial/910-overloading-typecasts/ )

operator PrimitiveKind::kind() const { return kind_; }

讓他可以被 implicit 轉成 PrimitiveKind::kind,後來回頭一想,其實我前面 overoad 的那十幾個 relactional operator 好像都可以省下來,測試了一下,發現確實可以運作。

以下是最後的完成品。

class PrimitiveKind {
    enum kind { VOID, BOOLEAN, ... };

    operator kind() const { return kind_ ; }

    bool isBool();
    bool isInteger();
    bool isFloat();

    kind kind_;
}

使用簡單,用起來就像是 enum,可以放進 switch,可以直接比較,還可以有 member function,也封裝了 INT8 等等的 symbol(在 C++11 可以用 strong typed enum 達成)。

2012年11月9日 星期五

boost, clang, libc++

花了很多時間才把 boost 用 clang 跟 libc++ 編譯起來,作一點筆記,免得以後忘記。

首先,目前的 boost 有幾個 library 跟 clang 有相容性問題,編譯的時候可以先關掉。
  • signals
  • python
  • iostreams
  • mpi
所以使用
sudo ./bootstrap.sh --with-toolset=clang cxxflags="-I/usr/local/include/c++/v1 -stdlib=libc++" linkflags="-stdlib=libc++" --without-libraries=signals,python,iostreams,mpi
來設定。

設定完成以後,使用
sudo ./b2 toolset=clang cxxflags="-I/usr/local/include/c++/v1 -stdlib=libc++" linkflags="-stdlib=libc++" install
進行編譯跟安裝,對了,如果有需要的話,記得要用 debug build。

2012年9月19日 星期三

Software Transactional Memory

Software Transactional Memory

正在 survey STM,看了一下各語言的支援情形:
  • C#
  • 透過外掛修飾 class,讓這個 class 所有的 data member 都是 private,所有的 setter/getter 都是 virtual,看起來是要讓某個 class template 來 mock 那個 class,但是 setter/getter 是 atomic 的。可以作到 C++ 的 一樣的事情,但是沒有 transactional block 的能力。
    stackoverflow 上面有一篇討論,C# 沒有語言層面的支援,可以透過 library 來完成。
  • Java
  • 也是一樣,透過 library 完成。
  • Golang
  • 應該是沒打算提供 transactional memory,根據這篇討論,go 提供 message passing 作為取代。
  • C++
  • 有兩個 compiler 提供了 atomic block 的實作,一個是 Intel C++ compiler(真是太強了),另外一個是 g++(嘖嘖),大概最後還是選擇以類似 C++ 的形式為目標。

找到 gcc 的 transactional memory 的 spec,正在讀,作一點筆記。

__transaction_relaxed and __transaction_atomic

有兩個關鍵字:
  1. __transaction_relaxed
  2. 用來表示........ 其實我沒看懂。好,看到後面,懂了。這種 transaction 比較 weak,他只保證 transaction 「看起來」沒有跟別的 transaction 有交錯執行,但是,他還是可能跟別 thread 有交錯。舉例來說的話:
    Thread AThread B
    __transaction_relaxed {
        a = 1;
        b = a;
    }
    
    a = 3;
    
    這樣 Thread A 的 b 有可能會是 4。因為被另外一個 Thread B 的 a = 3; 亂入了。但是呢,如果寫:
    Thread AThread B
    __transaction_relaxed {
        a = 1;
        b = a;
    }
    
    __transaction_relaxed {
        a = 3;
    }
    
    那 b 就保證會是 1 了。因為 relaxed transaction 有保證這個 transaction 看起來不會跟別的 transaction 交錯執行。
    這邊一直強調「看起來」是很重要的,因為實際上,根據實作的細節(且為了效率的考量),執行的過程本身可能還是交錯並行的,只是透演算法的控制,讓執行的結果跟沒有交錯一樣,所以程式設計師就可以很直覺的認定這段程式碼的形為就如同一般 single thread 一樣。
    特性:
    • 其他的 transaction 無法觀察到 __transaction_relaxed 的 partial result
    • 其他的 thread 有可能觀察到 __transaction_relaxed 的 partial result
    • __transaction_relaxed 有可能觀察到其他 thread 的 partial result,有的時候你會想要等待某一個 std::atomic 變數變化來作事情,所以 relaxed transaction 有其必要性
    • 沒有限制 operation 的種類,什麼都可以放進去(如果我沒誤解的話,第 8 頁 45 行)
    • 無法 cancel,因為(見規格書第 9 頁第 16 行)容許有 side effect 的動作(比方說IO)而這些動作無法撤銷
    • Relaxed transaction 可以 nested 含有 relaxed transaction

  3. __transaction_atomic
  4. 用來表示(跟 __transaction_relaxed 比起來)更嚴格的的 transaction。這大概是我們要做的,但不確定前一種要不要作 :P
    這邊現在我也看懂了,也就是說,在 atomic transaction 之下,即使只寫
    Thread AThread B
    __transaction_relaxed {
        a = 1;
        b = a;
    }
    
    a = 3;
    
    我們也可以保證 b 百分之一是對的,會是 1。哇勒~!這種東西要怎麼作阿!!!
    特性:
    • 只有 "safe" code 可以放在裡面(等一下在 4.2 節說明)
    • 可以被 cancel
    • 不能有 side effect(比方說 IO)

transaction_safe

為了確保 transaction 是「可能」的,atomic block 裡面能寫的程式碼必須要加上一些限制,也就是 atomic block 裡面只能有 "safe" statements 。safe satements 所呼叫的 function 裡面,也只能含有 safe statements(這感覺很像 pure function ,一個 pure function 裡面只能呼叫 pure function)。
為了表明一個 function 是 safe function,需要在函數前面加上 attribute transaction_safe 修飾這個 function(safe 屬性在某些狀況下也有由 compiler 推導出來,見後續)。 transaction_unsafe 用來表明一個 function 不 safe,compiler 就可以阻止他被呼叫(比方說雖然現在這個 function safe,但是未來改版以後可能不 safe,我們知道他未來有不 safe 的可能性,所以我們希望現在就禁止他被使用)。
也可以直接修飾 class,這樣這個 class 所有的 member function 都會被修飾,然後每一個函數也可以各自修飾來 override safety。

__transaction_cancel

可以用 __transaction_cancel 放棄一個 transaction。__transaction_cancel 也可以跟 throw 一起使用,發出一個 cancel-and-throw,也會放棄 transaction。

outer

transaction 可以 nested,也可以用 outer 修飾來阻止被 nested-inside。另外 outer 也可以用來修飾 throw,讓最外圍的 transaction 被 cancle。只有被 outer 修飾的 transaction 可以被這樣 cancel(目前還沒看到為什麼這麼限制的原因,但應該有原因,後面可能會講到),且 function 也需要標上 transaction_may_cancel_outer 來修飾,不然不能發出 outer throw。
exception 被丟出 transaction,且不是使用 cancel-and-cancel 的話,transaction 有效!(這點跟 wiki 上面提到的不一樣,看樣子這個設計不是普世價值)

Safe and Unsafe

單位是 statement。safe statement 或是 unsafe statement。
只有 safe 的 function 可以被呼叫,這些 function 叫做 transaction-safe function,另外一類叫做 transaction-unsafe function。一個 function safe 不 safe 是型別的一部分,所有寫到這個函數的地方都必須一致,不能有的地方 safe 有的地方不 safe。
你可以用一個 unsafe 的 function pointer 指到一個 safe 的 function。但是不能用一個 safe 的 function pointer 指到一個 unsafe 的 function(有點類似 const 的觀念)。

Lambda 也有 safe/unsafe。

如果一個 statement 有以下任何一個特性,那他就是 unsafe:
  • 他是一個 relaxed transaction
  • 他是一個 outer atomic transaction
  • 初始化一個 volatile 或 assign to 一個 volatile 或 read from 一個 volatile 變數
  • 他是一個 unsafe asm,但是什麼 asm 是 unsafe 則是看 implementation dep
  • 呼叫一個函數,但是這個函數不是 transaction-safe 或是 may-cancel-outer(It contains a function call to a function not known to have a transaction-safe or may-cancel-outer function type)到底在講什麼...

一般的 function 宣告,如果你沒有特別指定,他 implicit 根據裡面有沒有含有 unsafe 的 statement 來決定自己 implicit 宣告成 safe 還是 unsafe。但是「直接呼叫自己」的 recursive 函數是 unsafe(應該是說 compiler 會偵測 directly recursive call,但是 indirectly call 就不管),但是你也可以 explicitly 指定 recursive funciton 是 safe。

template function 一樣也會自動推導則,但是,是具現化以後才推導,會看內含 statement safe 不 safe,如果有 unsafe 的 statement,那就 implicit unsafe,如果全部的 statement 都是 safe,那就 implicit safe。

Ctro 跟 Dtor,user defined 的當然就是作一般 (template) function,compiler generated 的,就看 base class 跟 non-static data member 的 Ctor/Dtor 是不是 safe。

Transaction Expression

SomeType myObj = __transaction_atomic ( expr );
SomeType myObj = __transaction_relaxed ( expr );

作用於 expression 求值的過程。也就這個求值的過程,會是 trasactional 的。

transaction expression 不能 nested。也不允許用 outer 修飾,也不能含有 transaction statement,也不能含有 cancel,也不能含有 cancel-and-throw,因為 C++ 不允許 expression 含有 statement。接下來還有一堆超饒舌的,先跳過,看了實在好想吐 orz 18 頁第 1 行。

Function Transaction Blocks

void f() __transaction_relaxed {
}
void f() __transaction_atomic {
}

意思就是這個 function body 內部的執行,會是 transactional。

如果這個 function 剛好是 Ctor/Dtor 的話,那個 base class 跟 member class 的初始化也都是 transactional 的。下面一個例子,比方說這個 class 的每個物件都有一個流水號,根據一個 global variable 來的。

class Foo {
    static size_t _count = 0;
    size_t _id;
    Foo() __transaction_atomic {
        _id = _count++;
    }
}

function transaction block 也可以跟 try block 混在一起。

try __transaction_atomic : Foo() {
}
catch (...) {} // catch 不是 transaction 的一部分
__transaction_atomic try : Foo() {
}
catch (...) {} // catch 是 transaction 的一部分

__transaction_cancel

可以用來放棄一個 transaction,只能寫在 atomic transaction 裡面。transactional expression 不能 cancel,function transactional block 也不能 cancel。

__transaction_cancel [[outer]];

outer cancel statement 只能寫在被標明為 transaction_may_cancel_outer 的 atomic transaction 或是 function block transaction 裡面。

幹……怎麼會這麼多……後面還有……好想哭……

2012年4月5日 星期四

喜歡上一個漫畫家「冬目景」

喜歡上一個漫畫家「冬目景」。

最早是在,可能有十年了吧,在表弟家看到的一本漫畫叫作《黑鐵》。一個人被改造成機器人的劍客故事,聽起來既白癡又低能,不知道是搞笑漫畫還是熱血打鬥,但是實際上卻是一點點抑鬱的,很觸動人心深處的故事,跟劍客不劍客沒什麼關係。就像很多科幻小說,除去科幻的部份,卻還是很精彩,我想,好的故事,跟背景設定無關,而是故事本身的重點是在人身上,而黑鐵就是這樣的故事,重點在人身上。後來在清大念研究所,宿舍的交誼廳也放著一套黑鐵,但是並沒有全部,這次我很仔細的全部看了,更喜歡這個漫畫了,我發現他不只是故事好,畫面也總是帶一點點悲戚的美,歹勢阿,我文筆很爛,想不到什麼好詞描述,不過就是這樣。

過了幾年的現在,又想到這部漫畫,想起來,想去把結局也看完,上往搜索了一下,才發現這個漫畫連載中斷,所以沒有結局了。也知道了作者叫作「冬目景」,ㄟ,我發現我看過她的《白老鼠遊戲》但是卻沒什麼特別的印象。發現冬目景的作品很多都中斷連載,不知道原因,只覺得很可惜。看了一些作品的介紹,看到《昨日之歌》好像會是我喜歡的類型的故事,就去找來看了,結果……真的很喜歡,只是看的過程常常會不小心的掉下眼淚,冬目景的畫真的很漂亮 ^^ 應該說畫面看起來常常髒髒的,筆觸也斷斷續續的,但是看起來就是很漂亮,筆觸成熟,看起來很隨意,不會講,懶的寫了 @_@ 反正很喜歡,害我很想寫部落格,不過我寫不出什麼毛,所以還是停吧...

2011年11月4日 星期五

Vim 自動提示編譯錯

Vim error highlight

2013/08/12 更新[[[ 自從 YouCompleteMe 這個 plugin 出來之後,一堆 plugin 都變成垃圾了,包含這篇文章的所有內容,也變成垃圾了,請直接參照 https://github.com/Valloric/YouCompleteMe 然後不用再往下讀了。 ]]]

一直想要一種功能,就是 vim 可以自動顯示錯誤的程式碼,像是 visual studio 或是 eclipse 那樣。最近摸索了一下終於讓我實現了這個功能 :P

事先準備

  • AsyncCommand plugin

    可以在背景執行動作,不會妨礙現在進行的編輯作業。

  • errormarker plugin

    可以把 quick fix list 裡面的錯誤,轉而使用 syntex highlight 直接在編輯視窗內標示出來,看一下官方網站的 screensho:

    http://mh21.piware.de/vim-error-markers-doxygen.png

進行修改

理論上這兩個東西都有安裝的話,好像就成功了,不但可以在背景編譯,還可以在編輯畫面表示錯誤。當然,實際上這兩個都安裝了以後,還是沒辦法直接達成目的的,不然我也不用寫這篇文了 XD

經過 trace 兩者的 script 以後,發現原因在於 errormarker 是透過 hook QuickFixCmdPost event 來呼叫 SetErrorMarkers() 函數來把 quick fix list 裡面的資料轉標到編輯畫面。當平常使用 :make 的時候,QuickFixCmdPost 會被觸發,但是當透過 AsyncCommand 進行 make 的時候,似乎不會觸發 QuickFixCmdPost 事件,於是 SetErrorMarkers() 也不會被呼叫,然後一切都完啦。所以我們的目標就是讓 AsyncCommand 「正確」的呼叫 SetErrorMarker() 就好。

先講一下 AsyncCommand 的機制,AsyncMake 其實是一個 wrapper,包住了 asynccommand#run(make, asynchandler#qf) 這個動作,後面那個 asynchandler#qf 是等到 make 結束以後,用來處理結果的 handler,而這個 handler 會在 asynccommand#done() 的時候被呼叫,所以我們只要在 asynccommand#done() 裡面呼叫 SetErrorMarkers() 就可以了。

asynccommand#done().vim/bundle/asynccommand/autoload/asynccommand.vim 這個檔案裡面,找到他,

 1   function! asynccommand#done(temp_file_name)
 2     " Called on completion of the task
 3     let r = s:receivers[a:temp_file_name] "handlers are registered in s:receivers
 4     if type(r.dict) == type({})
 5       call call(r.func, [a:temp_file_name], r.dict)
 6     else
 7       call call(r.func, [a:temp_file_name])
 8     endif
 9     unlet s:receivers[a:temp_file_name]
10     delete a:temp_file_name
16   endfunction

在函數結束之前加上呼叫 SetErrorMarkers() 的程式碼,變成這樣:

 1   function! asynccommand#done(temp_file_name)
 2     " Called on completion of the task
 3     let r = s:receivers[a:temp_file_name] "handlers are registered in s:receivers
 4     if type(r.dict) == type({})
 5       call call(r.func, [a:temp_file_name], r.dict)
 6     else
 7       call call(r.func, [a:temp_file_name])
 8     endif
 9     unlet s:receivers[a:temp_file_name]
10     delete a:temp_file_name
11
12     if exists("*ExposeSetErrorMarkers") " Check and
13       call ExposeSetErrorMarkers()      " Call ExposeSetErrorMarkers()
14     endif                               " here
15     
16   endfunction

注意到我們呼叫的不是 SetErrorMarkers() 而是 ExposeSetErrorMarkers(),這是因為 SetErrorMarkers() 是一個 script local 函數,只能在 script 內部被呼叫,所以我在 errormarker.vim 裡面加了一個函數來曝光 SetErrorMarkers()

1   function! ExposeSetErrorMarkers()
2       call s:SetErrorMarkers()
3   endfunction

這樣以後只要輸入 AsyncMake 就可以在背景編譯,編譯完成以後自動 highlight 錯誤了。為了方便使用,我還加上了幾個 autocommand:

1   au BufWritePost *.h   AsyncMake
2   au BufWritePost *.c   AsyncMake
3   au BufWritePost *.cc  AsyncMake
4   au BufWritePost *.cpp AsyncMake

這樣編輯 c/c++ 的時候每次存檔都會自動編譯然後 highlight 錯誤。

其實我知道我的改法很醜啦,但是他 work XD 如果有人知道比較優雅的改法請跟我分享阿~

小記:我發現我 ubuntu 安裝 vim 的話,是沒辦法作這件事的,執行 script 的時候會發生錯誤,但是安裝 vim-gtk 的話就可以了,不知道是因為設定的時候哪個選項沒開,但是總之如果有人遇到一樣的問題的話請試試看安裝 vim-gtk。

2011年9月26日 星期一

眷村有個每天騎腳踏車巡邏的老人今天睡覺沒醒


這個老人每天都打著赤膊,騎著快解體的淑女車,大街小巷的到處跑,也沒有要去哪裡,反正就是一直到處騎,但是範圍非常的大,航跨十公里的範圍內都有機會看到他打著赤膊慢慢的騎著腳踏車,雖然沒有人從頭到尾跟著他走過一趟,但是我相信他每天的路線應該都是一樣的。

騎了幾十年了,大家都認識他了,他以前是一邊騎,一手抓著米酒頭在灌,臉紅紅的,身體也紅紅的。十幾年前開始,酒沒了,取而代之的是菸,一邊慢慢的騎車一邊抽菸。手上沒菸的時候如果遇見認識的人,就會先擋兩根來(也不會還 XD)。像我小舅舅每天晚上固定的時間就會在外面抽菸,也固定給經過的他兩根菸。

厲害的是他向來都只穿一條褲子,從來不穿上衣。除了有一年冬天超冷,某天他穿了一件短袖上衣出來,大家沒認出是他 XD


外婆說今天上午那人一樣到處騎腳踏車,遇見認識的人也一樣擋兩根菸,一樣都是活跳跳的,中午那人吃飽了以後去睡午覺,下午快五點的時候,眷村裡面其他的老人去他家要去找他吃晚餐的時候,發現他還在睡。

其實永和這個大陳義胞五和新村已經很老了,眷村裡面,老一輩的,小時候跟著兩蔣來台灣的,現在的年紀最起碼都六七十起跳,都是隨時就會回家的狀態。眷村裡面,巷弄間,總是家家戶戶的人都坐在門口的藤椅上聊天,誰家發生什麼事,誰家女兒嫁人了又離婚了,誰家曾孫出生了,大家都知道。這些年來,每兩三年總有一個兩個人就不見了,就不會再出現了。

所以當鄰居發現他還在睡的時候,也沒很驚訝。因為這也沒什麼,就是回家時候到了。通知了還在陽明醫學院唸書的女兒,救護車來就把人帶走了。

外婆:「早上騎車的時候還活跳跳的,怎麼中午睡覺就不醒了 -_-」
小舅:「本來每天都被要兩支菸還蠻賭爛的,久了也有感情了....」

至少是個走的安詳。

2011年9月24日 星期六

我外婆,在美國

聽外婆講了幾個當初她跟外公到美國去生活發生的笨事,覺得很有趣,記錄下來。

當初外婆跟外公兩個人,年輕的時候,就這樣跑去美國了,英文也不會講,只會很簡單的 yes 跟 no 之類的。但是還是就這樣跑去美國了,準備開始過他們的新生活。

到美國的時候,天氣跟台灣不一樣,空氣很乾,外婆走在路上,覺得臉很不舒服,因為臉都乾掉了,而且也很冷,不知道怎麼辦之際,看到旁邊的百貨公司,竟然有很多沒人要的透明塑膠袋,看起來品質很好,很厚,恨透明,而且還很乾淨,外婆異想天開,想說既然很乾淨、又沒有人要,外婆就把塑膠袋撿來,然後往自己的頭上一套,既可以擋風,又可以保住溼氣,還可以看到外面,所以可以正常走路沒問題。「我真聰明,呵呵」外婆說。塑膠袋套好以後,外婆把原來連帽大衣的帽子也套上,蓋在塑膠袋外面,便更覺溫暖。那知道,一個不小心吸氣的時候,塑膠袋竟然就捂住口鼻了,一下子不能呼吸,外婆急了,就大口吸氣,但是塑膠袋就包的更緊,然後因為急了,也忘記要先把帽子掀開,結果塑膠袋要往上拉開就一直被帽子擋住,塑膠袋一直拉不開阿!一口氣上不來就快要死啦!外婆就狂扯塑膠袋,但是因為塑膠袋的品質很好,竟然扯不破!!!救命啊!最後不知道是怎麼的終於把塑膠袋弄開了 =_= 外婆說「那件事情之後我就有陰影,所以我看到小孩子在玩,把塑膠袋套頭上的時候我都很害怕。」「外婆,還好你沒死,不然很丟臉,塑膠袋套頭上,人家會以為你是自殺的,新聞標題寫『移民疑似生活困難想不開』,被認識的人看到你會被笑死 XD」「真的,還好沒死,哈哈哈哈哈」

有一次,從租屋處下樓出來丟垃圾的時候,把門開著,想說丟完垃圾就回去,結果沒想到就在人在外面的這短短的時間裡,風從房內的窗戶吹來,把門給甩上了,外婆人就被鎖在外面進不去。雖然房東就住在一樓,但是外婆並不想去跟房東拿鑰匙開門,「因為我每次有事去找他,他都會趁機偷抓我的屁股 =_= 我很生氣,寧願坐在外面吹風也不要去跟他拿鑰匙!」房東是個老米,死老不修。結果我外婆就這樣坐在外面,也不知道要幹麻,就一個人在路邊發呆,一直作到晚上,鄰居的華人回來的,看到外婆「阿你怎麼坐在外面?」「我出來丟垃圾,結果門被風關上了進不去」「那怎麼不去跟房東拿鑰匙?」「不想 = =」結果鄰居幫外婆去拿鑰匙,最後外婆才進的了家門 XD

還有一次,又是出來丟垃圾的時候,門又給風關上啦~!這次外婆一樣不想去找房東拿鑰匙,因為不想被摸屁股 XD 但是這次不一樣的是:外婆正在燒開水 XD 如果不趕快進去屋裡把火關掉,整棟房子搞不好燒光光。那怎麼辦捏?外婆住在四樓,想到二樓有一個認識的鄰居,是一對華人夫妻,就跑去三樓敲門,老公出門去了,只剩下老婆在家「那個,你家能不能讓我過一下?我門給風關上了,我想要從窗戶外面爬逃生梯上去」「不行啦!我老公如果知道我讓別人進家門他會打我耶!」「拜託你啦!我正在燒開水,如果進不去的話,整棟房子都要燒掉耶!」結果對方才讓外婆進去,外婆沿著外面逃生梯往上爬,爬到四樓,但是靠著逃生梯的窗戶是鎖著的,開著的是稍微有點距離的另外一扇窗戶(風也就是從這個窗戶灌進來把門甩上的),那個有窗戶有段距離「年輕的時候比較不怕死,我就沿著牆壁邊緣爬過去」沒想到外婆竟然就扮演蜘蛛人了。因為很危險,所以外婆花了很久的時間才爬過去,結果爬到一半的時候,被附近的米國人看到了,以為我外婆是小偷,正在從逃生梯想要爬去窗戶偷東西,結果那個老米報警了,警察來了,找了房東,房東拿了鑰匙,開了我外婆那戶的門,等我外婆好不容易爬進窗戶的時候,警察跟房東已經在家裡面等她了 XD

感恩節到了,朋友送了她們一隻火雞,但是外婆說她不知道火雞要怎麼吃,「好大一隻,中國人又不會吃這種東西,轉送給其他華人朋友也沒有人要 =_=」最後想一想,就決定拿去送給房東。房東夫婦都在,因為外婆不會講英文,外婆就在那邊比手畫腳,說要把火雞給房東,房東大概看懂意思了,就很開心準備要接受,結果我外婆就繼續比手畫腳,作出摸自己屁股的動作,然後跟房東說「No! No! No more!」意思就是「你以後不要再摸我的屁股!」當然房東看的懂是什麼意思,沒想到房東太太也看懂了,結果現場發火,把房東先生打一頓,外婆就很開心的回家去了 XD

有一天鄰居提議要吃炸雞,說他出錢,讓外婆去買,鄰居教外婆,雞的英文叫做「七肯」,外婆記住了,就跑去買炸雞,因為家裡到賣炸雞的距離很遠,外婆走了很久才到,結果走到的時候,已經忘記雞的英文是什麼了「糾竟是七肯還是八肯呢?」想了很久,還是想不起來,外婆最後決定應該是「八肯」,然後就跟店員「八肯、八肯」了很久。當然,不管外婆再怎麼八肯,店員也不會把雞賣給她。外婆只好再走很遠的路回家,再問一次雞的英文到底是七肯還是八肯,然後再跑去買,結果第二次到店裡面的時候,忘記兩人份的「吐」怎麼講了,不過這個比較簡單,後來外婆比了兩根手指,店員:「吐?」外婆:「對!對!對!吐!吐!吐!吐!」就解決這個問題了 XD

有一天走在百貨公司附近的時候,看到兩個米國年輕情侶正在接吻,外婆看到覺得很震驚!因為在台灣不可能有這種事情啊!那個時候民風保守,外婆從來沒見過這件事情,就看傻了眼,雖然眼睛看傻了,腳還在一樣在走路,但是就沒在看路,結果竟然一腳踩進清潔工留在走廊上的水桶!踩進去就算了,外婆想要把腳抽出來,但是卻沒成功,還被水桶絆到!結果整個人一直往前撲跌,最後一張臉直接撞在百貨公司的玻璃上!轟隆的好大一聲!外婆因為很痛,無法痛談,臉貼著玻璃,百貨公司裡面的人因為巨響通通看出來了,看到外婆的臉黏在玻璃上,一隻腳還在水桶裡 XD 外婆爬了起來,沒事一樣的繼續慢慢散步。我:「你沒有快點逃走嗎?很丟臉耶 XD」「有什麼好丟臉的 A_A 美國人又不認得我的臉 A_A」