Magnolia Tech

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

「Anker Nano II 65W」を購入 - 最小の65W対応のUSB PD充電器

発売前に予約していた「Anker Nano II 65W」が届きました。普段Appleの純正61Wの充電器を持ち歩いていて、それ一つでPCもタブレットスマホもカバーしていましたが、さすがに大きさがちょっと不満でした。

「Anker Nano II 65W」は、Ankerの新しいUSB PDの充電器シリーズ。

AnkerのUSB PD充電器、あまりに種類が多いし、同時期に似たような機種がリリースされているので分かりづらいけど、Nano IIシリーズが出て「とりあえず自分の機器のスペックに合わせて買っておけ」って言えるようになったかも。

65W版の出力は以下の通り、スマホからタブレット、PCまでこの小ささでカバーしてくれます。

5.0V=3.0A / 9.0V=3.0A / 15.0V=3.0A / 20.0V=3.25A (最大 65W)

ちなみに、使っているとそれなりに発熱はするので、設置場所は気をつけた方が良いと思います。

このサイズなら、持ち運ぶ充電器を切り替えることができそうです。

ちなみに、7/23現在、65W版は売り切れですが、45W版と30W版は在庫が有ります。

とりあえず、2021年7月現在で、USB PD充電器を選ぶ時に迷ったらこれを買っておけば良さそうです。


相変わらずUSB PD、充電器の出力側はスペックがそれなりに書かれているのに、特にPC側はどの入力に対応しているのか分からない機種が多いのは変わらないですね...手元のDellのPC、今年のモデルでもどれが充足しているのかさっぱり分かりません。低い出力の充電器に繋ぐと「低出力」ってだけ教えてくれるんですけどね...

あと、USB Type-Cケーブルは相変わらず混沌としているのでThunderbolt3ケーブルか、Thunderbolt4ケーブルを買っておくのがおすすめなのは変わらないですね...

以下の記事も参考にしてみてください。

blog.magnolia.tech

blog.magnolia.tech

Scalaの識別子(クラス名、メソッド名、変数名)に使える文字・使えない文字

Scalaでは、クラス名、メソッド名、変数名などの「識別子」に漢字・ひらがな・カタカナが使えます。

scala> val 変数 = 42
val 変数: Int = 42

scala> def 引数を倍にするメソッド(引数: Int): Int = 引数 * 2
def 引数を倍にするメソッド(引数: Int): Int

scala> val 答え = 引数を倍にするメソッド(変数)
val 答え: Int = 84

でも意外と使えない文字が有ります。

scala> val 質問・回答 = "しつもん・かいとう"
1 |val 質問・回答 = "しつもん・かいとう"
  |      ^
  |      illegal character '\u30fb'
1 |val 質問・回答 = "しつもん・かいとう"
  |                       ^
  |                       expression expected but eof found

scala> val 𠮷野家 = "よしのや"
1 |val 𠮷野家 = "よしのや"
  |    ^
  |    illegal character '\ud842'
1 |val 𠮷野家 = "よしのや"
  |     ^
  |     illegal character '\udfb7'
1 |val 𠮷野家 = "よしのや"
  |                 ^
  |                 '=' expected, but eof found

1つ目は、"・(中黒)"が使われています。

2つ目は、”𠮷野家"の1文字目が"吉"ではなく"𠮷"になっています(看板の通りですね)。

識別子に使える文字は?

Scalaコンパイラは、識別子に使える文字を、JavaCharacter.isUnicodeIdentifierStartと、Character.isUnicodeIdentifierPartを使って判定しています。

文字通りStartが1文字目を判定し、Partが2文字目以降を判定するのに使われます。

ドキュメントから少し引用してみましょう。

Character.isUnicodeIdentifierStart

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Character.html#isUnicodeIdentifierStart(char)

  • isLetter(codePoint) returns true
  • getType(codePoint) returns LETTER_NUMBER. Note: This method cannot handle supplementary characters. To support all Unicode characters, including supplementary characters, use the isUnicodeIdentifierStart(int) method.

