ブラウザで動くMarkdown editor

vue.jsの公式サイトのexampleにmarkdown editorっていうのがあって、以下のコードの様にただfilterにmarked指定するだけでちゃんと動いててすごかった。

new Vue({
  el: '#editor',
  data: {
    input: '# hello'
  },
  filters: {
    marked: marked
  }
})

htmlもこれだけ

<div id="editor">
  <textarea v-model="input"></textarea>
  <div v-html="input | marked"></div>
</div>

marked.jsのmarked関数を適用してるだけなのでmarked.jsがすごいのかもだけど、感動したので手元でも動かしてみた。

環境

例によって、yoのwebappを使う。

bowerでvue.jsとmarked.jsをinstall。ついでに、textareaが縦に伸びていく様にjquery-autosizeもインストール。

$bower install vue marked jquery-autosize --save

markedは勝手にはindex.htmlに追記されないので、自分で追記してやる必要がある。

    <!-- manual import -->
    <script src="bower_components/marked/lib/marked.js"></script>

後は、autosizeを適用するコードをjsに追記。

 11 $(document).ready(function(){
 12   $('#autosizable').autosize();
 13 });

htmlもちょっと修正

   38       <div id="editor">
   39         <div v-html="input | marked"></div>
   40         <textarea v-model="input" id="autosizable" ></textarea>
   41       </div>
   42     </div>

cssも書いてやる。

   95 html, body, #editor {
   96   margin: 0;
   97   height: 100%;
   98   font-family: 'Helvetica Neue', Arial, sans-serif;
   99   color: #333;
  100 }
  101
  102 textarea, #editor div {
  103   display: inline-block;
  104   width: 49%;
  105   height: 600px;
  106   vertical-align: top;
  107   -webkit-box-sizing: border-box;
  108   -moz-box-sizing: border-box;
  109   box-sizing: border-box;
  110   padding: 0 20px;
  111 }
  112
  113 textarea {
  114   border: none;
  115   border-right: 1px solid #ccc;
  116   resize: none;
  117   outline: none;
  118   background-color: #f6f6f6;
  119   font-size: 14px;
  120   font-family: 'Monaco', courier, monospace;
  121   padding: 20px;
  122 }
  123
  124 code {
  125   color: #f66;
  126 }
  127

ついでに、highlight.jsをインストールしてcodeのsyntax-highlightもしてみた。

$ bower install highlightjs --save

jsにもちょこっと追記

  1 marked.setOptions({
  2   highlight: function (code) {
  3     return hljs.highlightAuto(code).value;
  4   }
  5 });

これだけで、以下の画像みたいに表示される。けっこうちゃんとしたmarkdown editorになっててすごい!!

f:id:south37:20141228033940p:plain

ちなみに、右側がテキストエリア、左側がmarked.jsでレンダリングした結果になっている。vue.js使ってるのでもちろんリアルタイムで表示がされる。

まとめ

余計なお世話かもだけど、はてなブログにもプレビュー同時に見ながら編集できるマークダウンエディタがついてると嬉しいなーとか思った。ただ、画面のサイズどうするのとかいろいろ問題あるし、実際つけると微妙なのかもなーとも思った。試してみないと分からなそう。

ただ、はてなブログのプレビュー見るときにサーバーへリクエスト送ってるっぽくてけっこう遅延があるので、クライアントサイドでのレンダリングは試す価値があると思う。

Masonry試してみた

とある事情でPinterest的UI作ってみたいなーと思ってて、Masonryを試してみた。

環境構築

とりあえず、試すための環境構築をしてみる。久しぶりに、yeomanを使う。

yeoman

久しぶりでversionが古い気がしたので、npm updateしてnpmのモジュールを一気にupdateした。この時点で、yo, bower, gruntのversionはそれぞれ

$ yo -v
1.2.0

$ bower -v
1.3.12

$ grunt -V
grunt-cli v0.1.13
grunt v0.4.5

みたいな感じになった。

yoで雛形を作る。

まず、webappという名前のgeneratorをinstallする。

npm install generator-webapp

これで、yo webappでwebapp generatorを使ってwebアプリケーションの雛形を作ることが出来る。どうでも良いかもだけど、npmコマンドでyo用のgeneratorをインストールするって忘れててちょっと戸惑ってしまった。

次に、yoでgeneratorを走らす。

$ yo webapp

     _-----_
    |       |    .--------------------------.
    |--(o)--|    |    Welcome to Yeoman,    |
   `---------´   |   ladies and gentlemen!  |
    ( _´U`_ )    '--------------------------'
    /___A___\
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

Out of the box I include HTML5 Boilerplate, jQuery, and a Gruntfile.js to build your app.
[?] What more would you like? Bootstrap, Sass, Modernizr
[?] Would you like to use libsass? Read up more at
https://github.com/andrew/node-sass#node-sass: Yes
   create Gruntfile.js
   create package.json
   create .gitignore
   create .gitattributes
   create .bowerrc
   create bower.json
   create .jshintrc
   create .editorconfig
   create app/styles/main.scss
   create app/favicon.ico
   create app/robots.txt
   create app/index.html
   create app/scripts/main.js
   invoke   mocha
