長い開発期間を経て、ついにScala 2.13.0がリリースされました!
今回、ドキュメントへの1行だけの追記ですが、初めてScala本体へのPRがマージされたので、Contributorsに自分の名前が有るのが最高に嬉しいですね。
というわけで、Scala 2.13、使っていきましょう!
Scala 2.12と、2.13で返す型が変わっていますが、ドキュメント上で探すことができませんでしたのでここに書いておきます。
Welcome to Scala 2.12.8 (OpenJDK 64-Bit Server VM, Java 12.0.1). Type in expressions for evaluation. Or try :help. scala> val chars = "こんにちは世界".toIndexedSeq chars: scala.collection.immutable.IndexedSeq[Char] = Vector(こ, ん, に, ち, は, 世, 界)
Welcome to Scala 2.13.0-RC3 (OpenJDK 64-Bit Server VM, Java 12.0.1). Type in expressions for evaluation. Or try :help. scala> val chars = "こんにちは世界".toIndexedSeq chars: IndexedSeq[Char] = こんにちは世界 scala> chars.getClass res0: Class[_ <: IndexedSeq[Char]] = class scala.collection.immutable.WrappedString
WrappedString
を返す方が余計なコピーも無くてよさそうですね。
先日のエントリで、ArraySeq.unsafeWrapArrayを取り上げましたが、そもそも何が'unsafe'なの?immutableなデータ構造にラップするので、safeなのでは?と疑問に思ったところ、いつものごとくKenji Yoshida(@xuwei_k)さんに教えて頂きました。
immutableなコレクションなのに、もとのArrayの参照保持しておいて中身変えると、ArraySeqの方も変わるからunsafe、という意図です。
— Kenji Yoshida (@xuwei_k) 2019年6月2日
言い換えると、もとのArrayを変更しないと自分で保障出来て、パフォーマンス的にどうしてもコピーを避けたいときにだけ自己責任で使え、という意味でそういう命名かと pic.twitter.com/5v91rkNdco
なるほどーいくらラップしても元のArrayがmutableであることには変わりないので、そこは理解して使えよ!ってことのようです。その注意喚起の意味でのunsafeですね。
ちなみにArraySeq.unsafeArray
のscaladocにはそれなりのメソッドの危険性が書かれています。
abstract defunsafeArray: Array[_] The wrapped mutable Array that backs this ArraySeq. Any changes to this array will break the expected immutability. Its element type does not have to be equal to the element type of this ArraySeq. A primitive ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an array of a supertype or subtype of the element type.
しかしどちらかというと、ArraySeq.unsafeWrapArray
のscaladocに書いて欲しいところですね。
もしどこにも書いてないならscaladoc追加するだけのpull reqチャンス(?)
— Kenji Yoshida (@xuwei_k) 2019年6月2日
というわけでアドバイスを頂いたこともあり、初めてのScala本体へのPRを書きました。
レビューは通っているので、Scala 2.13.1あたりには取り込まれるのではないでしょうか。
1行の、ドキュメント追加とはいえ、マージされると嬉しいなぁ。
いよいよ正式リリースが近づいてきたScala 2.13ですが、既存のコードをリリース候補版のScala 2.13でコンパイルすると以下のようなメッセージを見かけるようになりました。
scala> def makeSeq(a: Array[Int]): Seq[Int] = if (a == null) Nil else a ^ warning: method copyArrayToImmutableIndexedSeq in class LowPriorityImplicits2 is deprecated (since 2.13.0): Implicit conversions from Array to immutable.IndexedSeq are implemented by copying; Use the more efficient non-copying ArraySeq.unsafeWrapArray or an explicit toIndexedSeq call makeSeq: (a: Array[Int])Seq[Int]
copyArrayToImmutableIndexedSeq
なんてメソッド、呼び出していたっけ?LowPriorityImplicits2
っていうクラスって何だっけ?そもそも、このメッセージは何を意味しているのか?…調べた結果をまとめました。
まずはScala 2.13へのマイグレーションガイドをチェックします。
20ページに関連する記載が有ります。
Wrapped Java varargs pretend the array is immutable • Using the new s.c.i.ArraySeq • You can do the same with ArraySeq.unsafeWrapArray • A deprecated implicit conversion makes a copy of the array
Scala 2.12までは、ArrayをSeqへ渡すと、scala.collection.mutable.WrappedArray
に変換されていました。これはScala 2.12のscala.Predef
で定義されているImplicit Conversionの挙動です。
scala> val r: Seq[Int] = Array(1, 2) r: Seq[Int] = WrappedArray(1, 2)
Scala 2.13ではSeqがImmutable化されたことを受けて、scala.collection.immutable.ArraySeq
に変換されます。
scala> val r: Seq[Int] = Array(1, 2) ^ warning: method copyArrayToImmutableIndexedSeq in class LowPriorityImplicits2 is deprecated (since 2.13.0): Implicit conversions from Array to immutable.IndexedSeq are implemented by copying; Use the more efficient non-copying ArraySeq.unsafeWrapArray or an explicit toIndexedSeq call r: Seq[Int] = ArraySeq(1, 2)
これはScala 2.13のscala.Predef
で定義が追加された以下のコードによるものです。
private[scala] abstract class LowPriorityImplicits2 { @deprecated("Implicit conversions from Array to immutable.IndexedSeq are implemented by copying; Use the more efficient non-copying ArraySeq.unsafeWrapArray or an explicit toIndexedSeq call", "2.13.0") implicit def copyArrayToImmutableIndexedSeq[T](xs: Array[T]): IndexedSeq[T] = if (xs eq null) null else new ArrayOps(xs).toIndexedSeq }
LowPriorityImplicits2
もcopyArrayToImmutableIndexedSeq
が出てきました。暗黙の変換によりコピーが発生するので、toIndexedSeq
でコピーして変換するか、それではパフォーマンス的に問題になる場合はArraySeq.unsafeWrapArray
を使ってコピー無しにimmutable化するか明示的に示しましょう、ということですね「ArraySeq.unsafeWrapArray
」って何がunsafe
なの?という話は、また別のエントリを書きます)。
確かに、警告が出なくなります。
scala> val r1: Seq[Int] = Array(1, 2).toIndexedSeq r1: Seq[Int] = ArraySeq(1, 2) scala> val r2: Seq[Int] = scala.collection.immutable.ArraySeq.unsafeWrapArray(Array(1, 2)) r2: Seq[Int] = ArraySeq(1, 2)
しかし、元々LowPriorityImplicits2
というクラスも、copyArrayToImmutableIndexedSeq
というメソッドも、Scala 2.12まではなかったし、Scala 2.13でも明示的に使うものではありません(implicit conversionですしね)。
定義された瞬間に非推奨になってしまうクラスと、メソッド…しかもユーザーコード上には出てきません…「実は、最初からそんなメソッドなんか無かったんですよ…」って言うと何だか押井守っぽいですね。
というわけで上記のメッセージが出たら、明示的に変換方法を指定しましょう、という話でした。
Welcome to Scala 2.12.8 (OpenJDK 64-Bit Server VM, Java 12.0.1). Type in expressions for evaluation. Or try :help. scala> val seq1: scala.Seq[Int] = scala.collection.immutable.Seq(1, 2) seq1: Seq[Int] = List(1, 2) scala> val seq2: scala.Seq[Int] = scala.collection.mutable.Seq(1, 2) seq2: Seq[Int] = ArrayBuffer(1, 2)
Welcome to Scala 2.13.0-RC3 (OpenJDK 64-Bit Server VM, Java 12.0.1). Type in expressions for evaluation. Or try :help. scala> val seq1: scala.Seq[Int] = scala.collection.immutable.Seq(1, 2) seq1: Seq[Int] = List(1, 2) scala> val seq2: scala.Seq[Int] = scala.collection.mutable.Seq(1, 2) ^ error: type mismatch; found : Seq[Int] (in scala.collection.mutable) required: Seq[Int] (in scala.collection.immutable)
もうmutable.Seqは代入できない…っていうか今までできたんだ…知らなかった…
先日AnkerのUSB PD 60W対応の充電器を買ったので、卓上の電源周りを見直そうと、USB Type-Cケーブルも新調した。純正では2mも有って卓上では取り回しづらいので、ELECOMのUSB 3.1対応、USB PD 5A対応の、所謂全部入りのケーブル…以前はけっこう高かった印象だったけど今ならAmazonで1342円とめちゃくちゃ安い。これなら規格をUSB 2.0とかに落とさなくてもいいかなっていう値段。
エレコム USB-Cケーブル C-C 1m USB3.1Gen2 認証品 PD対応 5A出力 ブラック USB3-CC5P10NBK
ただ、相変わらずケーブルの刻印を見ても何の規格に対応しているのか、さっぱり分からないんだけど…(かろうじて、10って書いてあるから10G...つまりUSB 3.1ってこと?くらい)
とにかくUSB Type-Cケーブルは混沌としているので、1.0mを越えない用途であればこのケーブルを買っておけば充電も、周辺機器の接続も間違い無い。そして、ケーブルの刻印が致命的に分かりづらいので、違う規格のものを混ぜないで統一して使った方が良いですね。
MacBookの充電器を追加で買うなら現状Anker一択じゃないかなーって。
しばらく絶版になっていた「The Art of UNIX Programming」がアスキードワンゴから再発された。アスキードワンゴはこの手のUNIX文化に関する書籍をどんどんリリースしてくれるので、本当にありがたい。みんなまた絶版にならないうちに買いましょう。
本書の構成は…
原著が2004年と今ではわりかし古めなので、第2部以降は全部読み切るより、自分の興味の有るトピックを拾い読みするくらいが丁度いいかも(けっこうページ数は多い)。
しかし、第1部の「コンテキスト」はとにかく重要。ここだけは全部しっかり読み切った方がいい。現代でも通用するソフトウェアに関する思想が詰まっている。
個人的には、冒頭に出てくる下記の主張が最高に大好きだ。
The Art of UNIXを読み直したら、ずっと出典を探してた、Dick Hammingの「誤った問題を正しく解くよりも、正しい問題を誤った方法で解く方がよい」が出てきた
— magnoliak (@magnolia_k_) 2018年10月14日
これと、Richard P. Gabrielの「Worse is Better」と併せて、みんな朝起きたら3回復唱しよう
その後もRob Pikeによる「プログラミングの原則」や、筆者によるUNIXに関する17個の考え方なども学びの多いことが並んでいる。
特に、「明確性の原則:巧妙になるより明確であれ」や、「分離の原則:メカニズムからポリシーを切り離せ。エンジンからインタフェースを切り離せ」といったあたりが秀逸なメッセージ。
と言う訳で数あるUNIX文化の解説書の中でもけっこうな物量の本だけど、ほんと冒頭の第1部だけでもいいので、じっくり繰り返し読んだ方が良い本。お勧めです。
Art of UNIX Programming, The (Addison-Wesley Professional Computing Series)