kagamihogeの日記

kagamihogeの日記です。

JEP 323: Local-Variable Syntax for Lambda Parametersをテキトーに訳した

http://openjdk.java.net/jeps/323 を読んだ。

JEP 323: Local-Variable Syntax for Lambda Parameters

Author   Brian Goetz
Owner   Vicente Arturo Romero Zaldivar
Created 2017/12/08 15:15
Updated 2018/02/12 17:25
Type    Feature
Status  Targeted
Component   specification/language
Scope   SE
Discussion  amber dash dev at openjdk dot java dot net
Effort  XS
Duration    XS
Priority    3
Reviewed by Alex Buckley
Release 11
Issue   8193259
Relates to  JEP 286: Local-Variable Type Inference

Summary

暗黙的に型指定されるラムダ式(implicitly typed lambda expressions)の仮引数宣言でvarを使用可能にします。

Goals

ローカル変数宣言と暗黙的に型指定されるラムダ式の仮引数宣言でのシンタックスを揃える。

Non-goals

メソッドの仮引数などその他の変数宣言は対象外。

Motivation

ラムダ式は暗黙的な型指定が可能で、この場合はすべての仮引数は型推論されます。

(x, y) -> x.process(y)    // 暗黙的に型指定されるラムダ式

Java SE 10ではローカル変数で暗黙的な型指定が使用可能になります。

var x = new Foo();
for (var x : xs) { ... }
try (var x = ...) { ... } catch ...

ローカル変数の統一感の観点から、暗黙的に型指定されるラムダ式の仮引数でも'var'を使えるようにしたい、と我々は考えました。

(var x, var y) -> x.process(y)   // 暗黙的に型指定されるラムダ式

統一感によるメリットには、修飾子やnotably annotationsをローカル変数とラムダ式の仮引数に、簡潔さを失うことなく、適用できる点です。

@Nonnull var x = new Foo();
(@Nonnull var x, @Nullable var y) -> x.process(y)

Description

暗黙的に型指定されるラムダ式の仮引数で、予約済みの型名varを使用可能にします。

(var x, var y) -> x.process(y)

上記は以下と同等です。

(x, y) -> x.process(y)

暗黙的に型指定されるラムダ式は、すべての仮引数でvarを使うか、全く使わないか、のどちらかでなければなりません。また、varは暗黙的に型指定されるラムダ式の仮引数でだけ使用可能で、明示的に型指定されるラムダ式では引き続きすべての仮引数でマニフェスト型(manifest types)を指定します。よって、マニフェスト型の仮引数を使いつつvarも使うことは出来ません。以下の使い方は出来ません。

(var x, y) -> x.process(y)         // 暗黙的に型指定されるラムダ式で'var'と'非var'を一緒には使えない
(var x, int y) -> x.process(y)     // 暗黙的に型指定されるラムダ式で'var'とマニフェスト型を一緒には使えない

理屈の上では、上記例の下側、半明示的な型指定(semi-explicitly typed )(もしくは半暗黙的な型指定(semi-implicitly typed)、どちらに重きを置くかの見方の違いに依る)のようなラムダ式は可能に見えます。しかし、このJEPではそれはスコープ外とし、これは型推論オーバーロード解決に深く影響するためです。これが、ラムダ式ですべてマニフェスト引数型にするか全くしないか、という制限を設ける主な理由です。同様に、暗黙的に型指定されるラムダ式の引数での型推論varを使うか全く使わないか、という制限を設ける考えです。将来のJEPでこの部分推論(partial inference)の課題に取り組むかもしれません。また、省略のシンタックスの簡潔さを損ないたくないので、以下のような表現が出来るようにはしない予定です。*1

var x -> x.foo()

Alternatives

従来通りJava SE 8 の暗黙的に型指定されるラムダ式の宣言を使用し続ける。

Risks and Assumptions

このJEPの、暗黙的に型指定されるラムダ式の引数名の前にvarを追加するのは、ソース互換性に関してはノーリスクです。これはvarなし引数の型推論var型推論は同一なためです。

*1:Also, we do not wish to compromise the brevity of the shorthand syntax, so we won't allow expressions like:が原文。compromise がよくわからん

JEP 321: HTTP Client (Standard)をテキトーに訳した

http://openjdk.java.net/jeps/321 を読んだ。

JEP 321: HTTP Client (Standard)