.
.
.

この時、最初に

[?] What more would you like? (Press <space> to select)
❯⬢ Bootstrap
 ⬡ Sass
 ⬡ Modernizr

みたいな画面が出て、Bootstrap, Sass, Modernizrをそれぞれ使うかどうかを選べた。j, kで上下移動でspaceで切り替えが出来て、今回は3つともチェックをつけて実行した。

処理が終わるといろいろファイルが作られてた。

$ ls
Gruntfile.js app          bower.json   node_modules package.json test

ただ、bower.jsonに記載されてる類のjsファイルはまだインストールされてなかったので、bower installしてやる必要があった。

$ bower install
bower modernizr#~2.8.2          cached git://github.com/Modernizr/Modernizr.git#2.8.3
bower modernizr#~2.8.2        validate 2.8.3 against git://github.com/Modernizr/Modernizr.git#~2.8.2
bower bootstrap-sass-official#~3.2.0           cached git://github.com/twbs/bootstrap-sass.git#3.2.0+2
bower bootstrap-sass-official#~3.2.0         validate 3.2.0+2 against git://github.com/twbs/bootstrap-sass.git#~3.2.0
bower jquery#>= 1.9.0                          cached git://github.com/jquery/jquery.git#2.1.3
bower jquery#>= 1.9.0                        validate 2.1.3 against git://github.com/jquery/jquery.git#>= 1.9.0
bower bootstrap-sass-official#~3.2.0          install bootstrap-sass-official#3.2.0+2
bower modernizr#~2.8.2                        install modernizr#2.8.3
bower jquery#>= 1.9.0                         install jquery#2.1.3

bootstrap-sass-official#3.2.0+2 bower_components/bootstrap-sass-official
└── jquery#2.1.3

modernizr#2.8.3 bower_components/modernizr

jquery#2.1.3 bower_components/jquery

これで、bower_componentsというディレクトリが生成され、そこにbootstrap, jquery, modernizrなどのライブラリがインストールされた。

$ cat bower.json
{
  "name": "masonry-practice",
  "private": true,
  "dependencies": {
    "bootstrap-sass-official": "~3.2.0",
    "modernizr": "~2.8.2"
  }
}%

$ ls bower_components
bootstrap-sass-official jquery                  modernizr

良い感じ

一度雛形のWebAppを動かしてみる

とりあえず、今generatorで作ったアプリケーションを動かしてみる。grunt serveコマンドを叩くとlocalhost:9000をlistenするサーバーが起動され、さらに勝手にブラウザの画面がたちあがる。

$ grunt serve // 注: grunt serverではない。serverコマンドは非推奨らしい。
// サーバーが立ち上がり、ブラウザにhttp://localhost:9000/が表示される。

ここまではうまくいった。

masonryを試す

次に、masonryを試してみる。bowerでmasonryをインストールする。

bower install masonry --save

割といろいろ依存してるみたいで、けっこうbower_componentsの中身が増えた。

$ ls bower_components
bootstrap-sass-official eventEmitter            get-size                jquery                  matches-selector        outlayer
doc-ready               eventie                 get-style-property      masonry                 modernizr

あと、app/index.htmlにも勝手にscriptタグが追加されてた。

// app/index.htmlのscript読み込み部分
    <!-- build:js(.) scripts/vendor.js -->
    <!-- bower:js -->

    ~ いろいろ ~

    <script src="bower_components/get-style-property/get-style-property.js"></script>
    <script src="bower_components/get-size/get-size.js"></script>
    <script src="bower_components/eventie/eventie.js"></script>
    <script src="bower_components/doc-ready/doc-ready.js"></script>
    <script src="bower_components/eventEmitter/EventEmitter.js"></script>
    <script src="bower_components/matches-selector/matches-selector.js"></script>
    <script src="bower_components/outlayer/item.js"></script>
    <script src="bower_components/outlayer/outlayer.js"></script>
    <script src="bower_components/masonry/masonry.js"></script>
    <!-- endbower -->
    <!-- endbuild -->

ちょこちょこ修正

もともとあったdiv要素とか消してmasonryのGetting started見ながらdiv作ったり簡単なjsを書いたりした。

これがjs。ほぼドキュメントのまんま。

  1 var container = document.querySelector('#container');
  2
  3 imagesLoaded( container, function() {
  4   var msnry = new Masonry( container, {
  5     columnWidth:  340,
  6     itemSelector: '.item'
  7   });
  8 });

