Magnolia Tech

いつもコードのことばかり考えている人のために。

小西康陽 / わたくしのビートルズ

普段、本を読むと言えば技術書ばかりで、あまりコラム集のような、明確な目的の無い本を読むことが無い。

ピチカート・ファイヴの…といってもピチカート・ファイヴ解散からもう18年経っているので、さすがにその枕詞はいらないかもしれないけど…小西康陽のコラム集「わたくしのビートルズ」を入手した。

今回もフィクションともノンフィクションともつかない、つかみ所の無いショートストーリーめいたコラムが充実していて、ちょっとした合間の時間に読むのにぴったりの構成。内容よりもリズム感…いつまでも読んでいられる流れるような文章。

1990年代中盤の渋谷系ブームをリアルタイムに経験して、渋谷でレコードばかり買っていた世代としては、小西康陽の名前は特別だ。そして、雑誌や小冊子の、ちょっとしたコラムに小西康陽の名前を見つけると、未だに真っ先に読んでしまう。

約10年おきに刊行される小西康陽のコラム集…「これは恋ではない」「ぼくは散歩と雑学が好きだった」に続く3冊目。以前の2冊の単行本は常に家の本棚の一番いい場所に(ヤン富田の単行本と共に)置かれている。10年後に、新刊のコラム集は刊行されるのだろうか。

ぼくは散歩と雑学が好きだった。 小西康陽のコラム1993-2008

ぼくは散歩と雑学が好きだった。 小西康陽のコラム1993-2008

これは恋ではない―小西康陽のコラム 1984‐1996

これは恋ではない―小西康陽のコラム 1984‐1996

Scala 2.13におけるStringに対するtoIndexedSeqの挙動

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を返す方が余計なコピーも無くてよさそうですね。

scala 2.13から導入されるArraySeq.unsafeWrapArrayは何が'unsafe'なのか?

blog.magnolia.tech

先日のエントリで、ArraySeq.unsafeWrapArrayを取り上げましたが、そもそも何が'unsafe'なの?immutableなデータ構造にラップするので、safeなのでは?と疑問に思ったところ、いつものごとくKenji Yoshida(@xuwei_k)さんに教えて頂きました。

なるほどーいくらラップしても元の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に書いて欲しいところですね。

というわけでアドバイスを頂いたこともあり、初めてのScala本体へのPRを書きました。

github.com

レビューは通っているので、Scala 2.13.1あたりには取り込まれるのではないでしょうか。

1行の、ドキュメント追加とはいえ、マージされると嬉しいなぁ。

Scala 2.13からArrayからIndexedSeqへの暗黙の変換が非推奨となる

いよいよ正式リリースが近づいてきた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へのマイグレーションガイドをチェックします。

https://confadmin.trifork.com/dl/2018/GOTO_Berlin/Migrating_to_Scala_2.13.pdf

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
}

LowPriorityImplicits2copyArrayToImmutableIndexedSeqが出てきました。暗黙の変換によりコピーが発生するので、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ですしね)。

定義された瞬間に非推奨になってしまうクラスと、メソッド…しかもユーザーコード上には出てきません…「実は、最初からそんなメソッドなんか無かったんですよ…」って言うと何だか押井守っぽいですね。

というわけで上記のメッセージが出たら、明示的に変換方法を指定しましょう、という話でした。

Scala 2.13からscala.SeqはImmutableになった

Scala 2.12まで

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)

Scala 2.13から

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は代入できない…っていうか今までできたんだ…知らなかった…

ELECOMのUSB 3.1, PD対応のType-Cケーブルを買った

f:id:magnoliak:20190531204917j:plain

先日AnkerのUSB PD 60W対応の充電器を買ったので、卓上の電源周りを見直そうと、USB Type-Cケーブルも新調した。純正では2mも有って卓上では取り回しづらいので、ELECOMのUSB 3.1対応、USB PD 5A対応の、所謂全部入りのケーブル…以前はけっこう高かった印象だったけど今ならAmazonで1342円とめちゃくちゃ安い。これなら規格をUSB 2.0とかに落とさなくてもいいかなっていう値段。

ただ、相変わらずケーブルの刻印を見ても何の規格に対応しているのか、さっぱり分からないんだけど…(かろうじて、10って書いてあるから10G...つまりUSB 3.1ってこと?くらい)

f:id:magnoliak:20190531204633j:plain

とにかくUSB Type-Cケーブルは混沌としているので、1.0mを越えない用途であればこのケーブルを買っておけば充電も、周辺機器の接続も間違い無い。そして、ケーブルの刻印が致命的に分かりづらいので、違う規格のものを混ぜないで統一して使った方が良いですね。

MacBookの充電器を追加で買うなら現状Anker一択じゃないかなーって。