怠惰とゆとりと
どうも。
VB.NETにおけるdynamic宣言
19日の日記[オーバーロードとかよくわかってなかった - はちみつとビールですが、なんやかんやでなんかVB.NETには、C#でいうdynamic型宣言にあたるものは存在しないくさいという結論に至りました。
option strict offにした場合、デフォルトで遅延バインディングが許容されるようになるので、それでやってね〜〜ってことなんでしょう。きっと。
全体をoption strict offになんてするはずがないですし、ファイルごとに変えるのもだるいですね。どうやら、Dynamic.DynamicObjectを継承させることでダックタイピング的などうのこうのをするクラスを作ることが出来るのですがわざわざVBでそんなの使っている人なんてみたことないですね。
以前、DbExecutorを使わせていただいたときも、Dynamicの挙動がおかしかったのはそーいうことなんでしょう。まぁMS的にもVB.NETとかどうでもいいのかもしれませんネ。僕もどうでもいいです。VB.NETってMSDNですら、少し発展的な内容になると途端に情報が少なくなるので、困りものですね。特にこういうC#では出来るのにVB.NETでは出来ない、というケースの場合は検証やらでとても時間を食います。
そして本題
ApplescriptとRubyでもう僕は移動しない - hp12c
こういう記事をみつけたので、僕もやってみた
iTerm
さて、元記事ではapplescriptをRubyからキックするgemを使って書いたコードをAppleScriptから呼び出すようにしてQuickSilverに登録して呼び出しています。
面倒ですし、僕は透過度を微調整するようなことはないのでスケスケとプレーンの二択にするようにして、単純にコマンドラインから呼び出すようにしたいと思いました。
あとせっかくなのでPythonを使って書きました。超みじかいですね、わざわざエントリ書くほどのもんなんでしょうか。
僕は~/bin以下にPATHを通してシェルスクリプトとかそーいうのを突っ込むようにしているので、以上をそちらに突っ込みました。
引数に-を渡したらスケスケ、それ以外なら非スケスケ——というのを期待したのですが。が、なぜか一度呼び出すと超スケスケになったっきり、うんともすんとも言いません。
.transparency.get()を呼び出したところ、どんな数字をsetしても[0.8999999761581421]が帰ってきます。わけわかんねー。
つーかまず、AppleScriptがよくわかっていないので、それとappscriptについて調べてみようと思います。……思ったのですが、僕はゆとり教育世代なので、なんかやりはじめてからもう一時間経っちゃったし正直いって萎えてしまい、というかもう11時すぎてるし眠いし、今日のところはこれくらいで勘弁してやろうと思います。
- 23日追記
寝て、起きてから書き直したらうまく動きました。そもそも渡す数値の桁を間違えていたよーです。
あとはこれに実行権限を与えて適当な所に置きましょう。健全なマカーであれば、一日の作業のほとんどはターミナルに引きこもって行うことだと思います。当然シェルはzshだと思います。
なので、zshrcに適当なfunctionなりを設定して、引数付きでこいつを呼び出してあげればそれで事足りると思います。あるいは元コードのように、interval的なものを設定して、連打するごとに透過度が変わるような設定に変えてもいーんじゃねえかと思います。
- 追記おしまい
あと、今この日記を書いていて思い出したのですが、iTermは<⌘+u>を押下することで透過設定のon/offを切り替えることが出来ます。
つまり、裏側にあるブラウザなどが見える透過度に設定しておいて、あとは作業中の欲求に応じて<⌘+u>を押せば僕がやりたかったことは大体出来てしまう訳ですね! うわ、できた! くそが!
でも、Mac限定になっちゃうけどこのappscript自体は面白いかも。iTermとか、そこらへんの主要なアプリのラップするオブジェクトを作ってやれば色々と使いでがありそーっすね。
オーバーロードとかよくわかってなかった
ちょっとメモ
今日やろうとして、ちょっとハマって結局逃げたところ。というより、ちょいちょい似たようなパターンに遭遇しては綺麗に実装できなくてハンカチかんでたパターン。
書き捨てコードで、スパゲッティだったのでいまいちうろ覚えだけど
public IEnumerable<T> hogeIsMatch<T>(IEnumerable<T> lines, IEnumerable<t> baseLines) where T: BaseHoge { var hoged = lines.select(line => { var matched = baseLines.matchedLineFilter(line) // ~ なんかする ~ } return hoged }
元はVB.NETだったのだけれど、上記のようなコードになっていて`matchedLineFilter`の部分はT(BaseHogeを継承した型)に応じて分岐させるような感じにしたかった。
そこで書いてみたコードが
public static class HogeHelper { public static BaseHoge matchedLineFilter(this IEnumerable<BaseHoge> me, BaseHoge targ) { throw new notImplementException() } public static FooHoge matchedLineFilter(this IEnumerable<FooHoge> me, FooHoge targ) { return me.where(l => /* lの各プロパティをtargと比較 */) .firstOrDefault() } // 以下、派生させた型ごとにオーバーロードした拡張メソッドを増やす }
こんな感じ。
んでも……
僕の中では、実行時のTの型に応じたmatchedLineFilterが呼ばれるでしょーウフフフーという目論みだったわけだが、当然そうはならず。常にBaseHogeを引数とした、つまりnotImplementExceptionが吐き出されてしまう世界。
いわゆる静的な型の言語の、仮想メソッド呼び出しみたいな真似って呼び出し主の型に応じたアレしかしてくれないのね、きっと。
つまり、あまり内部実装的な部分までは僕はわからないのだが、これはジェネリック使ってようがどうしようが、静的に(コンパイル時に)決定できる型情報でのみ関数呼び出しのディスパッチが行われるのではーという推理的なものが脳裏にひらめいた。
つまり割とどうしようもないということ。多分StragegyとかVisitorパターンとかに沿う形で実装しなおせば良いのかもしれないけど、使い捨てコードだしそんな時間はない。そもそもあんま大げさなことはしたくない。型を見て自前でディスパッチとかやりたくねーし。リフレクションも書きたくない。
そこで僕は、hogeIsMatchをジェネリックを使わない形で書き直し、BaseHogeの派生型の数だけコピペして書き換えるという形で逃げた。
今回はまぁそんな感じで逃げたわけだが、これは掘り下げた方が良さそうな雰囲気なので掘り下げてみる。
たとえばScalaだとどうなんだろう。
とりあえず検証は明日やるとして
def matchedLineFilter[T](lines: List[T], baseLines: List[T]): List[T] = { val hoged = lines.map(line => val matched = line match { case foo:FooHge => baseLines.matchedLineFilter(line) case bar:BarHoge => baseLines.matchedLineFilter(line) // ~~~ case _ => throw new notImplementException() } // ~ なんかする ~ return hoged }
こんな感じに……通るのかこれ……?
構文合ってるかどうかも心配だけど、まさしくただのかっこいいif文になっていて激しくいけてない。
と、今気がついた。
ようは動的言語よろしく、型の解決を実行時にやらせれば良いのだ。
VBは元々それが出来る。そしてC#にはdynamicが導入されている。なので最初の例の、baselinesだけでもdynamicでとってやれば、matchedLineFilterの引数の型の解決が実行時にまで遅延して、結果として動的な型に応じたメソッドが呼び出されるのではなかろうか。
うん、これはいかにも合法な予感がするぞ? 明日試してみよう。
ただ、相当な回数呼び出されるのでパフォーマンスが心配だ。いざとなったらメモ化みたいな感じでデリゲートをキャッシュしたりすれば良いのかしらん? いやでも、確かdynamicは動的に生成したコードのキャッシュを保持した記憶があるので、余計なことはせんでいいのかもしれない。ここのところも明日調査すべし。
逃げっぽいけど、こういう柔軟な対応が出来るのが.NETの良いところですなぁ。まだ解決するかわからねーけど。
出来れば、もう少し型安全な形で実装できる方法を探りたい。拡張メソッドで型のパターンマッチのような動作が実現出来るときいたことがあるが、やはりそういったものはどうなのかなー読みにくくなりそうだなーと不安なので、つまるところ書きなぐりであっても最初からもう少しまとまった設計で実装出来るようになったほうが良いのかもねなどととりとめもなく。今回に関していえば、ちゃんと書き直せばこういう小手先のアレをせんでも良いスクリプトなので。
プロンプトを玲音にした
ゆのっちプロンプト(✖╹◡╹✖ ←こういうの)にしてる方をちょいちょい見かけて、実に気持ちが悪いなと感心したので僕もプロンプトを玲音にしてみました.
とりあえずこんな感じで、色とか表情は後日練ろうと思います。あとユーザの名前とかそういうのも表示させるかどうか悩んでます。
現状の設定はこんな感じに書いてます。
https://github.com/hachibeeDI/dotfiles/blob/master/.zsh/themes/hachibee.zsh-theme
かなりぐちゃぐちゃなので気が向いたら整理したいですが、コマンドの終了コードが0以外だと Ծ‸Ծ✖ が帰ってスゴイ・カワイイヤッター! あるいは悪いlainにするのもいいかもしれないですね。
明日の会社のために、スライドを見直したりしようと思ってたんですけど、何やってんでしょうねぼくは。とりあえずお酒飲んじゃったんでもう寝ます、おやすみ。
PowerShellは出来る子なのではないか
WindowsにはまともなCUIが、もといスクリプティングな環境がない。そう考えている時期が僕の今日まででした。
今日、会社の都合でPowerShellでスクリプトを書いたのですが、こいつが思ってた以上に好感触。
文法もC#とシェルスクリプトを合わせたような感じ。オブジェクトベースのシェルということで、パイプにしても、シェルスクリプトがテキストをつないでいくのに対して、powershellはLINQ書いてる気分。
何よりも.NETerなら学習コストがとても低い!
手持ちにWindowsの環境がないで未検証のコードになってしまうが、例えば郵便番号とかのCSVを読み込んでなんか処理するようなものを書く場合
Import-Csv | ? {$_.郵便番号 -match "^19[4-7]-\d{4}$"} | % {$_.住所}
こんな感じで書けば、正規表現でマッチした郵便番号が存在するレコードのうち、住所だけを抜き出すことが出来ちゃう。
こういう作業を、cygwinとか入れたりせずにコマンドライン一発で出来てしまう。
いけてるのが、パイプで渡してるオブジェクトに対して、CSVをパースして定義しているカラム名を勝手にフィールドとして定義してくれているところ。これをC#のLINQでやろうとするとDynamicを使うことになるのかしらん? awkだとこうはいかない
解説すると。
?{} の部分は、色々と書き方があるのですがwhere{}とも書くことが出来ます。要はfilter。
%{}はmapです。
ちなみに$_はパイプ処理時に暗黙に用意される変数で、渡される変数を示してる。Scalaで使う_みたいな感じだと思えばわかりやすい。
あと、awkっぽい文法が用意されております。
1..15 | % -Begin{[int]$total} {$total = $total + $_} -End{Write-Host $total}
こんな風に書くことも出来る。ちなみに、powershellはかなり色々な書き方が用意されていて、例えばパイプにしてもForeach-Objectと書けたり| foreachと書けたり| %と書けたりする。
awkっぽい部分も、別の関数に分けてしまって
function pipe() { begin {hoge} process {hoge} end {hoge} }
とも書けるらしい。というかそもそも、-Beginとか明示しなくても、ScriptBlockを三つ渡してあげれば、勝手に判断してくれるらしい。出来る子だ。
あと文字列中の文字の展開も
$hoge="hoge" $foo="foo" Write-Host String::Format("hoge={0}, foo={1}", $hoge, $foo) Write-Host "hoge={0}, foo={1}" -F $hoge, $foo Write-Host "hoge=$hoge, foo=$foo" #シングルコーテーションだと展開されない
とまぁ.NETおなじみのString.formatからシェルっぽくそのまま展開とか色々出来る。あと変数には型を指定することも出来る。
そして.NETのライブラリは基本的に全て呼べる。
上では書いてないけど、関数の定義とかもC#チックですごくとっつきやすい。しかもその上で、シェルスクリプト風の文法にも対応している。コマンド自体の利便性を拡張するために、パイプ用のフィルターを別途定義したりできる。さらに、先のCSV-importみたいなものにしてもC#とかで自作して拡張できちゃう(多分)という。
正直、今まで触りもせずに馬鹿にしてきていたけど、*nixに負けないスクリプティング環境が手に入ったとさえ感じるでござる。ネットワーク系とかは……わかんないけど。
あとはもう少しまともなターミナルエミュレータさえ用意してくれれば、あるいはWIndowsにプログラマブルな環境がそろう日が来るのかもしれない。
まぁその前にWindows買わないといけないけども。
いまさらオブジェクト指向について考えを巡らせたので
なんで2013年も終わりになりそうになってて、ScalaとかHaskellだとかF#だとかで巷がにぎわってるのにこんなカビの生えた話題なんでしょうね。いや、僕的には割と生々しいんですけども。
というのも、社内で有志を募りちょこちょことやったりしているモノに関連して、コーディング規約を僕の独断と偏見で全部書いたりしていた訳です。
そんでもって、そこに関連して良いコードを書くためのハウトゥーみたいなものも勝手に書いたりしつつあるわけです。僕も新人ですけど、例えば新人が新たに入ってきたりとか、運用の人がコーディングに参加したりとかなんだりするときに役に立ちますし、うまく練り上げれば社内でも有用な文書になりますもんね。というか正直社内のコーディングのアレについては若干歯がゆいものを感じているので、これを気に良いコードを書く習慣が広まれば良いなぁと思ってもいるのです。
という導入がありまして。
その社内の某ではWebフレームワークを使うので、非開発者や新人はもとより、開発チームでもオブジェクト指向について危うい感じのメンバーもいるアトモスフィアを感じているので、さも偉そうな感じで解説用の文書を書こうと思い立ちました。
世の中でどーいわれてんのか
そんで、僕自身はまあそれなりにわかってるつもりではあるんですけど、人様の為の文書をまとめるとなるとそんないい加減なことじゃいけない。ましてやゆくゆくは社内の手引書にまで育て上げたいと思っているのだ。つまり世の中で、OOPについて言及している文章(主にネットの)からパクろうと思ったんです。
でも、なんかこうこれじゃない感のあるエントリとかばっかなので余計もやもやした。
なんだろう、クラスベースの言語機能をオブジェクト指向とイコールで結んでる感じのが多くね? って感じなんだけど、それって違くね? って思うんですよ。
だって僕、普段仕事では.NET使ってますけど、.NETにしても関数型的な機能(関数型の定義とかどうでもいいからね。ようは高階関数とかレキシカルスコープ的な挙動を使ったコーディングですよ)を結構使いまくるわけで、そんなこんなでオブジェクト指向してるコードを書けてるという自己評価ですよ。ええ。
あと本題とは全然関係ないんだけど、一時話題だったstaticおじさんなんかはともかくとして、20世紀入ってからのエントリでオブジェクト指向は全能じゃない〜だとか銀の弾丸が〜とか言っちゃってるの、ナンセンスだと思うんですよね。もはや基礎教養レベルのものについて、ノウハウ以上のことを語るのって意味あるんでしょーかね。それ言っちゃうとこのエントリの意味がなくなるんですけどね。
つまり言いたいのは、みんな難しく考え過ぎなんじゃねえの? だって僕、特に苦労とかなくて一瞬で理解出来たんだけど、なんか難しいことあんの?え?俺あたまいいの? っていう。もちろん、理解できるっていうのとうまく扱えるってのは別もんで、そこんところ僕は経験不足も相まってまだまだなのは自覚的ですけど。
どう考えてるのか
まずクラスがどうこうとか、関係ないと思う。いわゆる一つの言語しか知らないし知る気もない系の人とかは、この手のに凝り固まりがちな気がすんだよね。そういう人ってPythonはカプセル化が出来ないからオブジェクト指向は出来ない! とか言い出しちゃう。
オブジェクト指向は、単純にコードを組み立てる上でのアプローチのことであって、クラスがどうだとかポリモルフィズムがどうだとかってのは、下のレイヤーの話と混同すんなよっていう。多分これわかってる人は当たり前にわかりすぎてて、だから誰もわざわざエントリ書かないのか、もしくは僕が完全に的外れ超高校級かのどちらかだと思うんですけど。
たとえてみましょう。いいですね。オブジェクト指向の話っていっつも抽象的なたとえ話ですもんね。
たとえばですね。ネットワークのプロトコルってあるじゃないですか。
僕全然詳しくないんで間違ったこと言ってるかもしれないですけど、あれもいわばオブジェクト指向だと思うんですよ。
通信の規約って、確かRFCとかいうのに載ってるって聞いたんですけど、実装レベルでの規約ってのは例えば
+ 全体の長さはaビットまでで
+ データの区切りはbビットごとに一つの単位として区切る
+ さらに全体を区切って、先頭はID、二つ目はステータス、三つ目は通信内容……
なんて感じだったと思うんですよ。
これってクラスベースでいう、インターフェースの定義じゃないですか? んで、実際にプロトコルにそってやりとりされるデータはインスタンスなんですよ。
他にも、例えばHTMLとかにしても、こういうマークアップの時はこうしてくださいよーっていう規格が存在する。そんで、その規格にそって各ベンダは中身をそれぞれ実装する。
中身の実装はてんでばらばらだけど、ちゃんと規格にそったHTMLを流せば、どれも規格通りの画面を表示してくれる。多少の誤差はでるけど。多少の。
そんなかんじ
どうですかね。オブジェクト指向の考え方ってごくごくありふれたものだと思うんですよ。
だから、C言語だろうがアセンブリだろうが(書いたことないけど)、Haskellだろうが(書いたことないけど)Lispだろうが(書いたことないけど)オブジェクト指向は実現できます。多分。
っていうか
「Haskellはオブジェクト指向は出来ない。でも純粋な関数型のパワーがあればそんなものはいらないのだ!(くわっ」
みたいなのとか、超もやもやしないですか? だって、モナドとか超オブジェクト指向っぽいじゃないですか。
「関数型のパワーを使えば、より素敵なオブジェクト指向を実現できる!」
これならいい、全然もやっとこない。
実現するための手法は色々あると思うんです。関数型にしたところで、クラスベースとは別の形でのオブジェクト指向的な、あるいはもっとうまくて崇高ななのかなのかもしんないですけど、でも物事を設計する上での冴えたやり方としてのオブジェクト指向はクラスがどうだとかそういうのに縛られたもんじゃあないですよっていう、そんだけ。
え? そんな抽象的な論はいいからクラスだとかインターフェースだとかポリモルフィズムだとかのオブジェクト指向的な手法をどうこうしたコーディングが出来なくて悩んでんだよカスって、それ努力と向上心の不足じゃあないんですか? 手を動かしてれば簡単に理解出来ますよ。多分ね。
オブジェクト指向が難しい、理解できないっていう人の気持ちはよくわかんないんですけど、たぶん難しく考え過ぎですよ。楽に、綺麗に、自分が使っている言語に適した形で、って言うように心がけてコード書いてれば自然とそういう方向に向かってコードが良くなっていくと、僕はそうなってくれたら良いなあと思ってます。社内でも、もうちょっとオブジェクト指向に対する理解が広まってくれたらいいなあと、思ってます。
以上です。