これがhtmlに追記した部分。

   36       <div id="container">
   37         <div class="item">
   38           <img src="http://corp.toei-anim.co.jp/press/watori01.jpg" width="320px">
   39           <p>ワールドトリガー</p>
   40         </div>
   41         <div class="item">
   42           <img src="http://worldtrigger.info/images/cover.png" width="320px">
   43           <p>ワールドトリガー</p>
   44         </div>
   45         <div class="item">
   46           <img src="http://www.tv-asahi.co.jp/worldtrigger/intro/img/wt.jpg" width="320px">
   47           <p>ワールドトリガー</p>
   48         </div>
   49         <div class="item">
   50           <img src="http://livedoor.blogimg.jp/zakuzaku911/imgs/f/3/f39495e6.jpg" width="320px">
   51           <p>ワールドトリガー</p>
   52         </div>
   53       </div>

これがcss。丸みつけたり線引いたりした。

   94 .item {
   95   margin: 5px;
   96   border: 1px solid #ccc;
   97   box-shadow: 0 2px 1px #eee;
   98   -webkit-border-radius: 4px;
   99 }

で、出来たのがこんな感じ。

f:id:south37:20141221021112p:plain

うん、なんか良さげな気がする!!!!

ここから発展させるとすると、XMLHTTPRequestで追加で画像取得してどんどん下に伸びていけばさらにそれっぽくなると思う。

まとめ

サクッとそれっぽいviewが作れて楽しかった。Masonry既にめちゃめちゃ有名だけどやっぱり良さげだった。

あと、ワールドトリガー週刊少年ジャンプで好評連載中でめちゃめちゃ面白いので読むと良いと思う。

RustにおけるOwnershipの仕組み

前回に引き続き、Mozillaイチオシの言語であるRustを触ってみる。今日はメモリ管理の仕組みとしての「Ownership」に着目する。

ちなみに、今日書く内容はRust Guideの17章、OwnershipのGuidePointerのGuideをつまみ食いしながら適当にまとめたものなので、原文読んでもらっても良い。

メモリ管理について

まずは背景として、メモリ管理の必要性について考えてみる。

一般に、計算機上で動くソフトウェアというのはデータをメモリ上に次々に確保して様々な計算等を行っていく訳だけど、メモリというのは有限の大きさしか持たない為にデータの追加ばかりしていく訳にも行かなくて、使わなくなった領域を次々に解放して再利用しなければならなくなる。

こういった事を考えると、メモリ解放の機構を言語に組み込む必要性があると分かる。

メモリに確保されるデータの種類

メモリに確保されるデータには、大別すると次の3種類がある。

  1. ソフトウェア実行中はずっと残る静的なデータ
  2. プロシージャ呼び出し時に確保され、プロシージャを抜けると解放されるスタック上のデータ
  3. ソフトウェア実行時に動的に確保されるデータ(ここで確保される領域をヒープメモリと呼ぶ)

メモリの解放という文脈でこれらのデータを考えると、1の静的なデータはずっと残るものなので解放されないし、2のスタック上のデータは勝手に解放されるので気にしなくて良いのだけど、3の動的に確保されるデータをどう扱うかが問題になってくる。

c言語では、mallocやfreeによってユーザーが責任を持ってメモリの確保と解放を行うことが求められたけど、メモリリークや不正なメモリへのアクセス等が起きやすく大きな問題を抱えていた。

一方、近年の多くの言語では Garbage Collection(GC) の機構を組み込みで持つことでユーザーをメモリ管理の複雑さ・煩雑さから解放したが、 GC 実行時にストップザワールドが起こる等のデメリットもあった。

そこで、Rustは「Ownership」という考え方を導入することで、メモリリークの危険性を抑えながらパフォーマンス上の問題を解決することを目指した。

Ownership

動的にメモリを確保する際、例えばc言語では

{
    int *x = malloc(sizeof(int));

    // we can now do stuff with our handle x
    *x = 5;

    free(x);
}

の様な書き方をする。同様の事が、Rustにおいては

{
    let x = box 5i;
}

という記述で表現できる。ポイントは、この記述できちんとメモリの確保と解放が表現出来ている事だ。

box というキーワードによって 5i という値がヒープ上に動的に確保され、その参照がxへbindされている。このxがownershipを持っていて、xがscopeから外れる(xを含むブロックを抜ける)時にメモリの解放が行われる。

この様に変数にownershipを持たせる事で、メモリの解放が必ず行われる事を保証できる様になる。

ownershipは移動させることもできて、例えばBox型の値(boxキーワードでヒープに確保した値への参照)を引数として関数を呼び出した場合には、ownershipはその関数内の変数numに移る。

fn main() {
    let x = box 5i;

    add_one(x);
}

fn add_one(mut num: Box<int>) {
    *num += 1;
}

ただし気をつけなければならないのは、ownershipを移すと、ownershipを失った変数からは元の値へアクセス出来なくなる事である。上記の例であれば、add_one(x)呼び出しの後にxを使おうとするとエラーが出る。

fn main() {
    let x = box 5i;

    add_one(x);

    println!("{}", x); // error!!!!!
}

fn add_one(mut num: Box<int>) {
    *num += 1;
}

この問題を避けるために、例えば関数から返り値を使うといった方法が考えられる。

