Let's write β

プログラミング中にできたことか、思ったこととか

新しい言語を学ぶときにチェックすること

ある言語からある言語へ移行するときや、新しい言語を学ぶときに付きまとうのが
その言語独特の文化も問題です。自分の今つかっている言語とはまったく違うメンタルモデルをもっている言語を勉強するときに、闇雲に突っ込んでいっても五里霧中になってしまいます。
そこである言語をやるときにある程度の環境を把握するために、自分が何をやっていたかを自分のメモのためにまとめておきたいと思います。

  • プリミティブとそうでない型が存在するのかしないのか?

プリミティブとそうでない何かしらのインスタンス的なものという区別が
その言語にあるのかどうかというをチェックしておかないと思わぬところで抽象化に手間取ったりします。そこでまずはその確認をします。

  • ポインターのような型があるのか?

C言語にはポインター型がありますが、ポインターを抽象化してしまって隠してしまっている言語はかなり多いです。そこでその言語にはポインター型があるのかというのを確認します。どちらが良いというのではなく、遠隔から変化が及ぼされてしまうのかというのを知りたいので。

  • 参照渡しか、値渡しか

前の2つの確認とも重なるのですが、引数に指定したものが参照渡しされているのか
値わたしされているのかというのを確認します。またプリミティブとそうでないものの区別が存在する場合はそれぞれがどちらなのか確認しておきます。

  • メモリの自動管理はあるか?その効率はどうか?

昨今ではGCを持った言語がかなり多いです。そこで、その言語にはGCがあるのか?それともなんらかの形で開放してやらなければならないのか、ということを確認します。またGCを有効にしたり無効にしたりすることができる環境では、GCの効率がどの程度なのかということを確認しておきます。

  • 関数はファーストクラスか?

関数をなんらかの形で関数から返すことができる言語も昨今では増えてきています。
関数が関数ポインターを利用すると参照できるCのような言語もありますので、そこらへんを踏まえて抽象化の方法を練ります。

  • 変数のスコープはどうなのか?

変数がどのようなスコープをもっているのかを確認しておきます、ダイナミックスコープなのかレキシカルスコープなのか、コード中で一時的なスコープを作成する穂方があるかどうか(let)、変数の宣言の方法によってスコープがどのように変化するのか(static, defvar..etc)

  • クロージャは提供されているかどうか?

これは関数がファーストクラスかどうかというのと関連してきますが、クロージャを作成する方法を言語がもっているのか?持っていないとしたらそれを模倣する方法はあるのか?を確認します。

  • 関数から値はいくつ返せるか?

関数から値を返したいときに、多値を返せる言語もありますし、そうでなく引数にポインターを渡してもらって代入することで返す言語もあります。また関数から値を明示的に返さなければいけないのか、最後に評価された式の値が自動的に返される言語もあります。

  • 型付けはどうか?動的型か?静的型か?強いか?弱いか?

個人的には動的型の言語のほうがすきですが、静的型にもそれなりに利点はあります。そこで、言語の型付けの方法がどうなっているのか?というのを確認しておきます。

  • どのような条件分岐構文をもっているのか

たいていの言語はif-then-else構造とswitch-case構造は持っていると思います。
そこでその記法を確認するとともにcondやパターンマッチのような抽象的な
条件分岐が存在するのかどうか確認します。またunlessやwhenのような構造が
提供されているのかどうかも確認します。

  • どのようなループ構文をもっているのか

for文のような基本的な構文を提供している言語も多いですがここら辺は言語によってまちまちで配列に対してmap関数を適用したりすることで
ループを行ったり、独自の効率的な構文を提供している(loop-recur)言語もあります。また再帰を使ってループを表現するのが一般的という言語もあります。

  • そのほかの特徴的な機能はどのようなものがあるのか?

Schemeのcall/ccやHaskellの遅延評価のようにほかの言語にはあまりない特徴的な機能にはどのようなものがあるのか確認します。適宜チュートリアルや解説ページ書籍をよみ、どのような時に利用するのが適切なのかを確認しておきます

  • nilやundefinedなどの特殊な状態の確認

nilやundefinedの問題は常に付きまとってきます。存在しない変数を問い合わせたときにエラーが発生するのか、はたまたundefinedが帰ってきて確認しない限り何もいってこないのか(javascript..etc)などを確認します。nilやundefinedに対して何かを呼び出したときにエラーになるのか((car nil)やらnil.each, x = undefined)やらも確認します。

  • nilとBool型の関係