isLetterJavaのCharacterクラスが提供するメソッドで、以下の文字が対象となります。

  • UPPERCASE_LETTER
  • LOWERCASE_LETTER
  • TITLECASE_LETTER
  • MODIFIER_LETTER
  • OTHER_LETTER

つまり、UnicodeのCategoryにおける6種類の属性を持つものが利用できることが分かります。漢字やひらがな、カタカナ等はほとんど対応しますね。

また、Scalaでは、記号のみから成る識別子を特別扱いしていて、Character.isUnicodeIdentifierStartの判定とは別に特定のASCII記号と、Unicodeの「Symbol, Other」「Symbol, Math」に該当する記号のみから成る識別子を許可しています。

例えば、以下の変数名は有効です(絵文字は「Symbol, Other」に該当する)。

scala> val ☃️ = "ゆきだるま"
val ☃: String = ゆきだるま

そして、最後に大事なことが書かれていますね。そう、Character.isUnicodeIdentifierStartにはcharを引数に取るものと、intを引数に取るものの2種類があり、charを引数に取る方ではUnicodesupplementary charactersがサポートされていないのです。

Character.isUnicodeIdentifierPart

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Character.html#isUnicodeIdentifierPart(char)

次に、Character.isUnicodeIdentifierPartを見てみましょう。

  • it is a letter
  • it is a connecting punctuation character (such as '_')
  • it is a digit
  • it is a numeric letter (such as a Roman numeral character)
  • it is a combining mark
  • it is a non-spacing mark
  • isIdentifierIgnorable returns true for this character. Note: This method cannot handle supplementary characters. To support all Unicode characters, including supplementary characters, use the isUnicodeIdentifierPart(int) method.

少し使える文字が増えました。数字やアンダースコアや、が増えているのがわかるかと思います。

ただ、表記方法が違うので分かりづらいですが、Character.isUnicodeIdentifierStartで使える文字は全て使えます。

そして、やはり引数にcharを取る方では、supplementary charactersがサポートされていません。

なぜ使えないか?

中点(なかぐろ)

https://www.compart.com/en/unicode/U+30FB

こちらを参照すると分かりますが、Unicodeのカテゴリが「Other Punctuation」になっているためです。

𠮷野家

𠮷野家の「𠮷」は「Supplementary Ideographic Plane」に属しています。

https://www.compart.com/en/unicode/U+20BB7

なので、現在の実装では正しく判定できません。

Scalaコンパイラサロゲートペア文字を正しく認識し、BMP(Basic Multilingual Plane)以外の文字も識別子として扱えるようになればいいのですが。

同様の理由で、Unicodeの絵文字群のうち、かなりの文字が「supplementary characters」なので、識別子として使えません。先程の☃️は使えましたが、顔文字はダメですね。

scala> val  😂 = "泣いて笑って"
1 |val  😂 = "泣いて笑って"
  |     ^
  |     illegal character '\ud83d'
1 |val  😂 = "泣いて笑って"
  |      ^
  |      illegal character '\ude02'
1 |val  😂 = "泣いて笑って"
  |                 ^
  |                 '=' expected, but eof found

というタイミングで、Scala2に「supplementary characters」を使えるようにするPRが作られました。

Accept supplementary characters by som-snytt · Pull Request #9687 · scala/scala · GitHub

Scala3にもポートされることが期待されています。

早く使えるようになるといいですね!

文字コードへの理解

絵文字の普及でBMP以外の面のサポートがだいぶ進みましたが、まだまだ意外なところでサポートが進んでいないことがわかりますね。

BMPとか、supplementary charactersについて知りたい方は、下記の本がおすすめです。全部書いてあります。

『ITと数学』、その切っても切れない関係

初めてコンピュータサイエンスを学ぶとき、「コンピュータサイエンスは、つまりは統計だから」と言われた。今考えるとそれは必ずしも当たっている訳でもないけど、遠くもなかった。