fn main() {
    let x = box 5i;

    let y = add_one(x);

    println!("{}", y);
}

fn add_one(num: Box<int>) -> int {
    *num + 1;
}
//注: これはあくまで例で、あまり良い方法では無い。

ただし、今回の例ではnumの所有権は一時的なものであれば良く、返り値という形ですぐにまたmainのyに戻されている。こういった一時的な所有権というシチュエーションは良くあるものであり、上記の例よりもBorrowingという仕組みを使う方が推奨されている。

Borrowing

Borrowingとは、ownershipは移さずに値への参照を可能にする機構である。&キーワードで値への参照を作ると、それは値をborrowingする為のpointerとなる。例えば、ownershipを移すことで実現していた上記の例は、以下のコードに書き直せる。

fn main() {
    let x = box 5i;

    println!("{}", add_one(&*x));
}

fn add_one(num: &int) -> int {
    *num + 1
}

呼び出し方がちょっとややこしくなってるけど、 *x で5iという値を意味していて、さらにその値をborrowingするために&キーワードで参照を作っている。

xのownershipは移動しない為、何度でもxの値を使用できる。

fn main() {
    let x = box 5i;

    println!("{}", add_one(&*x));
    println!("{}", add_one(&*x)); // 何度でもxを使える!!
    println!("{}", add_one(&*x)); // 何度でもxを使える!!
}

良い感じ。

mutableなborrowing

mutableなborrowingというのも一応出来て、&mutキーワードを使ってmutableな参照を作れば良い。ただし、もともとの値がmutableでないといけない。

fn main() {
    let mut x = box 5i;

    add_one(&mut *x);

    println!("{}", x); // xの値はborrowingされただけで移動してないから使える!!
}

fn add_one(num: &mut int) {
    *num += 1
}

mutや&mutや*の様なキーワードが入り乱れる事になるのでちょっとつらい感じになる。

Owner、およびBorrowerの権限について

Rustにおいては、ownerやborowerにはそれぞれ独自の権限がある。ownerは、次の3つの権限を持つ。

owner の権限

  1. リソースがいつ解放されるかを制御出来る。
  2. リソースを immutable な形で多くの borrower に貸し与えることが出来る。
  3. リソースを mutable な形で1つの borrower に貸し与えることが出来る。

ただし、これは次の2つの制約の存在も意味する。

owner の制約

  1. 既に誰かに貸し与えたリソースを変更したり、mutable な形で別の誰かに貸し与えたりする事は出来ない。
  2. 既に誰かに mutable な形で貸し与えたリソースは、アクセスすることが出来ない。

基本的に、変更によって変な競合が起きる可能性のある事は禁止されてるっぽい。

また、borrowerには次の権限がある。

  1. borrowがimmutableなら、リソースの読み取りが出来る。
  2. borrowがmutableなら、リソースの読み書きが出来る。
  3. 他の誰かにリソースを貸し与える事が出来る。

ただし、borrowerにも重要な制約があり、

「他の誰かにリソースを貸し与えたら、自分のborrow backの前に貸し与えた分を borrow backしてもらわなければならない」

らしい。この制約が守られないと、例えばownerのスコープが終了してメモリが解放され、不正な値となった領域にborrowerがアクセスする、といった危険な事が起きてしまう。そういった意味で、大事な制約となっている。

所感

Ownershipについて調べてみて、Cなんかと比べて一番便利なのはヒープ上に確保した値をプロシージャで安心して返せることなのかもなーと思った(返り値のownerが明確であれば、メモリの解放を保証出来るから)。

正直、Cでバリバリコーディング出来るとかでは全然無いんだけど、解放が保証されるか分からないポインタを使うとか想像するだけで怖すぎるなーとは思う。

で、C++におけるメモリ管理のお作法がちょっと気になったのでGoogle C++スタイルガイド 日本語訳とかいうのを見てみたら、現代的なC++コーディングではスマートポインタという解放が保証された機構を使うものらしい事を知った。

基本的には所有権の移動が無い scoped_ptr を使って、どうしても共有の必要性が出てきたら(参照カウントを組み込んだ) shared_ptr を使うと。なるほど。

割とRustと似たような事をやるっぽい。

Rustに入門してみる

今日は、Rustに入門してみる。

Rustは、Mozillaの開発したプログラミング言語である。公式サイトでは"high-level, bare-metal programming"を謳っており、高い抽象度を保ちながら低いレイヤーのコントロール(具体的にはユーザーによるメモリ管理等)が可能らしい。

近年出てきた言語の内、高い抽象度とハイパフォーマンスの両立を強みにしていた言語としてはGo言語が真っ先に思い浮かぶ。ただ、GoにおいてはGCを採用していた事を考えると、手動でメモリ管理が可能なRustはさらに低レイヤーを担当する事を目指してるようだ。

MozillaとしてはCやC++に置き換わりたい様だし、そういった立ち位置を目指す言語に興味が湧いたのでちょっと触ってみた。