Owner    Chris Hegarty
Created 2017/06/08 11:46
Updated 2018/01/31 16:29
Type    Feature
Status  Candidate
Component   core-libs/java.net
Scope   SE
Discussion  net dash dev at openjdk dot java dot net
Effort  M
Duration    M
Priority    2
Reviewed by Alan Bateman, Brian Goetz
Endorsed by Brian Goetz
Issue   8181784

Summary

JDK 9とJDK 10のupdatedで導入されたincubatedのHTTP Client APIを標準化します。これはJEP 110由来のものです。

Goals

JEP 110のGoalsに加え、このJEPでは以下を行います。

  • incubated APIに寄せられたフォードバックの取り込み
  • incubated APIをベースにjava.net.httpパッケージで標準APIを提供
  • incubated APIの削除

Motivation

このJEPのMotivationはJEP 110のMotivationから変更はありません。

Description

このJEPの提案内容は、JDK 9とJDK 10のupdatedでincubating APIとして導入されたHTTP Clientの標準化です。このincubating APIには重要な改善に繋がった多数のフィードバックが寄せられましたが、大筋はそのままです。このAPIにはノンブロッキングリクエストとCompletableFuturesに基づくレスポンスセマンティクスが含まれ、依存アクションをトリガするチェーン処理ができます。リクエストとレスポンスボディのBack-pressureとflow-controlはjava.util.concurrent.Flow APIreactive-streamsを介して提供されます。

JDK 9とJDK 10ではincubatingなので、その実装をほぼ完全に書き直します。現在の実装は完全に非同期です(以前のHTTP/1.1実装はブロッキング)。RX Flowの概念を実装にプッシュダウンしており、HTTP/2をサポートするのに必要だった元々の概念の多くを削除しました。データフローのトレース、ユーザレベルのリクエストパブリッシャとレスポンスサブスクライバから基底のソケットまで、が簡単になります。これらにより、各種の概念とコードの複雑さを大きく削減し、HTTP/1.1とHTTP/2の再利用の可能性(possibility of reuse)を最大化しました。

提案した標準のモジュール名はjava.net.httpで、標準パッケージ名はjava.net.httpです。

APIの詳細についてはJEP 110を参照してください。

Testing

incubated APIに対する既存のテストを修正して新しい標準APIで使えるようにする必要があります。すべてのシナリオをカバーするテストを追加する必要があり、特にHTTP/1.1とHTTP/2間のアップグレード・ダウングレードが挙げられます。

Risks and Assumptions

incubated HTTP Client APIに依存するコードは、パッケージインポートを少々、修正の必要があります。その他のincubatedの機能に差異はありません。incubatingモジュールに依存するコードは既にコンパイル・実行時に適切な警告を出しています。

JEP 325: Switch Expressionsをテキトーに訳した

http://openjdk.java.net/jeps/325 をテキトーに訳した。

JEP 325: Switch Expressions

Author   Brian Goetz
Owner   Jan Lahoda
Created 2017/12/04 08:56
Updated 2018/01/29 16:23
Type    Feature
Status  Candidate
Component   specification/language
Scope   SE
Discussion  amber dash dev at openjdk dot java dot net
Effort  M
Duration    M
Priority    3
Reviewed by Alex Buckley
Issue   8192963

Summary

switchを文でも式としても使えるよう拡張し、また、nullの扱い方を改良します。この変更は今までの書き方を単純化するもので、switchパターンマッチング(JEP 305)に備える目的もあります。

Motivation

我々はJava言語にパターンマッチング(JEP 305)を導入するための拡張の準備をしていますが、既存のswitchの微妙ないくつかの点が障害となっており、これはユーザを長年イライラさせ続けているものでもあります。これにはnullの処理(switchは引数がnullだとNullPointerExceptionをスロー)と、swtichが文でしか使えない、があります。場合にもよりますが、式として複数条件分岐*1を表現する方が自然な場合があります。

既存のswitch文の多くの使われ方は本質的にはswitch式のシミュレーションで、各arm*2は共用のターゲット変数に代入するか値を返すかのどちらかをします。

int numLetters;
switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        numLetters = 6;
        break;
    case TUESDAY:
        numLetters = 7;
        break;
    case THURSDAY:
    case SATURDAY:
        numLetters = 8;
        break;
    case WEDNESDAY:
        numLetters = 9;
        break;
    default:
        throw new IllegalStateException("Wat: " + day);
};