コンピュータの原理の裏にはたくさんの数学の概念が潜んでいる。学校で習う高等数学、果たして何に役に立つのか?と疑問に思ったら、この過去のSoftware Design誌の数学に関する記事をまとめた『ITと数学』を読むのがお勧め。

そんなに分厚くもないし、値段もそこまで高くは無いので、自分が学ぼうとしていることがどんな意味があるのかわかることで、学習意欲も高くなるはず。

そういえば、つい先日もSEGAがゲーム制作に必要な数学の知識を解説するスライドを公開したばかりだ。

techblog.sega.jp

世界は数学に溢れている


個人的には、機械学習に普段あまり触れることはないけど、第3章の「数学プログラミング入門」がお気に入り。

あと、表紙がとにかく優勝

Scala 2.13対応の『Scala スケーラブルプログラミング 第4版』は、全Scala使いが買うべき一冊

Scalaの言語設計者であるMartin Odersky著『Scala スケーラブルプログラミング 第4版』が出版された。今回はScala 2.13対応ということで、全面的に書き直されたコレクションクラスに対応するための改版。

基本的な構成は前の版と変わらず、基本的な文法からオブジェクト指向関数型プログラミングまで一通り解説されていて、言語仕様を知るには必須の1冊。最初から最後までを読み切る、というよりは気になった言語仕様を知りたい時にまず開くと、だいたい答えが書いている、という期待で読む本(分厚いし)。

関数型プログラミング言語の解説書だけど、「モナド」のような概念的にちょっと理解が難しい要素は全然出てこないところも良い(モナドという用語も、全編を通してオマケ的に1回しか出てこない)。

あくまでプログラミング言語機能の解説書として、淡々と機能が解説されていく構成になっている。

ただ、言語解説書なので、この本で「Scalaに入門する」のはなかなかハードだし、テスティングフレームワークは一部触れられているが、sbtなどのツールチェーンの解説は無いし、WAFの解説もない(その代わり、なぜかデスクトップアプリケーションとしてのGUIプログラミングの解説は、ある)ので、その辺りを知りたい場合は物足りないかも。

入門者の方はまずは『Scala研修テキスト』や、『実践Scala入門』から入ると良いでしょう。

scala-text.github.io


また、原著の方はもうすぐScala3に対応した第5版が出版されます。こちらも翻訳されることを祈って、皆さんまずは第4版の日本語版を買いましょう!

オライリーから出ているScala本もScala3のリリースに合わせてアップデート、もうすぐ出版されます。こちらも期待。


文中で一点気になったところと言えば、124ページの脚注の演算子識別子の記載。

より正確に言えば、演算子文字は、Unicodeの数学記号(Sm)やその他記号(So)、英数字、括弧、角括弧、中括弧、シングル/ダブルクォート、アンダースコア、ピリオド、カンマ、バッククォート文字以外の7ビットASCII文字である。

この記載だと、演算子識別子には「Unicodeの数学記号(Sm)と、その他記号(So)が含まれない」と読めてしまうが、実際には利用可能です。これはつい最近まで公式ドキュメントのSyntax Summaryの記載が誤っていて、そのまま引用されているよう。

つい先日それを修正するPRを書いて、取り込まれましたところ。

github.com

現在公開されているドキュメントでは、元の分かりづらい記述ではなく、「使える文字を列挙する」形式に改められた。

www.scala-lang.org


初めてScalaを知って、『Programming in Scala』の初版の原著を買ったのは10年前だった気がする。Perlの次に覚える言語としてなぜScalaに興味をもったのか、そのきっかけはさっぱり覚えていないけど、Scala3のリリースなど、今でも活発に開発が続いているし、DDD界隈での評価も有る。当時思ったほどの普及はしていない気もするけど、所謂ギョームアプリケーションを書くには良い言語なのは変わらないんじゃないかと。