とりあえず、公式サイトのGuideの手順を順番に試してみる。

1. RustをMacにインストール

公式サイトに従って、curlでschellscriptダウンロードして実行する。

curl -s https://static.rust-lang.org/rustup.sh | sudo sh

rustとcargoのinstallerのダウンロードが始まって、だいたい5~10分程でインストールが完了する。

ちなみに、installされたRustのversionはrustc --versionで確認出来て、14/12/06時点では以下だった。

rustc 0.13.0-nightly (6f4c11be3 2014-12-05 20:23:10 +0000)

まだ1.0前のアルファ版なのでアップデートはあるらしく、定期的にcurl -s https://static.rust-lang.org/rustup.sh | sudo shでアップデートしてねって感じらしい。

2. Hello worldしてみる。

とりあえずHello world。main.rsファイルにmain関数を定義。

// main.rs
fn main() {
    println!("Hello, world!");
}

rustcコマンドでコンパイル。そして実行

$ ls
main.rs
$ rustc main.rs
$ ls
main    main.rs
$ ./main
Hello, world!

ちゃんとHello worldが出力された。やったぜ!!

main.rsのコードについて

割と見たまんまの解釈で良くて、fnキーワードと波括弧({})で囲んだブロックでmain関数を定義してる。main関数は特別な関数で、生成したバイナリの実行時にはmain関数の中身が実行される(この辺はCとかと一緒)。

println!ってのが実はただの関数じゃなくて、Macroらしい。ビックリマーク(!)ついてればMacroらしいけど、まだ序盤だからって事で理由は教えてくれなかった。そもそもRustにおけるMacroってのが何を指してるのかはまだ分からない。

後、indentはスペース4つって指定されてた。

3. Cargoを使う。

CargoというのはRustのプロジェクトを管理する為のツールで、具体的にはRustのコードのビルド、依存ライブラリのダウンロード、依存ライブラリのビルドの3つの仕事を行うらしい。そこそこの規模のプログラムを書くならCargoを使うべきとの事。

まあ今は練習なので、先ほど書いたmain.rsをCargoプロジェクトにしてみる。まずは、srcディレクトリを作ってそこにmain.rsを移動する。cargoでは、srcディレクトリにコードを置くのが規約らしい。

$ mkdir src
$ mv main.rs src
$ rm main

次に、configuration fileであるCargo.tomlを生成。TOMLって見た事なかったんだけど、INIの進化版みたいな感じらしい。

// Cargo.toml
[package]

name = "hello_world"
version = "0.0.1"
authors = [ "south37 <sout37777@gmail.com>" ]

[[bin]]

name = "hello_world"

Cargo.tomlにはプロジェクト名、version, author名なんかを書く。そして、buildコマンドでビルド。

