ECMAScript 6 Final Draft Approved

剛剛看到說 ECMAScript 2015(ES6) 定稿了,最後一版草稿是 RC4(還沒 release),接下來會是 ECMA 認證流程的樣子,不過繼續下一版的討論也不會中斷,順便要說一下他們最後 approve 的地方是在 H.R. Giger 博物館的酒吧,超酷的,這是畫異形那位大師的博物館。


For the Entire Web

這陣子有兩件事情引起我的一些注意,覺得值得寫下,兩件事情我覺得其實本質上是同一件事情,先來看一下第一件事情,就是 Daniel Yoder 寫了篇文章 React Is A Terrible Idea,這篇文章在 React 當紅的時間出現,自然引起很多人的不滿,隨便在 Google 上搜尋就可以找到一堆回應,我自己對於 React 其實是沒特別感覺,沒有喜歡也沒有覺得它做錯什麼,真的要說的話大概還有點覺得它方向正確,我是認為 React 和 Angular 的 directive 都在把 component 的觀念引入前端工程師的視野之中,而這對於 Web Component 的發展應該會是有正面影響的。

再回到 Terriable Idea 這篇文章,作者對 React 的評論我其實不完全認同,最後面有提到用 Web Component 而不要用 React,這部分我覺得是作者誤會了 React 的角色,不過有些地方有人說 React 明明就可以和 Web Component 合作,還附上 ng-conf 的演講影片,我到覺得他們也完全沒搞清楚作者的重點在哪裡;提到 Flipboard 的 react-canvas 那部分算是我認為最能表現出作者想要講什麼的,作者想說的重點是現在的網路環境有限制、有問題,但是遇到時不要用一些旁門左道的方法來處理,因為這些問題終究會被解決,而問題被解決時,你之前所花的時間和資源就等於是完全浪費掉,與其要浪費在走旁門左道,還不如把這些時間和資源用在從正確的地方解決這個問題,而最後受惠的不只是自己,還有所有網際網路的開發者、使用者,這是從一個很高等生命體的角度來看事情,就如同這篇文章的標題:「For the Entire Web」,要你犧牲自己的部分利益去成就整體網際網路的利益,當然這是有些理想化,很多商業公司可能要短時間就有產品出來,不太可能所有的開發在遇到問題時都停下來等瀏覽器或是標準齊備,但是對於不少的大型企業,我就覺得他們確實應該要好好正確的回饋網路環境來解決這些問題,像是文中提到 Facebook,還有接下來要說的 Google,不過他說 Facebook 是為了和 Google 競爭才開發 React 之類的論點我就不予評論了,太多臆測~

可能有人會說,有沒有這些資源的投入應該差距也不大吧,最近就剛好有另外一件事情可以佐證,Dart for the Entire Web 這篇 Dart 官方的公告說到,Dart VM 將不會進入到 Chrome 裡面,也就是說要在瀏覽器上跑 Dart,將還是只有轉成 JavaScript 這個選項,這件事其實是蠻大的一件事,上一個在網頁裡面跑的另外一種語言是微軟的 VBScript,最大的問題不在於好不好寫,而是在於他被單一企業把持,不過後來結果大家也都知道,所以當 Google 推出 Dart 而且說以後 Chrome 會可以直接跑 Dart 的時候,我想大部分人都是都不看好的,甚至部分人是覺得 Google 怎麼做微軟做過的蠢事。而剛好在這個官方公告出來後幾天內,Brendan Eich 在 Hacker News 上回應一串討論回應的蠻激動的,這串本來是在說 ECMAScript 新版本有很多東西根本是從 Dart 來的,Brendan Eich 則是反駁說很多東西在 Dart 出來前就已經在討論有 Proposal 了,然後到後來寫了一篇幾乎都在抱怨 Dart,還提到 V8 team reset 的事情,從這邊看起來,似乎是因為新的 V8 team 不打算作 Dart VM 進去,才有了 Dart 那篇公告;而 Brendan Eich 抱怨的重點,其實就是前面那段提到的,Google 花了超多人力資源去搞 Dart,而不是來幫忙改進既有的 ECMAScript,而這確實有實際的影響,他舉了一個例子,就是大數(bignums)的支援,Dart 有支援,在 ES 這邊目前有一點可能性會在 ES7(2016) 中出來,但這東西其實從 2010 就已經開始有討論了,如果有人來將這些討論規格化,並實做起來,那大數應該在現在的 ES6(2015) 就有了。

