vital.vim icon indicating copy to clipboard operation
vital.vim copied to clipboard

refinements in import() and load()

Open ujihisa opened this issue 11 years ago • 9 comments

vital 本体の API のドキュメントを書こうと思ったけど、import() とか load() の仕様の議論がまだ収束してないことに気付くなど。 えーと、load の as 機能について。現状の load(['Foo']) がわかりづらいとの話だった気がする。 個人的には短く書けて気に入っているのだけど。 仕様整理。

  1. load するとモジュールが V に置かれてそこからアクセスできるようになる。

    V.load('Foo.Bar.Buz')
    -> V.Foo.Bar.Buz
    
  2. 複数同時にロード可能

    V.load('Foo.Bar.Buz', 'Hoge', 'Huga')
    -> V.Foo.Bar.Buz
    -> V.Hoge
    -> V.Huga
    
  3. 文字列ではなくリストを渡すと、as として処理される

    V.load(['Foo.Bar.Buz', 'FBB'])
    -> V.FBB
    
  4. as を空文字列にすればトップレベルに直接ロード可能

    V.load(['Foo.Bar.Buz', ''])
    -> V (Foo.Bar.Buz の関数が直接使える)
    
  5. 空文字列の場合は省略可能

    V.load(['Foo.Bar.Buz'])
    -> V (Foo.Bar.Buz の関数が直接使える)
    

ふと思ったのだけど、リストじゃなくて辞書を渡す仕様にして 5. の省略可能をなくすのはどうか。 as としては辞書の方が自然な気もするし。

V.load({'Foo.Bar.Buz': 'FBB'})
-> V.FBB

必然的に複数同時に処理可能。 ここらで人の意見が欲しい。

lingrでのthincaさんの提案を引用しつつ整形。

まず一般的な指針として、vitalのimport/loadは記述の短さよりも記述のわかりやすさを優先すべきと思っています。「このファイルはこれとこれをこのように使う」というのはexplicitである方が読みやすいです。複数の箇所に散らばるものは常に記述が短くあるべきですが、ファイルの先頭で宣言するものの場合、記述の短さはあまり重要でないと思います。

というわけで、thincaさんの「5. の省略可能をなくすのはどうか」は大賛成です。が、それだけでなく、「2. 複数同時にロード可能」をなくすべき、あるいは別名の関数にするべきだと思います。

というわけでこんな新仕様はどうでしょう。

  1. load するとモジュールが V に置かれてそこからアクセスできるようになる。これ以外にload()の使い道はない。

    V.load('Foo.Bar.Buz')
    -> V.Foo.Bar.Buz
    
  2. load_as すると第二引数の名前で参照可能。これ以外にload_as()の使い道はない。

    V.load_as('Foo.Bar.Buz', 'FBB')
    -> V.FBB
    
  3. import_extending すると第1引数の変数を破壊的に書き換え、その中に読み込む関数が注入される。したがって以下のようにすることで、元の提案の4.が実現できる。なお、第二匹数が辞書でなかった場合、エラーとなる。また関数名がかぶった場合、元々存在する関数が上書きされ、あとで読み込ませたものが優先される。なお、import_extendingの第二引数は省略できない、つまりこれ以外にimport_extendingの使い道はない。なお、この関数の名前が長いのは、なるべくimportで別の変数を作ってほしいため。

    V.import_extending(V, 'Foo.Bar.Buz')
    -> V (Foo.Bar.Buz の関数が直接使える)
    
    let B = V.import('Foo.Bar.Baaaa')
    V.import_extending(B, 'Foo.Bar.Booo')
    -> B (Foo.Bar.Booo の関数も直接使える)
    
  4. (導入するとすれば) load_eachで複数同時にロード可能。名前が長いのは、なるべくload()を並べて使ってほしいという想いから。

    V.load_each('Foo.Bar.Buz', 'Hoge', 'Huga')
    -> V.Foo.Bar.Buz
    -> V.Hoge
    -> V.Huga
    
  5. (導入するとすれば) import_extending_eachで複数同時。これも同じく意図的に長い名前で。

  • load_as_eachuse_eachはなし。前者は元の問題の4. や5. などのため。後者はなにが優先されるのかわかりづらいため。

ところで、上記方法で、lingrでmanga_osyoさんが要求していたユースケース: Vなどを経由せずいきなりs:から使えるようにしたいというものも自然に解決できます。実装上の黒魔術はなく、explicitで、かつ十分に短いです。

V.import_extending(s:, 'A.B.C')

以下、実装の。擬似コード。実際には厳しめの引数のチェックとエラー処理が入ります。

function! s:load(x)
  call s:load_as(a:x, a:x)