$ cargo build
Compiling hello_world v0.0.1 (file:///Users/<ユーザー名>/Documents/programs/rust/hello_world)

$ ./target/hello_world
Hello, world!

これで、targeフォルダ以下に実行ファイル(hello_world)が生成される。良い感じ!!

ちなみに、cargo build実行後にはCargo.lockファイルが生成される。中身は

[root]
name = "hello_world"
version = "0.0.1"

で、あまり大した内容になってないけど、依存ライブラリ等があればここに書き込まれていくらしい。

lockって拡張子がGemfile.lockを彷彿とさせるんだけど、どちらも元ネタは同じだったりするのだろうか?gemはまさに依存関係管理ツールだし。

4. 変数へのbinding

Rustでは、letキーワードを使って変数への値のbindingを行う。Rustは静的型付け言語であり、型付けを行わなければならない。

let x: int = 5;

型の表記が無いとエラーが出る。

let x = 5;
$ rustc practice.rs
practice.rs:2:9: 2:14 error: cannot determine a type for this local variable: cannot determine the type of this integer; add a suffix to specify the type explicitly [E0102]
practice.rs:2     let x = 5;
                      ^~~~~
error: aborting due to previous error

ただ、Rustは型推論をサポートしている為、型が自明であれば問題は無い。例えば、上記の例ではiをつけて数値がintegerである事を示してあれば大丈夫。

let x = 5i; // 5の後ろのiがintegerの値であることを示している。

デフォルトでは変数はimmutableであり、書き換えることは出来ない。

let x = 5i;
x = 10i;
$ rustc practice.rs
practice.rs:3:5: 3:12 error: re-assignment of immutable variable `x`
practice.rs:3     x = 10i;
                  ^~~~~~~

mutableな変数を用意したければ、mutキーワードを使う。

let mut x = 5i;
x = 10i;

immutableがデフォルトってのは個人的にはとても好ましい。公式サイトによれば、安全性を考慮した結果らしい。

5. if構文

Rustのifを使った条件分岐は見たまんま。自然に理解できる。

let x = 5i;

if x == 5i {
    println!("x is five!");
} else {
    println!("x is not five :(");
}

ただ、Rustにおいては構文のほとんどが式(expression)であり、値を返すため、if式も下みたいな使い方ができる。

let x = 5i;

let y = if x == 5i { 10i } else { 15i };

良い感じ。

Rustにおける構文の内、値を返さない文(statement)は2種類しか無いらしい。一つは変数のbindingで、下記の表記は出来ない。

let x = (let y = 5i); // expected identifier, found keyword `let`

もう一つはexpression statementと呼ばれる構文で、セミコロン(;)をつけることでexpressionがstatementに変換される。(逆に言えば、デフォルトではrustの構文は全てがexpression)。

例えば、if式の中でセミコロン(;)を使うと値が返されない(より正しく言うとunitと呼ばれる特別な値が返される)。その為、以下のセミコロンを用いたif構文の結果を変数にbindingしようとするとエラーが出る。

let x = 5i;

let y: int = if x == 5i { 10i; } else { 15i; };
$ rustc practice.rs
practice.rs:4:18: 4:51 error: mismatched types: expected `int`, found `()` (expected int, found ())
practice.rs:4     let y: int = if x == 5i { 10i; } else { 15i; };

終わりが見えてこない

まだ構文の本当に基礎っぽいとこしか触れてないけど、終わりが見えてこないので今日はここまで...

本当はRustのメモリ管理に興味があって、ownershipとかborrowingとかみたいな現代的なメモリ管理について学べそうで興味を持ったんだけど、このペースだとたどり着けないのでまた今度にする。

ownershipは、まだあんま分かってないけどスコープを抜けるときに確保したメモリが解放される仕組みっぽい。それだけだとスタックと変わら無いんじゃないかと思うけど、別のスコープにownershipを移す事ができたり(その場合は元のスコープの所有では無くなる)、別のスコープに所有権を貸し与えたり出来るので、常に1つのスコープに所有されつつ、そのスコープが終了すればメモリの解放が行われる事を保証出来るらしい。

まだ自分でコード書いて試してみてないからアレだけど、説明だけ読んだ感じだとすごく良い仕組みのように感じる。

参考

Ownershipとかについては、このページで紹介されてて興味を持った。

こちらは所有権の移動(move)の説明。

おめでたい話

今日は、プライベートなお話を書く。とてもおめでたいお話。

背景: VOYAGE GROUPでのインターンとリレーブログ

実はこのブログは焼き肉ブログというはてなグループに所属していて、グループ内ではメンバー同士で1日交代でブログを書いていってる。メンバーは皆去年の夏に同じインターン(VOYAGE GROUPのTreasure)に参加した仲間で、ブログを書く習慣をつけたりお互いに知見を交換しあったりする為にリレーブログを始めた。何人かは地方にいる為にそんなに頻繁には会えないんだけど、東京に来る機会があった時は皆で焼き肉を食べに行ったりして、何だかんだで1年以上の付き合いになってた。

そんな中、メンバーの一人であるdorivenが結婚する事になり、まさに今日、都合がついた僕, ism1000ch, moguranosenshiの3人で結婚式に出席してきた。

やっぱり色々思うところはあったので、簡単にだけどまとめてみたいと思う。

続きを読む

7つの言語 7つの世界を読んだ

「7つの言語 7つの世界」という本を図書館から借りてきて読んだ。この本では、異なるパラダイムをサポートする7つの言語について、シンプルながら本質を捉えた説明がなされていた。もともと色んな考え方を知るのは好きな方なので、めちゃめちゃ楽しんで読めた。

取り上げられていた7つの言語

筆者が選んだのは、Ruby, Io, Prolog, Scala, Erlang, Clojure, Haskellの7つの言語だった。筆者としては、オブジェクト指向が圧倒的に広まってる中、関数型の考え方や並行処理に対する優れたアプローチを紹介したいという意図があったようだ。

7つの言語のうちRuby, Scala, Haskellについてはそこそこ触った事はあったんだけど、他は全然知らない言語だった。特にIoについては名前すら知らなかったので、この本のお陰で出会えて良かったと思う。

ClojureLisp族だし置いとくとして、Io, Prolog, Erlangみたいな全然触れた事が無かった言語についてまとめてみる。

Io

Ioはプロトタイプベースのオブジェクト指向言語で、そういった点ではJavaScriptの仲間になる。プロトタイプベースのアプローチでは、オブジェクトの振る舞いをクラスによって表現するのでは無く、プロトタイプとなるオブジェクトを指定することで表現する。JavaScriptのプロトタイプは、関数をコンストラクタにして、コンストラクタのprototypeプロパティにオブジェクトを指定して、そのプロトタイプを持つオブジェクトをnew演算子で生成して...みたいにめちゃめちゃ分かりにくい設計になってるんだけど、Ioはかなりシンプルな文法でプロトタイプベースのオブジェクト生成が行えるので、分かりやすさという意味でめちゃめちゃ魅力的だった。

Ioでは、オブジェクトを生成する際は基本的には既存のオブジェクトをCloneすれば良い。

Ferrari := Car clone
// CarオブジェクトをプロトタイプとしたFerrariオブジェクトを生成

cloneがCarオブジェクトに対するメッセージになってるのもポイントで、Ioでは特殊な構文というものを用意せず、徹頭徹尾メッセージングによってプログラムを構築する事になる。この辺は以下の記事がよくまとまってると思う。

るびま: Rubyist のための他言語探訪 【第 3 回】 Io

一貫性がある設計というのは自分としてはものすごく好ましい事で、理解しやすいし興味深かった。

並行処理を言語の基盤レベルでサポートしてるのも特徴的で、Ioではコルーチン、アクター、フューチャといった機能を簡単に使うことが出来る。コルーチンはメソッドの処理中にいったん処理を抜けて他のメソッドに処理を譲る仕組みで、Ioにおいてはメッセージの非同期呼び出しとyieldメッセージでコルーチンを実現することが出来る。

アクターは分散処理を実行する単位となる存在で、Ioにおいては独自のThreadを持つオブジェクトとして表現される。アクターの生成はものすごく簡単で、オブジェクトに非同期メッセージを送るだけで良い。

  1 obj1 := Object clone
  2 obj1 name := "obj1"
  3 obj1 test := method(
  4   for(n, 1, 3,
  5     n    print
  6     ": " print
  7     name println
  8     yield
  9   )
 10 )
 11
 12 obj2 := obj1 clone
 13 obj2 name := "obj2"
 14
 15 obj2 @@test; obj1 @@test
 16 Coroutine currentCoroutine pause

上記の例では、obj1とobj2に@@testという非同期メッセージを送って、アクターとして動作させている(メッセージの先頭に@@をつけると非同期呼び出しになる)。

testメソッドの中にyieldメッセージが含まれているため、この時点で処理を別のアクターに移すことになる。これはまさにコルーチンとしての振る舞いである。

上記のコードの実行結果は、以下のようになる。

$ io actor.io
1: obj1
1: obj2
2: obj1
2: obj2
3: obj1
3: obj2
Scheduler: nothing left to resume so we are exiting

別々に@@testメッセージを呼び出したobj1とobj2が、yieldで処理を譲り合うことで順番に出力を行っている事が分かる。

Ioにおいてはフューチャと呼ばれる機能も用意されていて、これは非同期呼び出しの「結果」を即座にオブジェクトとして利用出来る仕組みとなっている。メッセージ呼び出しに@をつけると結果を返す事が出来て、この時帰ってくるのがフューチャである。

  1 futureResult := URL with("http://google.com/") @fetch
  2
  3 writeln("Do something immediately while fetch goes on in background...")
  4 writeln("fetched ", futureResult size, " bytes")
  5 writeln("end")

上記のコードの実行結果は、

$ io future.io
Do something immediately while fetch goes on in background...
fetched 9367 bytes
end

となる。

ポイントは"Do something immediately while fetch goes on in background..."という出力が即座に行われる点で、これは1行目の@fetchの非同期呼び出しが別Threadで処理されて、現在のThreadでは即座に次の処理が行われる為である。4行目でfutureResultを使おうとしている為、その時点で@fetchの処理が終わってなかった時に初めて処理がブロックされる。特殊な事をしなくても、非同期に呼び出しておいてその結果を必要になったタイミングで使えるので使い勝手が良さそうである。

いったんまとめ

Ioだけで結構長くなったのでいったんまとめる。Ioでは、メッセージングとその非同期呼び出しというシンプルな構造で、コルーチン、アクター、フューチャといった便利な機能を実現している。並行処理についてはこれまであんまり意識した事が無かったけど、イメージをつかめた気がする。

どうでも良い話だけど、coroutineを知った事でgoのgoroutineという名前の意味もやっと分かった気がする。

goroutineはgo文で関数を実行する事で非同期に起動される手続きで、channelを使って値をやり取りできる。channelは値の受信時に処理をブロックする。その為、channelを使うことでgoroutine同士の同期をとる事が出来て、coroutineとしての機能を実現する事も出来る。そこから、coroutineっぽい名前(goroutine)がつけられたんだと思う。

ちょっと調べたら

"Users of C#, Lua, Python, and others might notice the resemblance between Go's generators/iterators and coroutines. Obviously, the name "goroutine" stems from this similarity"

っていう記述を見つけたから間違いなさそう。

Go Language Patterns: Coroutines

Prolog, Erlangについて

Prologは論理制約プログラミグが出来る言語で、制約の元で非決定性計算を行うっぽい。ErlangPrologを出発点としてるからシンタックスは似てるけど、一番の強みはそこじゃなくて「平行性と耐障害性」らしい。Threadでもプロセスでも無い「軽量プロセス」という単位で大量の平行処理を行わせる事ができて、メッセージングによって協調的な動作をさせたり死活監視や再起動を簡単に行えたりする。これがものすごく良いらしくて、熱く語ってるブログも見つけた。

なぜErlang/OTPなのか

実は元々Erlangに一番興味があって「7つの言語 7つの世界」という本を借りたので、良い勉強になった気がする。

これらの言語については、また今度詳しくまとめるかもしれない。

7つの言語 7つの世界

7つの言語 7つの世界

ノーマン先生の「誰のためのデザイン?」を読んだ。

ノーマン先生の「誰のためのデザイン?」を読んだ。

この本では、身の回りの物の「使いにくさ」が人の認知構造も踏まえながら考察されている。最後には、その成果が「デザインの7原則」としてまとめられている。豊富な例のおかげで読み易くかつ理解し易い作りになっているが、決して平易なだけでは無く学びの多い内容となっている。

古い本ではあるが、今でも色あせる事の無い良書だと思う。

デザインの7原則

  1. 外界にある知識 と頭の中にある知識の両者を利用する
  2. 作業の構造を 単純化 する
  3. 対象を目に見えるようにして、実行のへだたりと評価のへだたりに橋をかける( 可視性 )
  4. 対応づけ を正しくする
  5. 自然の制約や人工的な制約などの 制約 の力を活用する
  6. エラー に備えたデザインをする
  7. 以上のすべてがうまくいかないときには 標準化 をする

以上7つがデザインの7原則としてまとめられていた。それぞれの原則の意味については、以下のブログで分かり易く説明がなされている。

人間中心のデザインの原則 -『誰のためのデザイン?』を読んで-

1の外界にある知識の利用、3の可視性、4の対応付け、5の制約の利用については、若干意味の被りがある(と僕には思える)ものの、これらの原則は良いデザインを提供する為の優れた指針となっている。

原則の意味の被りについて

3の 可視性 はものすごく広い概念で、本書を通じて重要性を強調されているものでもある。何故ならば、システムの 目に見える 部分が「システムイメージ」であり、そこからユーザーは独自のメンタルモデル(ユーザーのもつモデルと呼ばれる)を作り上げるからである。使い易さの為には適切なメンタルモデルの構築が重要であり、その為には一貫した振る舞いや状態を示すシステムイメージが必要となる。

本書に記載されている原則としての可視性について言及しておくと、行為側での可視性は、「何が実行可能であり、どうやったら良いかが分かる事」と説明されている。これはまた、「意図とその時点でユーザが実行出来る行為」の自然な対応付けがつく事であるとも言える。この実現の為に、外界にある知識を利用したり制約を利用したりする事が出来る。対象の形状や特性が持つアフォーダンスも重要なヒントとなる。

評価側での可視性は「自分の行った行為がどんな効果を及ぼしたのかが分かる事」と説明されている。これはまた、「行為とその効果」の自然な対応付けがつく事であるとも言える。

以上を踏まえると、「目に見える制約やヒントによって可能かつ適切な行動が分かり、さらに適切な結果も目に見える事で良い対応関係を作れるようにする」といった文に1, 3, 4, 5の原則はまとめられるのでは無いだろうか。

そこに、単純化、エラーへの備え、標準化といった原則が追加されているのだと思う。

本書を読んでの所感

「誰のためのデザイン?」を読んだ時、「使いにくさ」や「不自然さ」の要因がきちんと言語化されていたのが僕にとっては衝撃的だった。これまで、何かを使ってみた時に「使いにくい」と判断する事はよくあったが、何故使いにくいのかまではきちんと言語化出来てなかった。

最初は使いにくいエディタ

パッと思いつく例としては、例えば「vim」や「emacs」の様なエディタがある。これらは使いこなせればものすごく生産性が上がるものの、最初はものすごく使いにくい作りとなっている。この使いにくさは、「外界にある知識」をほとんど利用出来ていない事に起因している。キーバインドを覚えて「頭の中の知識」として蓄えなければほとんど操作が行えず、可能な行動を絞り込む「制限」も無い(しいて言えば何かキーを入力すべきというくらいである)。これでは、最初は使いにくくて当然である。

そういった意味では、GUIアプリケーションにおいて「ボタン」や「タブ」(どちらもクリックする事をアフォードしている)といった部品が存在する事、「×ボタンをクリックする事でアプリケーションを終了する」といった標準化された振る舞いがある事は、「使い易さ」を高める大きな要因となっている。

では、エディタを使いこなした時の生産性の向上は何に由来するのだろうか? 本書においては、「頭の中に蓄えられた知識を利用した行動」の利点として、外界の知識を利用する場合に比べてはるかに高速に行う事が出来るという傾向の存在が指摘されている。これがエディタを使いこなした時の生産性の向上に繋がっているのでは無いかと考えられる。

他にも多くの例が考えられると思う。

今週の読書記録

達人プログラマーは今最終章(8章)なのでもうすぐ読み終わりそう。Land of Lispは手を動かす部分(ゲーム作る部分)をすっとばして一通り読んだ。ちなみに、これは半分以上すっとばした事になる。パターン認識と機会学習はチマチマ読んでてもうすぐ2章終わるとこ。t分布が出てきてめちゃめちゃ懐かしかった。