1.0 への移行¶
Onion は、まだ影響が小さいうちに、1.0 の前に構文と API を整理しています。 互換性を壊す変更を、コードの直し方と一緒にここにまとめます。
1.0 以降は互換性を約束します。1.x でコンパイルできるプログラムは、 その後の 1.x でもコンパイルでき、意味も変わりません。
ret は yield になりました¶
do ブロックの最後の値は yield で書きます。
// 以前
val sum = do[Option] { a <- getA(); b <- getB(); ret a + b }
// 現在
val sum = do[Option] { a <- getA(); b <- getB(); yield a + b }
- 変わったこと:
yieldは予約語になりました。retは普通の識別子に戻りました。 - 表示されるもの: 古いコードでは「ローカル変数 ret が見つかりません」と表示され、
yieldを使うようヒントが出ます。 yieldという名前の Java メソッド: バッククォートで呼び出します(例:Thread::`yield`())。- プロジェクト全体を書き換える:
retを変数名として使っている場合は、結果を確認してください。
2147483648 の直前には - が必要になりました¶
リテラル 2147483648(と 9223372036854775808L)は、-2147483648 のように単項 - のオペランドそのものである場合だけ有効です。
それ以外の場所では、以前は黙って最小値に化けていました。
// 以前: コンパイルでき、意外な値になっていた
val a = 1 - 2147483648 // -2147483647(ラップアラウンドによる)
val b = -2147483648 as Long // 2147483648: `as` は `-` より強く結合する
val c = -2147483648 / 2 // 1073741824: `/` は `-` より強く結合する
// 現在
val a = 1 - 2147483648L // または 1L - 2147483648L
val b = -2147483648L // または (-2147483648) as Long
val c = (-2147483648) / 2 // -1073741824
- 変わったこと: 最小値の絶対値は、トークンではなく、それを符号反転する場所で検査します。
- 表示されるもの: リテラルの位置に「整数リテラルがIntの範囲(-2147483648..2147483647)を超えています -- Long型リテラルにするには末尾にLを付けてください。」と表示されます(
L付きなら Long の範囲のメッセージです)。 - 引き続き使えるもの:
-2147483648、x + -2147483648、3 * -2147483648、-9223372036854775808L、0x80000000のような 16 進数・2 進数のビットパターン。
10進数の B/S リテラルは符号付きの範囲に収める必要があります¶
10進数の Byte リテラルは -128..127、10進数の Short リテラルは -32768..32767 の範囲になりました。
Java と同じです。以前は、範囲外の値が黙って桁あふれしていました。
// 以前: コンパイルが通り、意外な値になる
val mask: Byte = 255B // -1
val port: Short = 40000S // -25536
val n = -128B as Int // 128: `as` は `-` より強く結合する
// 現在
val mask: Byte = 0b11111111B // -1。ビットパターンとして書く
val port: Int = 40000 // Short には 40000 は入らない
val n = (-128B) as Int // -128
- 変更点:
2147483648と同じく、128Bと32768Sは-のオペランドそのものである場合だけ有効です。 - 表示されるエラー: リテラルの位置に「整数リテラルがByteの範囲(-128..127、またはビットパターンとして0b11111111まで)を超えています -- ...」が出ます(
Sサフィックスなら Short)。 - 引き続き使えるもの:
0b11111111Bのような2進数のビットパターンと、0xFFFFSのようにSを付けた16進数。 - 16進数と
B: 16進数リテラルのBは数字であり、接尾辞ではありません。0xABは Int の 171、0xFFBは Int の 4091 です。Byte にしたいときは0b11111111Bか-1Bと書いてください。 - そのようなリテラルが Byte に収まらなくなった箇所(
val x: Byte = 0xFFB、Byte 引数へのf(0xFFB))では、エラーにその理由を示すヒントが付きます。 - まだ収まる箇所では何も報告されず、値だけが変わります。
bs[0] = 0x1Bは 27 を格納し(以前は 1)、val y = 0x7FBは 2043 です(以前は Byte の 127)。末尾がBの16進数リテラル(0x...B)をコードから検索してください。
config ファイルの引用符付き String は、引用符を外して読むようになりました¶
shape name = config のレコードは、二重引用符で囲まれた String の値を、引用された文字列として読みます。
これで、前後の空白を持つ値も print と parse を往復できます。
# 以前: 引用符も値の一部だった
name = "Alice" # "Alice" と読む(7 文字)
# 現在
name = "Alice" # Alice と読む(5 文字)
name = " Alice " # Alice と読む(空白を保つ)
name = Alice # Alice と読む(引用符のない値はこれまでどおり trim)
name = "\"Alice\"" # "Alice" と読む(引用符を文字として残す書き方)
- 変わったこと: 引用符の中では、
\"が引用符、\\がバックスラッシュです。 それ以外のバックスラッシュはそのまま残るので、"C:\temp"はC:\tempと読みます。 - 表示されるもの: 引用符を文字として使っていたファイルもそのまま parse に成功します。
そのため、エラーもヒントも出ません。値の外側の引用符が消えるだけです。
設定ファイルの中から
"で始まる値を探してください。 閉じる"のない値や、中に裸の"がある値("a" and "b")は、行番号付きのDefectになります。 - 対象は
String成分だけです:IntやBooleanなどのスカラーは、これまでどおりに読みます。
空の [] / [:] は、隣の要素の型になりました¶
リストリテラル、またはマップリテラルの値に空の [] / [:] があると、他の要素が揃っている型として扱います。
以前は、リテラル全体が Object に広がっていました。
val adj = [[1, 2], []]
// 以前: List[Object] なので、adj[1].add(5) は E0005 で、次の行はコンパイルできた
adj.add("header")
// 現在: List[List[Int]] なので、adj[1].add(5) はコンパイルでき、次の行は E0005
adj.add("header")
// 以前の型を保つには、型を注釈する
val xs: List[Object] = [[1, 2], []]
- 変わったこと: 空のリテラルは、隣の要素の後に、その型で型付けされます。要素の評価順は、これまでどおりソースの順です。
- 表示されるもの: 異なる種類の要素を混ぜたコードや、
List[Object]の引数に渡したコードで、List[List[Int]].add(String)(またはMap[String, List[Int]].set(...))を示すE0005が出ます。 - そのまま動くもの: 明示した型注釈が優先されます。型の分かる隣の要素がないリテラル(
[[], []])は、これまでどおりです。