『[改訂新版]プログラマのための文字コード技術入門』...いつ役立つか分からないからとりあえず買っておいて損の無い一冊

”基礎技術”系の本には、いつ役立つか分からないからとりあえず買っておいて損の無い一冊、というのが有って、この『[改訂新版]プログラマのための文字コード技術入門』もそんな1冊。

文字コード周り、基礎を学んでいないと「文字集合」と「符号化方法」の区別できなかったり、「全角文字」とか「2バイト文字」のようなあやふや言い回しをして間違った設計をしてしまうことになる。

特に本書では基本的な文字コード周りの技術から、プログラミング言語での扱い方とか、ハマりやすい落とし穴(Unicodeの正規化とか)もしっかりフォローされているので、「とりあえず手元にあることの安心感」が半端ないです。

仕様と、実装、その間にあるもの

妙に時間をかけてしまって一つのPRを書いた。

Fixed Syntax Summary by magnolia-k · Pull Request #9666 · scala/scala · GitHub

Scalaの文法概要の記載が正確ではない(過去の修正で誤りが混入した)箇所を直すものだ。

他の誤りも無いかと確認する過程で、upper(大文字)の定義と、lower(小文字)の定義を読み取るのに非常に苦労した。

Syntax Summary | Scala 2.13

ただ、よく読むと分かるが、結局大文字も小文字もletter(文字)に集約されてしまい、構文上の区別は無い(大文字と小文字が使える箇所に差はない)。

また、実装上もJavaCharacter.isUnicodeIdentifierStartや、Character.isUnicodeIdentifierPartを使って判定されているが、結局どちらも大文字と小文字による分岐は存在しない。

つまり、仕様は複雑(大文字と、小文字を細かくパターン分け)な割りに、実装は非常にシンプルになっている。かと言って何か仕様に反した実装がされているわけでもない。仕様を満たすように正しく実装されている。

(UnicodeOther_Lowercaseというプロパティがどうのこうの...と出てくる割に、実装上はどこにも出てこないので不思議に思っていた)


このように、仕様は複雑だけど、パターンを読み切って実装は実にシンプルにまとまっている事例というのは案外いろんなところに存在する。だからといって、「仕様」を「実装」に合わせて描き直してはいけない。

仕様は仕様であり、実装は実装だからだ。

この仕様が拡張された時、やはりその複雑さに合わせてコードを書き直さないといけない時だってくるかもしれない。仕様はあくまで当初の意図がしっかり残っていなければいけないし、実装はそれを満たさなければいけないけど、完全に一致している必要もまたない。

それが将来に良い結果をもたらすかもしれないし、悪い結果をもたらすかもしれない。

技巧的に走りすぎたコードが良いとは限らないけど、それでも実装の効率性や、将来の拡張性を考えた時に、必ずしも仕様の字面通りのコードがベストであるとも限らない。

一方で確実に読み取りづらくなるのも事実で、そこに何らかの意図をコメント等で残しておかないと後世の人は混乱するだけかもしれない。

'仕様と、実装、その間にあるもの'…コードを書く人はその距離をコントロールしていかないといけないし、その距離が有るという事実を理解しないといけないのです。

そしてコードを書かない人が発するいつものセリフ...「こんな簡単な仕様を実装するのになんでそんなにかかるの?」という疑問に答えていかないといけないのです。


あ、仕様を満たしていない実装はとにかくダメですね、それはダメです。

ダメなんだけど、いつの間にか「バグも仕様」になってしまう時もあるので、話がさらにややこしくなるけどね!

Vimの正規表現でのUnicode周りのこと

  • ファイルがUTF-8で作成されていても、\uxxxx形式のコードポイントで検索できる(UTF-8のコードポイントではないのは何故だろう?)
  • [^\x00-\x7F]でもUTF-8の2バイト以上の文字にマッチさせられる
  • iskeywordの範囲じゃ無いのに、UTF-8の2バイト以上の文字がワード境界として認識される
  • Unicode Categoryに対する検索条件は設定できない