A programmer had a problem. He thought to himself, “I know, I’ll solve it with threads!”. has Now problems. two he
— Davidlohr Bueso
這裡是 WWW 第拾期,Wow Weihang Weekly 是一個毫無章法的個人週刊,出刊週期極不固定,從一週到五年都有可能。初期內容以軟體工程為主,等財富自由後會有更多雜食篇章。
The Missing Semester of Your CS Education
這是近期看過最實用導向的大學課程了!由 MIT 博士生授課,但不教死板又混亂的計算機科學,而是貼近開發者,異常實際的工具和技巧。
雖然內容對部分業界人士來說可能略淺,例如 metaprogramming 居然是在講 build system 和 makefile,不過學資訊的學生不一定熟稔,非常適合作為進入業界前先修的「失落的課程」。我自己印象最深刻的是「 …if you start a command with a leading space it won’t be added to you shell history. 」真的是嚇歪我的毛,推薦大家翻翻看看。
順便提一下 JonHoo 是我有認真在看的 live-coder。嗯,應該猜的到他寫什麼語言
Early Impressions of Go from a Rust Programmer
我有過很多面之緣的 Rust 核心成員 Nick Cameron 在大型專案中使用 Go 語言後(我猜是 TiDB)的評價,摘要個人覺得有趣的觀察面向:
- 很實際,設計得宜、小巧好學、std lib 很小很讚
- 比 C、C++、Java、Python 開發快,而且有很多改善,但撰寫感覺上是同世代的語言,例如還是有 null pointer
- 少了 macro 和 generic,專案大就會有許多 boilerplate 和
if err != nil { return err }
,讓閱讀原始碼變得困難 - 有 var args(應該是跟 Rust 比 XDD)
go
tooling 集中一處而非分散成好幾個小工具,很方便- 沒有 first class enum,用 constant 代替感覺開倒車(也導致
switch
並非 exhaustive,也就是 compiler 不會要求窮舉所有 enum member) - 在內建功能和黑魔法之間的取捨不太一致,Go 有很多魔法,但也很多簡單的事無法達成,例如
for ... range
可用在 array 和 slice 但不能用在其他 collection type;len
、append
是全域泛型函數,但只能用在內建型別,而且不能自己定義全域函數
個人認為 Nick 給的評價很正面,而我根據自己不太多的經驗,對 Go 的評價是「A tool to get jobs done easily」,但感覺就是把事情做完,寫程式那種創意設計回饋感較低。
(理性勿戰)
A slick matches!
macro comes with Rust 1.42.0
其實是一篇複習 x86 assembly 的文章
Rust 1.42.0 在 2020 年 3 月 12 日正式釋出,除了實用的 subslice patterns(和 Python 的 slicing 很相似)、更詳細的 unwrap
錯誤訊息(不用再 RUST_BACKTRACE=1
看 callstack),最有趣的就是 matches!
這個 macro,提供了比較 expression 是否符合特定 pattern,不用再寫整個 match
expression 來比較。
但今天想要分享的是 Rust 在 pattern matching 上如何最佳化,這個例子比較 char
是否落在大小寫 A-Z a-z 的範圍中:
pub fn slick(c: char) -> bool {
matches!(c, 'A'..='Z' | 'a'..='z')
}
編譯出來最佳化的組合語言長這樣:
example::slick:
and edi, -33 ; #1
add edi, -65 ; #2
cmp edi, 26 ; #3
setb al ; #4
ret
帥!其實原理很簡單,讓我們一行一行解密:
- 第一行是在抹去大小寫差異,A 是
0b1100001
,a 則是0b1000001
,兩者剛好差了 32,也就是0b100000
,因此可利用 bitmask 抹去第六個 bit,這樣小寫字母都會得到跟大寫一樣的值0b1100001 # a & 0b1011111 # -33 = ~32 = 0b1000001 # A
- 第二行則是將大家一視同仁減去 65,這樣的結果就會落在 0 ~ 25 之間
- 第三行的
cmp
實際上是執行SUB
指令,但只會將結果狀態紀錄在 EFLAGS 暫存器,由於0 ≤ edi < 26
,所以edi - 26 < 0
,可以得知需要借位,所以 CF(carry flag)會被設為 1 - 第四行的
setb
屬於SETcc
指令家族,會針對不同的條件設定 byte value,而SETB
的功能是「Set byte if below (CF=1)」,理所當然AL
會被設定為 1 然後回傳了。
打到這邊心好累,x86 asm 整個忘光,還請教了即將進入 Amazon 實習的大大才解決,我們感謝他。