nilが真偽値としてどのように扱われるのか、nilとは別にfalseやtrueのような型が存在するのかどうかはたまたtのような特殊な位置の真値があるのか、nilがどのような定義づけをされているのか(型の空集合云々)

  • 名前空間やパッケージングがどのように定義されているか?

標準の名前空間やパッケージングの方法がなく混乱している言語もあります(javascript..)はたまたそもそも名前空間を提供する方法が存在しないような言語もあります。存在する言語の場合はどのように定義し、どのよう中のものをエクスポート、インポートするのかを確認しておきます。

  • 関数と変数の名前空間の区分を確認します。

LispではLisp-1とLisp-2という用語(?)があり、関数と変数の名前空間が同じか、そうでないのか?という区分があります、これによって関数によって変数へのスコープが隠蔽されてしまうような事態がありうるのか?心配しなくていいのか?
仮に別の名前空間だとしたら、参照する方法にはどのような方法があるのか?ということを確認します。

  • 関数やメソッドの多重ディスパッチはできるのか?できるとしたらどのような条件でできるのか?

同名の関数を異なる引数で定義して多重ディスパッチができる言語は増えてきていますが、言語によって可能なことの範囲はことなります。引数の個数は固定で型が異なることでディスパッチがされるような言語もありますし、型も個数もばらばらでかまわないような奔放な言語もあります。また提供されているならば、引数の型の階層によってどのような順序でメソッドが探索されていくのかというのを確認します。明示的によばなくても勝手に呼ばれるような言語もあります。またCLOSのようにcall-next-methodのような特徴的な機能もあります。

  • 特殊なディスパッチがあるか?

CLOS特有の話題かもしれませんがbefore,after,aroundのような特殊なメソッド定義があり、既存のメソッドの実行にフックできる機能を提供している言語やライブラリがあります。またアスペクト指向のようなオブジェクト指向とは直行するような方法で特殊なフックを提供するライブラリもありますので、そこらへんの情報を収集します。

  • クラスの継承はどのように可能か?

クラスの継承をどのように行えるのか?ということを確認します。継承やら機能の注入はさまざまな方法があるので(Interface,Abstract,Mixin,Traits,多重継承,単一継承)その方法と環境を確認しておきます。

  • 継承されたクラスでのメソッドの呼び出し順序

単純に単一継承のみを提供している言語は簡単かもしれませんが、多重継承を提供している言語では菱形継承問題に対応するために言語使用としてクラスの型階層の探索の順序を制定している言語もあります。そのため仕様を確認して適切なメソッドが呼ばれるようにします。

  • 型階層の探索の方法は提供されているのか?

スーパークラスの一覧を取得したり、サブクラスの一覧を取得したり、ある型がある型のサブクラスやらスーパーくらすであるのかどうかを確認したり、どのようなメソッドやメッセージにそのクラスが対応かのうであるのかを確認する方法があるのか?を確認しておきます。

  • メタレベルの型が存在するか?

オブジェクト指向なかにはMetaClassを提供しているものもあります。そのような機能が提供されているのか?提供されているとしたら、MetaClassを利用してどのようなことが可能なのか使用を確認します。

  • 同図像性はあるのか?

ちゃんとしたマクロがかけるのかということとも関連してきますがコード中でコードをデータとして扱えるのかどうかということを確認します。
またここで得に注視したいのがコード中でコードをデータとしてあつかうための型が特殊化されていないかどうかを確認します。この型がその言語で普通に扱う型でない場合結局柔軟に操作するのは困難になってしまうことが多いです。(便利なオペレータが提供されていなかったりします)

  • コード中でコードをデータとして扱えるとしたら、そのデータの作成方法は直感的か?

データとして扱えるとしても、作成されることになるであろうコードを考えるのに、手間がかかったり、構文によって異なるデータ構造を用いなければならなければ結局は複雑なマクロはかけません。そのためそこをしっかりと確認しておきます。

名前空間はどのような機能を提供しているか確認します。ただの境界なのか?それとも名前空間にたいして働きかけることによって内部の変数名の一覧をとれたりするのかどうか?を確認します。

  • 変数名はどのようにあつかえるのか?

マクロをかける言語でないとこの機能は提供されていいないことが多いですが、変数名というものをコード中でどのように扱えるか確認します。言語中で変数名を生成できるのか?変数名をうけとり、そこに代入するといったことを行えるのか?などを確認します。
-