C Sharpens you up

http://qiita.com/yuba に移しつつあります

第4回Kotlin勉強会 @ Sansanにいってきた

AltJava言語(特に手続き型のBetter Java言語)では3年前からCeylon推しだったんですが、Kotlinにはかなわなかったなーと負けを認めてKotlin勉強会に参加してきました。 ちなみに同時期、AltJS言語としてHaxeを推してたけどこれもその後の流れはTypeScriptの完全勝利っぽくて自分の目利きのできなさにウケるんですけど、CeylonとHaxeがこれまた雰囲気似てる言語で苦笑するしかないです。

Sansanさんのオフィスかっこいい

f:id:Sampo:20161213193046j:plain 同じく渋谷宮益坂のビズリーチさんところも渋谷Javaで何度かお邪魔していますが、あそこもオフィスかっこいいし、渋谷すごいですね(小並

乾杯で勉強会スタートだ

f:id:Sampo:20161213193055j:plain メインゲストのたろうさんのご意向もあって?片手の勉強会となっていました。懇親会じゃなくて本体が乾杯で始める勉強会って初めて。Sansanさんごちそうさまでした。

KotlinでDSLを組む話

Sansanの山本さん(@boohbah)の発表。「KotlinでDSL

DSLを作る話、ここでは自力でインタープリタを作る“外部DSL”ではなく、ホスト言語機能を応用してDSLを実現する“内部DSL”を作ろうという話です。Kotlinの豊富な糖衣構文機能は、こう言われてみるとまるでDSLを組むために用意されてきたのか、という気がしてきます。

使っている機能は

  • 拡張関数 - 既存のクラスにメソッドを生やす。C#でいう拡張メソッド。
  • invoke - この名前のメソッドを用意しておくと () 演算子で呼び出せる。C++でいう operator()。
  • ()の省略 - 引数がラムダ式ひとつの場合は関数呼び出しの () を省略できる。
  • レシーバ付き関数リテラル - ラムダ式の仲間なんだけど、ドット記法で呼び出すので拡張関数と同じくメソッドを生やしたような見た目になる。
  • 中置記法 - 関数定義にinfixキーワードを付けると、 a.do(b)a do b と書ける。拡張関数でも使える。要は、好きなクラスに演算子を生やせる。

これらを駆使した結果

buildState(
  "Start",
  {
    setAction(
      buildTransit(
        "TO_ZERO",
        "Zero"),
      { })
  })

的なコードを

"Start" {
  "TO_ZERO" transitTo "Zero" action { }
}

と見事にわかりやすいDSLに落とせましたねと。 なお、このためにString型に拡張関数を生やしていたことについてはツッコミが入っていました。

Android Studio(IntelliJ)のJava→Kotlin変換結果を人手で改善する話

Sansanの辰濱さん(Kenichi Tatsuhama, Sansan | SlideShare)の徳島からのリモート発表。「Java → Kotlin 変換 そのあとに。」

実戦で相当使い込んだんだとよくわかるTips集です。 ここでコメントするよりスライドを見てもらった方が早いですが、apply使って一時変数を追放するのは気付いていなかった人多そう。 そしてこの発表でも扱っているJavaの変数宣言のNullabilityを機械判定できない話が次の人の発表につながっていきます。

Javaとの相互運用で型がどうなるかって話

むろほしさん(@RyotoMurohoshi)の発表。「Mapped TypeとPlatform Typeの話」

ひとつめのトピックはプラットフォーム型。Kotlinでは型がnullを許容するかどうか明確だけどJavaではそうじゃない。nullを絶対に返さないメソッドもString型のようにnullableな型で返すからKotlin側から扱いにくい。全部String?型扱いにする? それも不要なnullチェックが必要になってノイジー。そこでString!型。Kotlinの外から来たからnullableかnotNullかわかりませんよという型。それがプラットフォーム型。 これはややnull安全から一歩はみ出した言語仕様で、String!型はStringにもString?にも代入できてしまいます。特にStringに代入するときにはプログラマの注意でnullを渡さないようにする必要あり。実行時例外かっとびます。注意と。

もう一つが、int, Integer, ListなんかのJDK上の型がKotlinの型システム上でどう見えるか。型マッピングの仕様です。 KotlinではJavaListに当たるインターフェースが読み出しのみのListとそれに書き込みを加えたMutableListの2層に切り分けられていて、じゃあJavaListは相互運用でどう見えるか。Java側でアノテーションを付けることで区別させ、アノテーションなしだと(Mutable)Listというなんかすごい解釈がされるんだそうです。

Androidのビューコンポーネント組み立てをDSL化する話

k-kagurazakaさん(@kkagurazaka)の発表。「Ankoでコンポーネント指向」

XMLで画面を構築するつらみ

  • XMLそのものがつらい
  • アプリコードと行ったり来たりするのがつらい
  • 型安全でないのがつらい

そこでJetBrainsが作っているDSLライブラリ、Ankoどうでしょうという話です。

linearLayout {
  checkBox = checkBox().lparams {
    gravity = Gravity.CENTER_VEDRTICAL
  }
}

というコード、最初のDSLの話を聞いていると何が起こっているかわかりやすいですね。

Kotlin 1.1のbound call references機能の紹介がありました。この機能、Javaでは8ですでに導入されている機能の後追いになる、つまりインスタンスのメソッド参照のことなのですが、Kotlin 1.1のこの機能のちょっと恐ろしいところはJavaでgetter/setterの組として記述されたプロパティをひとつの参照対象とできるところ。執念を感じる。

ラムダ式禁止縛りに関数参照とカリー化で対抗しよう

トリはメインゲストたろうさん(@ngsw_taro)さんの発表。「ラムダ式禁止おじさん」

実際にはもちろん、ラムダ式禁止おじさんに張り合いたいのではなく、ラムダ式と同等の書き方をいろいろできるよという切り口からのKotlinの高階関数機能紹介です。

  • 単なる一引数関数なら関数参照で単純に置き換え可能(::println
  • 引数なしメソッドもメソッド参照で単純に置き換え可能(String::toLowerCase
  • 二引数関数はカリー化すればいい。カリー化する仕組みは自作する。どうやって作るかというと関数に対してinvoke拡張関数を生やす(ラムダ式禁止おじさんを完全に殺す黒魔術)。((::minus)(5)
  • カリー化するにも、先頭でなく右側の引数を固定したい場合はどうする? プレースホルダ付きカリー化だ。そういうinvoke拡張関数を生やしてカリー化すればいい。プレースホルダEnumで定義する。すると⋯ ((::minus)(アレ, 3)
  • Java8のインスタンスメソッド参照("ABC"::toLowerCase)みたいなのをKotlin 1.0でどうやるか(Kotlin 1.1ならできるようになるのは前の人の発表であった通り)。カリー化invokeが定義された状態で、こう。 (String::toLowerCase)("ABC")
  • nullableメソッドコール ?. をするラムダ式はどうする?(引数型->戻り型)型を(引数型?->戻り型?)型に変換するような拡張関数を関数に生やしてしまえ。その拡張関数の名前をnullOk とすると、(String::toLowerCase.nullOk()

そして結論はラムダ式使え。その理由はコードの読みやすさとかそういうのもあるものの、インライン展開というKotlinの利点が殺されてしまうからというのもあります。

懇親会

f:id:Sampo:20161213212004j:plain せっかくの懇親会、お二方としかおしゃべりしませんでしたチキンでごめんなさい⋯

お話しした方の話で印象に残ったのが、「JavaからKotlinへの移行は容易だがKotlinからJavaへは簡単に移行できないので、長期間続けるプロダクトに採用しにくい」という意見でした。そういえばAltJSではTypeScriptが猛烈な勢いで普及していますが、これの強みは言語そのものの良さだけでなく「JavaScriptにも容易に戻れる」という安心感はあるよなと思い起こしました。

全体的な所感

まだKotlinが普及初期であること、あとこの勉強会がまだ4回目と回数を重ねていないこともあり、マニアックな方面に偏ってしまわない誰でも理解できる内容の発表ばかりで、それでいて実のある話が聞けとても良いセッションでした。

LT持ち寄りの勉強会は全体としてのテーマというのが決められていないものなのですが、山本さんがDSL構築の話をしたあとにk-kagurazakaさんがその応用となる話をされていたのが見事にはまっていました。辰濱さんとむろほしさんの発表がnullabityでつながっていたのも一体感ありましたし、神の見えざる手を感じましたね。

発表者の皆様、Sansan様、ありがとうございました。

ちょまど問題の算数的解法を改善=14手

昨日の http://cs.hatenablog.jp/entry/2014/06/18/174157 には出題者の名前からちょまど問題という名前が付いたようです。

16手というのは算数的解法で、数学的にはまだまだ先があるのですが、ともかく算数的には16手が最短かと思っていましたが、まだまだ改善の余地がありましたね。14手になります。

解法のアイディア

  1. まず3回の試行で正解の分布を知る。正解を多く含む順に上位の選択肢2つ(A,Bと名付ける)と下位の選択肢2つが決まる。
  2. 9回の試行で、問9までについて正解がAかBか下位かがわかる。下位が正解の問題は最大4問。
  3. 2択問題が最大で4問なら、それらは2回の試行で正解がわかる。
  4. 問10の答は正解の分布から差し引きでわかる。

3 + 9 + 2 = 14手。

4択10問テストの正解探索回数=最大16回(破られた)

本日twitter上でエンジニアの間で話題になった問題。

4択問題10問のテストを全部埋めて提出すると正解数がわかります。
何回提出すればすべての正解を知ることができますか。

10問すべての正解は、最大16回の試行で知ることができます。
(2014-06-20追記:これは算数の範囲内での答なのですが、算数の範囲内でもさらに改善できました。14手です。 http://cs.hatenablog.jp/entry/2014/06/20/132605

続きを読む

PostgreSQLでは識別子に大文字を使ってはいけない

タイトルの通り、PostgreSQLではテーブル名、カラム名など識別子に英大文字を使うべきではありません。

続きを読む

DBの自動連番がロールバックしても戻らない理由

DBの主キーカラムに自動連番(MySQLならAUTO_INCREMENTSQL ServerならIDENTITYOraclePostgreSQLならシーケンス)を設定していると、基本的には連続した数字が付番されていくのですが、行削除もしていないのに抜け番が発生する場合があります。

などの場合です。

特にトランザクションロールバックは、DB全体の変更をなかったことにするはずなのに連番だけは進んだまま戻らないということで、知らないと違和感があるものです。

続きを読む

返す値を一時変数に受けるよりはtry-finally

余計な一時変数というのはなるたけ作りたくないものですが、例えばJavaでこんなコード書いちゃうことあるじゃないですか。

static T poll() {
  Integer result = array[top];                   // (1)
  if (++top >= array.length) top -= array.length;// (2)
  return result;
}

メソッドの戻り値が決まる(1)のが処理完了(2)より前というパターン。Delphiなら無縁な手間なんです*1が、C系の言語だとメソッド抜けるときまで戻り値を一時変数に受けておかないといけません。

こんな無意味な一時変数美しくありませんね。どこか行ってほしいですね。そして幸い、Javaにはそのための道具があります。try-finallyです。

*1:処理のどの段階ででも、関数名と同名の変数に代入しておいた値が抜けたときに戻り値になります。

続きを読む

.Net FrameworkのDateTime型

日付時刻のデータタイプはだいたいどの処理系でも深い闇を湛えているものです。
.Net FrameworkのDateTime型はさてどんな闇でしょう。

続きを読む