最後再回到 Terriable Idea 這篇文章,我雖然不完全認同他對 React 的看法,但是我認為他的重點沒錯,如果他拿 Dart 出來講可能就不會引出這麼多砲火吧(可是可能也比較沒人注意),其實 react-canvas 我覺得也是很有趣的實驗,不過做成正式產品上線就是另外一回事了,最大的問題,他為了終會被解決的次要問題(畫面不流暢)完全放棄了親和力的問題,而 Flipboard 這種內容為主的產品性質是不該放棄親和力的。


Vim Syntax and Regexp Note

前陣子為了寫更好的 Vim syntax 還去學了 compiler 的課程,雖然沒上完不過也對怎麼解析語法理解不少,不過其實 Vim syntax highlight 系統為了效能問題,有不少限制,沒辦法真的和 compiler 的 parse 原理完全互通,其中兩個限制影響比較大,第一個是沒辦法有完整的 AST 並解析其語意,因此除非寫得非常繁複,一定會有無法正確 highlight 的地方,例如 comment,不是說 comment 不能正確標示,問題是 comment 可以插入在很多地方,像是參數序列的中間,function關鍵字和後面()的中間等等,幾乎是可以放空白字元的地方就可以放 comment,然後不會影響程式語意,本來,不考慮註解時,我可以用skipwhiteskipempty然後加上nextgroup就可以指定下一個 token 是什麼,以 JavaScript function declaration 來說:

function fn (a) {}

這樣的程式碼我把他拆成四個部分,function keyword、function name、function parameter、function body,然後用 Vim syntax 語法設定:

syntax keyword javascriptFuncKeyword function nextgroup=javascriptFuncName skipwhite
syntax match   javascriptFuncName    contained /\k\+/ nextgroup=javascriptFuncParam skipwhite
syntax match   javascriptFuncParam   contained /([^()]*)/ nextgroup=javascriptFuncBody skipwhite
syntax region  javascriptFuncBody    contained start=/{/ end=/}/

除了 function keyword 外都有contained,用途是讓該 rule 不會在 TOP region 下生效,一個好處是減少 TOP region 下要檢查的 rule 數量,另一個好處是有些相同的 token pattern,但是其實語意上是不一樣的,可以盡量用這種機制拆分開來,到這裡都還很美好,但是加上 comment 後問題就變複雜了,先簡單寫一下 comment 的 syntax rule:

syntax region  javascriptComment     start=/\/\*/ end=/\*\//

然後 comment 可以放在哪些地方呢:

function /*cc*/ fn (a) {}
function fn /*cc*/ (a) {}
function fn (a) /*cc*/ {}

也就是本來 nextgroup 連接的地方都可以插入個 comment,可是只要插入了 comment,後面的 token 就不會被正確 highlight,因為 comment 的 rule 沒有 nextgroup,所以他的部分結束後就會回到用 TOP region 的情境,而後面應該符合的 rule 都有設上contained,所以就沒機會對到。當然現在要解決這個問題也不是沒方法可以避開,但是非常不好看,就是如下的設計:

syntax keyword javascriptFuncKeyword function nextgroup=javascriptFuncName,comment1 skipwhite
syntax match   javascriptFuncName    contained /\k\+/ nextgroup=javascriptFuncParam,comment2 skipwhite
syntax match   javascriptFuncParam   contained /([^()]*)/ nextgroup=javascriptFuncBody,comment3 skipwhite
syntax region  javascriptFuncBody    contained start=/{/ end=/}/

syntax region  comment1     start=/\/\*/ end=/\*\// nextgroup=javascriptFuncName,comment1 skipwhite
syntax region  comment2     start=/\/\*/ end=/\*\// nextgroup=javascriptFuncParam,comment2 skipwhite
syntax region  comment3     start=/\/\*/ end=/\*\// nextgroup=javascriptFuncBody,comment3 skipwhite

如此可以確保 comment 插入也不會讓後面的 token 沒 highlight,但是這樣的設計,實際寫起來會非常繁瑣,完全不想去研究 JavaScript 中會有多少類似的狀況。其實我是覺得 Vim syntax 應該是希望盡量都用前後獨立的 rule 來 highlight,盡量不要有前後相依的關係存在,就不會有上面的問題,也可以讓 highlight 過程比較單純,理想上是從頭開始,一個 token 一個 token 各自獨立的 highlight,不過是事情當然沒這麼簡單,第二個想記錄下來的事情也和這個有關係。