文としてこれを表現するのは、似たようなことの繰り返しになるので、回りくどく間違いやすいです。上記コードの意図は日にちに対応するnumLettersの値を計算をする、というものです。これは、より直感的で、明瞭・安全に書けるのが望ましいです。

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> 9;
};

switch式への拡張は更に別の要求へと繋がっています。単純なORパターン形式(上の例で見たもの)、フローアナリシスの拡張(式は常に値を計算するか即時終了する*3)、switch式の各caseで値の算出ではなく例外をスロー可能にする、などです。

Description

式として使えるようにswitch文を拡張します。よくある例としては、switch式は以下のようになります。

T result = switch (arg) {
    case L1 -> e1;
    case L2 -> e2;
    default -> e3;
}

switch式は複合的な式(poly expression)になります。ターゲット型が既知であれば、その型は各armにプッシュダウンします。既知であればswitch式の型はそのターゲット型となり、そうでない場合、各caseの型との組み合わせでスタンドアローンの型が算出されます*4

switch文では、breakがswitchの実行を停止させます。switchで使うために、breakが引数を取れるよう拡張し、その値はswitch式の値になります。

switch式のcaseはbreakを介して式で値を算出しつつ文の実行も出来ます。その場合switch文のように複数の文を書きます。

int result = switch (s) {
    case "Foo":
        break 1;
    case "Bar":
        break 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        break 3;
}

ただし、上記のような例は稀で、文は無く単一の式を評価する複数のcase、を想定しています。また、シンタックスシュガーを提供するので、その場合はswitch式は以下のように定義します。

case LABEL -> expression;

元はこうです。

case LABEL: break expression;

よって、上記例は簡潔に書けます。

int result = switch (s) {
    case "Foo" -> 1;
    case "Bar" -> 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        break 3;
}

また、switch式では以下のようにも書けます。

case LABEL -> throw e;

元はこうです。

case LABEL: throw e;

よって、以下のようになります。

int result = switch (s) {
    case "Foo" -> 1;
    case "Bar" -> 2;
    default -> throw new IllegalStateException(s);
}

これらの書き方は必要に応じて使い分けられるので、上記のswitch式は以下のようにも書けます。

int result = switch (s) {
    case "Foo" -> 1;
    case "Bar" -> 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        break 3;
}

breakの2つの形式(値有・無)はメソッドのreturnの2つの形式と似ています。両者ともメソッド実行を即時停止し、非voidメソッドでは加えて、メソッドの呼び出し元に値を返す必要があります。(break expression-valuebreak labelのあいまいさは比較的簡単に処理可能です)

switch式のcaseは網羅的である必要があり、とりうる入力に対しarmのうち一つだけが評価される必要があります。これは基本的にはdefault句が必要という意味ですが、enumのswitch式で取りうる値をすべて網羅する場合(and eventually, switch expressions over sealed types)、default句はコンパイラが挿入して、コンパイラenum定義がコンパイル時と実行時で変わったことを示します。(これは現状開発者が手でやっていますが、コンパイラによる挿入は面倒を省いてくれて、エラーメッセージは手で書いたよりも記述的となります)

更にswitchの改良を推し進めて、switchの式と文をある程度同じにします。case句で一つしか書けないのをカンマ区切りのリストで書けるようにします。

switch (day) {
    case MONDAY, FRIDAY, SUNDAY: 
        numLetters = 6;
        break;
    ...
};

引数が参照型(現状ではプリミティブのラッパー・文字列・enumのみ)のswitchでは、case句は明示的にnullを指定できます。

String formatted = switch (s) {
    case null -> "(null)";
    case "" -> "(empty)";
    default -> s;
}

もしswitchcase null句が無い場合、最初のcase句は以下であると解釈されます。

case null: throw new NullPointerException();

この挙動はswitchで参照型を用いる際の現行の振る舞いと一致します。

なおもし余裕があれば、switchで現行では使えないプリミティブ型、float, double, longなど、を使えるようにする拡張もするかもしれません。

Dependencies

Pattern Matching (JEP 305)はこのJEPに依存します。

*1:multi-way conditionalsが原文。訳は俺が勝手につけたもの。言うまでもなくswitch-caseのような複数の条件にマッチするヤツのこと

*2:switchからcaseが伸びる様をarmと表現してると思われ

*3:compute a value or complete abruptlyが原文。良い日本語思い浮かばず

*4:この辺良くわからん。