endfunction

function! s:load_as(x, y)
  ...
endfunction

" function! s:load_each(...)
"   for x in a:000
"     call s:load(x)
"   endfor
" endfunction

function! s:import_extending(x, y)
  call extend(y, s:import(x))
endfunction

ujihisa avatar Oct 20 '12 05:10 ujihisa

まとめおつです。 いくつか意見があったので書き込んでみます。 まず、上記を見て vital.vim でモジュールを使用する場合 3つに分けられると考えられます。

1.V に展開する

  • load 関数

2.モジュールの辞書を返す

  • import 関数

3.モジュールを展開する辞書を渡す

  • import_extending 関数

2.と3.は違う機能なので import を付けずに extending だけ(もしくは全く別の名前)の方が分かりやすいとかと思います。 あと load_each を用意するのではなくて、thinca さん案の load に複数モジュール名を渡したほうがすっきりしていると思います。 わたしも thinca さんの案ではリストも渡すようになっていたので複雑だと思っていたんですが、それを load_as に分ければ問題ないかなーと。 (もしくは load_each が非推奨であるなら削除してしまったほうがいい。

以下、上記を加味した使用方法の提案

" ---------------------------------------------------------
" V にモジュールを展開する
call V.load("Foo.Bar")
=> V.Foo.Bar


" 複数のモジュール名を渡すことで複数のモジュールを展開
call V.load("Foo.Bar", "Foo.Buz")
=> V.Foo.Bar
=> V.Foo.Buz


" laod_as で参照する名前を変更する
" こちらは複数ロード不可
call V.load_as("Foo.Bar", "FB")
=> V.FB


" ---------------------------------------------------------
" モジュールの辞書を返す
let M = V.import("Foo.Bar")
=> M.Foo.Bar


" こちらも複数のモジュールを指定することが出来る
let M = V.import("Foo.Bar", "Foo.Buz")
=> M.Foo.Bar
=> M.Foo.Buz


" ---------------------------------------------------------
" モジュールを展開する辞書を渡す
" s: にモジュールを展開する
call V.extending(s:, "Foo.Buz")
=> s: から直接使用出来る


" こちらも複数のモジュールを指定することが出来る
call V.extending(s:, "Foo.Bar", "Foo.Buz")
=> s: から Foo.Bar と Foo.Buz 直接使用出来る

とりあえず、わたしの考えはこんな感じです。

osyo-manga avatar Oct 20 '12 07:10 osyo-manga

関数の数が多すぎる気がします。 微妙に動作の違う関数がたくさんあると、ユーザはどれを使えばいいのかわからず混乱します。 似た機能の関数はまとめた方がわかりやすいのではないか、と言うのが私の意見です。

thinca avatar Oct 20 '12 07:10 thinca

ユーザはどれを使えばいいのかわからず混乱します

名前が短い順に推奨度が高く、長いほど推奨度が低い、というのを想定して提案してみました。ドキュメントにもそれを明記した方がいいですね。ちなみに、ひとつの関数ができることをひとつにしぼっているので、結果としてすべての仕様を理解するためのコストは小さいと思います。

ひとつの関数で複数のことができると、ユーザはどの方法が推奨されているのかわからず混乱します。異なる機能の関数は分けた方がわかりやすいのではないか、というのが私の意見です。

ujihisa avatar Oct 20 '12 07:10 ujihisa

そもそも、1つの方法を推奨するつもりはないです。 好きなように使っていただければ。

thinca avatar Oct 20 '12 07:10 thinca

co-meeting の方でも話し合っていたのですが、現在固まっている仕様はこんな感じです。 https://github.com/vim-jp/vital.vim/wiki/load-import%E4%BB%95%E6%A7%98%E3%81%BE%E3%81%A8%E3%82%81 ujihisa.vim を一旦の〆と考えていたので、この仕様で問題がないのであればこれに決めたいかと思います。 どうでしょうか?

osyo-manga avatar Nov 06 '12 08:11 osyo-manga

あと co-meeting のログはここら辺を参照して下さい。 https://www.co-meeting.com/g/870141505682293#!508352d4ab5c3734390006c1

osyo-manga avatar Nov 06 '12 09:11 osyo-manga

co-meetingはアカウント持ってないと見れないのがちょっとアレですね。 Lingrみたいに誰にでも公開にできないもんでしょうか。

tyru avatar Nov 10 '12 09:11 tyru

ぼくもオープンな場所がいいと思います。

mattn avatar Nov 10 '12 12:11 mattn

確かに公開出来ないのは厳しいですね…。

osyo-manga avatar Nov 11 '12 04:11 osyo-manga