假設目前 highlight 處理中,parse 到一個=,然後看到一組小括號(a),連起來如下:

= (a)

這時你會覺得(a)是什麼呢?是小括號,裡面是一個 expression 然後回傳變數a嗎?相信很多人會這樣認為,如果他後面是接分號的話:

= (a);

但是其實也可能是這樣子的:

= (a) => {}

ES6 的 arrow function,也就是說,如果一個 token 一個 token 解析,一定無法直接知道目前 token 代表的正確意義,所以 compiler 把程式碼轉成 AST 的時候,有時候會先往後面看一下來判斷現在的 token 到底是什麼意義。然而 Vim syntax 系統並沒有這種能力,嚴格來說,是可以用 match 來達成,不過還是很受限制。再來則是往前看的問題,我在設定運算子的 match rule 的時候,會希望嚴謹一點,本來想在兩邊加上 word boundary 的 pattern,在 Vim 裡面是\<\>,不過測試幾回發現,我的字元本身不是文字字元的話,這個 pattern 是沒有用的:

/\<word

這樣是有效的,但是下面想要 match==的會沒用:

/\<==

所以變成要自己寫往前看的 regexp,在 Vim 裡面有兩種類似的東西可以用,分別是\zs\@<=,通常,\zs效能比較好,會推薦使用,他的用途是標註你的 regexp 的 match 的起點,當然同時也有一個\ze是終點:

/abcd\zsefgh\zeijkl

上面這串 regexp 的目標是efgh,但是他的前後分別是abcdijkl,實際執行時會去找abcdefghijkl這串字串,完整比對到之後,只會回中間的efgh作為 match 的範圍,這設計要做一些操作的時候就會有差,像是文字取代。本來我就想要用這個來做 syntax,可是就發現還是不生效,所以改成用\@<=試試看:

/\(abcd\)\@<=efgh\@=\(ijkl\)

就發現成功了,想了許久才理解其原因,然後才瞭解,真的往前看的是\@<=\zs並沒有往前看,兩者最大的差異在於 pattern match 操作的起點,一般的使用大概感覺不太到差異,不過像是 syntax highlight 這種一個 token 一個 token 逐步處理的就會有差,當目標是efgh時,通常處理進度到e這個位置時,前面的abcd已經被處理過了,所以這時候會和 regexp 比對的字串就變成efghijkl,使用\zs的話,因為它還是要完整比對到abcdefghijkl,起點是a,就不會和efghijkl相符,但是用\@<=的話,pattern 的起點是efghe,這樣就可以 match 到目前剩餘的字串了。

前面說的個 token 一個 token 逐步處理的問題還有一個情形也讓我困擾很久,不過這次不是東西被用掉,問題是沒被用掉。這個狀況發生在巢狀結構的 region,像是 JavaScript 的 block:

syntax region  javascriptBlock start=/{/ end=/}/

然號要讓 block 裡面可已有 block 就要用contains

syntax region  javascriptBlock start=/{/ end=/}/ contains=javascriptBlock

