Kotlinのデフォルト引数を調べた
こっとりーん!(挨拶)
Kotlinはこんな感じでデフォルト引数が使えます。
class Calc {
fun add(x: Int = 1, y: Int = 2): Int = x + y
fun add2() = add(8, 16)
fun add3() = add(4)
fun add4() = add()
}
addの引数にデフォルト値を設定しているのでadd3やadd4で引数を省略できています。
で、これをjavapしました。
public final int add(int, int);
descriptor: (II)I
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=3, args_size=3
0: iload_1
1: iload_2
2: iadd
3: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 this LCalc;
0 4 1 x I
0 4 2 y I
LineNumberTable:
line 2: 0
RuntimeVisibleParameterAnnotations:
parameter 0:
0: #22(#23=s#24)
parameter 1:
0: #22(#23=s#25)
public static int add$default(Calc, int, int, int);
descriptor: (LCalc;III)I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=4
0: aload_0
1: iload_3
2: iconst_1
3: iand
4: ifeq 9
7: iconst_1
8: istore_1
9: iload_1
10: iload_3
11: iconst_2
12: iand
13: ifeq 18
16: iconst_2
17: istore_2
18: iload_2
19: invokevirtual #32 // Method add:(II)I
22: ireturn
LineNumberTable:
line 2: 7
StackMapTable: number_of_entries = 2
frame_type = 73 /* same_locals_1_stack_item */
stack = [ class Calc ]
frame_type = 255 /* full_frame */
offset_delta = 8
locals = [ class Calc, int, int, int ]
stack = [ class Calc, int ]
public final int add2();
descriptor: ()I
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: bipush 8
3: bipush 16
5: invokevirtual #32 // Method add:(II)I
8: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this LCalc;
LineNumberTable:
line 3: 0
public final int add3();
descriptor: ()I
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=4, locals=1, args_size=1
0: aload_0
1: iconst_4
2: iconst_0
3: iconst_2
4: invokestatic #37 // Method add$default:(LCalc;III)I
7: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 this LCalc;
LineNumberTable:
line 4: 0
public final int add4();
descriptor: ()I
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=4, locals=1, args_size=1
0: aload_0
1: iconst_0
2: iconst_0
3: iconst_3
4: invokestatic #37 // Method add$default:(LCalc;III)I
7: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 this LCalc;
LineNumberTable:
line 5: 0
public Calc();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #41 // Method java/lang/Object."<init>":()V
4: return
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LCalc;
コンスタントプールやコンストラクタは省略しました。
注目すべきはadd$default(Calc, int, int, int)というstaticメソッドですね。 第2,3引数はaddメソッドの第1,2引数に対応しています。
そして第4引数がデフォルト値が必要かどうかを判断するためのビット演算を利用したフラグです。 判断の方法ですが、例えば第4引数と1との論理積が0の場合は第1引数にデフォルト値を、第4引数と2との論理積が0の場合は第2引数にデフォルト値を使用する、といった具合です。 次に示す箇所がそれに当たります。
1: iload_3
2: iconst_1
3: iand
4: ifeq 9
7: iconst_1
8: istore_1
9: iload_1
intは32ビットなので33以上の引数にはどう対応してるのだろうと思って調べてみたところ第33引数では一周回って1との論理積で判断していました。 ということは第1引数に明示的に値を指定すると第33引数に何も指定していなくてもデフォルト値は使用されないということになりますね。 試してはいないですが。
javapの抜粋を掲載しますがインデックス416以降がそれに当たります。
390: iload 34
392: ldc #77 // int 1073741824
394: iand
395: ifeq 401
398: iconst_1
399: istore 31
401: iload 31
403: iload 34
405: ldc #78 // int -2147483648
407: iand
408: ifeq 414
411: iconst_1
412: istore 32
414: iload 32
416: iload 34
418: iconst_1
419: iand
420: ifeq 426
423: iconst_1
424: istore 33
426: iload 33
428: invokevirtual #80 // Method x:(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)I
431: ireturn
ただしKotlinはまだM8なので改善されるかも知れませんね。 ていうか33も引数使うんじゃねえ、って話ですが。
そんなこんなでKotlinのデフォルト引数を調べてみました。 あとやっぱりjavapは楽しいです。
KotlinではじめるJAX-RS
こっとりーん!(挨拶)
説明はもろもろすっ飛ばしてリソースクラスのコード掲載します。
package app
import javax.ws.rs.core.MediaType
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.QueryParam as q
Path("hello")
Produces(MediaType.TEXT_PLAIN)
class Hello {
GET fun get(q("name") name: String): String = "Hello, ${name}!"
}
という感じで普通にJAX-RSできました。
というかnameがnull許容しないので@DefaultValueを付けるべきと今思いましたので気が向いたら直しておきます(やらないパターン)。
サンプルが簡易すぎてKotlinの良さが出ていないのが悲しいですね。
良かった点。
- Mavenで簡単にビルドできた
- MavenプロジェクトをIntellij IDEAで容易くインポートできた
- たろーさん とTwitterで絡めた
微妙な点。
- Intellij IDEAのKotlinプラグインのOrganize Importが弱い気がする
- Intellij IDEAのコードフォーマットが option + command + l で両手使うのがやだ
- Intellij IDEAで command + w でファイルが閉じてくれなかった
そんな感じです。 要するにIntellij IDEAに慣れていないだけ、と。
それと テストクラス はJavaで書いていますが、これはアノテーション付きのstaticメソッドの書き方が分からなかったからです。 きっと誰かがKotlinに直してプルリクしてくれるに違いない(チラッ
本日のコードはGitHubにあります。 Arquillian のwildfly-managedでテスト書いてます。 テスト実行すると多くのJARと WildFly 8.1.0.Final をダウンロードするので時間のあるときにどうぞ。
Kotlinの勉強会もあるみたいですよ。