這時候就會發生奇怪的現象了,因為外面的 region 包括了頭尾的括號,然後進入 block 內要做 syntax match 的時候,一開始的{又 match 到 block,結果 Vim 就直接覺得這已經是第二層的 block 了,雖然好像有其它機制讓他不會一直循環下去變成無限多層,不過這樣還是會造成後面的 code 有被判斷錯誤的機會,因為 block 的開關不 match,這裡的關鍵也是要讓{}被處理掉,進入 region 內部就不會跑到上一層的起點,而這裡要用的就是matchgroup

syntax region  javascriptBlock matchgroup=bracks start=/{/ end=/}/ contains=javascriptBlock

如此就都會正常了,因為這樣的設定會讓{}直接被當成bracks這個 group,然後就被當成已經被解析過的 token,從它的下一個 token 繼續 highlight 分析,但是千萬不要另外加上bracks的 syntax rule,剛好又 match 到 region 的起點和終點:

syntax match   bracks  /[{}]/

這樣的話也會發生其它的怪異現象,總之 nested region 的重點在於,要用 matchgroup,然後不要用和 matchgrouop 同樣名稱,同樣 pattern 另外又設定一組 rule。

最後一個要紀錄的則是 Vim syntax 裡面的優先度,基本上是 keyoword 優先度最高,也就是有 match 到 keyword 的話,你的 match pattern 就都無效了,所以像是 JavaScript 裡面,label 雖然不可以用關鍵字,像是continue:就不合法,但是因為會先 match 到continue關鍵字,所以就很難用 syntax highlight 來標出這種錯誤,而在 keyword 比對完之後,才輪的到 region 和 match,兩者是同樣權重,但是後定義的優先,而且不受containsnextgroup裡面的順序影響,搞清楚優先順序在做細部的 syntax highlight 的時候還蠻重要的。另外要順便說說 region contains 和 nextgroup 的差異,nextgroup 其實還蠻不錯的,他不是限制下一個 token 一定是哪些東西,而是改變優先順序,先檢查完 nextgroup 裡面的東西,再檢查該 region 下的其它可能性,region contains 就不一樣了,該 region 裡面只有在 contains 裡面的東西會出現,另外還要特別注意一點,region 的處理並不管該 region 能不能正確的關閉,只要 match 到起點,就會把 region 打開,然後剛剛有提到,region 和 match 是同樣權重的所以就要非常注意:

syntax match  javascriptLabel       /\k\+:/
syntax region javascriptLabelblock  start=/\k\+: {/ end=/}/

這樣兩條 syntax highlight rule 然後配上下面的程式碼:

abcd: {
  var ii = 1 + 1;

var jj = 2 + 2;

要注意我的 block 其實沒有結束,但是結果 Vim 只會 match 到 label block 那條規則,而且由於一直找不到 region 的結束點,所以下面的var jj那行也是被認為在 block 內。

最後的最後要推薦一下 gerw/vim-HiLinkTrace 這個 Vim plugin,可以很完整的 trace syntax highlight 的狀況。


MacBook 2015

前兩天發表的 MacBook 很多人不看好,不過我倒是很看好的那邊,連我都想買了,不到一公斤但是確是台完整的 OSX 電腦,有正常大小的鍵盤、感壓觸控版,加上 Retina Display,買一台金色的去咖啡廳簡直要橫著走了,不過更讓我好奇的是它竟然沒取代 Air,Air 還比較重真是情何以堪,我推測比較可能的發展是 Air 產品線未來會收掉,回到之前兩條產品線的狀況。

另外還有一點讓我很好奇的就是觸控版的部分,一來是好奇他的感壓加上震動回饋操作起來的感覺 ,二來是 MacBook Pro 13 吋有更新,但是 15 吋卻沒更新,要知道相較於 13 吋 MBP,15 吋更新的頻率實在是低很多,在這個新觸控版的更新上竟然還沒有 15 吋的,實在不太合理,所以我猜蘋果是等另外一個產品出來:27 吋 5K 的 Cinema Display,可能很多人不知道,蘋果之前出的 iMac 5K 和以往不一樣,不能當作外接螢幕,其中一個最大的原因是目前通行的傳輸介面還不能傳輸到 5K 解析度,市場上的 DisplayPort 幾乎都是 1.2,至少要到 1.3 才有辦法處理 5K 解析度,iMac 5K 發表則只比 DisplayPort 1.3 晚一個月左右,蘋果除了要等 DisplayPort 1.3 之外,還有另外一個就是這次 MacBook 的主角之一:USB 3.1 Type-C,這條新的介面真的很強,除了向下相容外,可以反差,可以傳更多電力,傳輸資料量當然更大,還可以傳輸影像訊號,用的就是 DisplayPort 規格,嚴格說來是 DisplayPort 規範有個 Alternate Mode 可以使用其它線材做傳輸,而 DisplayPort 1.3 理想最高資料量的情況下(其實就是 5K 解析度)都還塞不滿 USB 3.1,可以邊傳完整 5K 畫面邊傳資料。我的猜測就是 15 吋 MBP 下次更新除了新的觸控版外,還有 USB 3.1 Type-C,更強的顯示卡,然後同場加映 27 吋 5K 的 Cinema Display,用 USB 3.1 Type-C 連接,同時供電,傳資料,以前 Cinema Display 那條三頭的線就一條 USB 解決了。

最後話題回來 MacBook,其實我覺得這台打的目標消費者族群很明確,就是買 MacBook Air 的那個族群,MacBook Air 剛出來其實是比 MacBook 還要高級一點的,現在兩邊角色正好互換,其實也是蠻有趣的。

MacBook_OP90_Tilt_Gld-PRINT


更之前的文章