TypeScriptは静的型付け言語なのかという話
この辺の話。
静的型付言語は型システムを入れる事で変数への代入や関数適用を禁止する事だと思っているので、any を介して定義とは異なる物を渡せてしまう動作を許してしまっているのに静的と表現するのがモヤモヤする、という意味です。
— mattn (@mattn_jp) August 10, 2022
— mattn (@mattn_jp) August 10, 2022
(中略)動的/静的な型付けと強い/弱い型付けはそれぞれ違う概念な気が。 https://t.co/OhpkXV6U1s
— odz (@odz) August 11, 2022
静的型付の定義は型システムにより型付きの関数引数や変数へ異なる型の値が適用される際にはエラーになる(または警告される)というのが僕の認識なのです。
— mattn (@mattn_jp) August 11, 2022
これ、私はtest
を呼び出す際にany
からの暗黙のキャストが入っているという理解なのですよね。
こういうイメージ。
const test = (f: string) => console.log(typeof f); const foo: any = [1]; test(foo as string);
こういう互換性のないキャストがエラーもなくできてしまうという意味で弱い型付けなのではないかと。
分かるんですけど、TypeScriptでany経由すると型チェックが台無しになるのと、C/C++でvoid *やreinterpret_cast経由で型チェック台無しになるのにさしたる違いは無いような気がします。
— odz (@odz) August 11, 2022
最後書いているように、若干極論ではありますが、C/C++でポインタだとキャストしてしまえばなんでも渡せてしまうよね、という話はありますしね。
#include <iostream> #include <typeinfo> #include <cstdlib> #include <cxxabi.h> static char* buffer = 0; static size_t bufferSize = 0; static const std::string getTypeName(const std::type_info& type) { int status; char* name = abi::__cxa_demangle(type.name(), buffer, &bufferSize, &status); if (name && status == 0) { std::string s(name); buffer = name; return s; } return ""; } __attribute__((destructor)) static void cleanup() { if (buffer) { free(buffer); } } class Foo { public: virtual void method() {} }; class Bar : public Foo {}; class Baz { public: virtual void method() {} }; void test(const Foo* p) { std::cout << getTypeName(typeid(*p)) << std::endl; } int main() { Foo foo; Bar bar; Baz baz; test(&foo); // Foo test(&bar); // Bar test(reinterpret_cast<Foo *>(&baz)); // Baz return 0; }
まぁ、暗黙的にany
からキャストされてしまうTypeScriptと明示的なキャストが必要なC/C++を同列に語るのも乱暴といえば乱暴ではあります。
ただ、いずれにしても他の静的型付け言語で備えているような機能を一部備えていないとしても、TypeScriptの型システムのほとんどは静的なチェックなので、静的型付けと呼ぶしかないような気がします。
C++のdynamic_castやJavaでのダウンキャストは動的な型チェックでもあったりするので、そもそも無理に分類する必要もないんじゃないかという話もありますけど。
「都税クレジットカードお支払いサイト」不正アクセス事件の調査報告書
ざっとしか読んでないですが。
GMO-PG では、2008 年 12 月に最初の PCI DSS 認証を取得し、年次での再認証監査を 8 回経た上で、2016 年 12 月に最新の認証を取得しており、クレジットカード情報 を取扱う事業者として要求されるべき一定レベルの情報セキュリティ体制を具備して いたものの、本件ではそのような体制が Apache Struts 2 の未知の脆弱性を突いたゼロデイ攻撃に対しては、奏功しなかったという事案である。
S2-045は脆弱性情報公開と同時に対策済みバージョンがリリースされているので、そもそもゼロデイ攻撃じゃないよね。8、9ページの時系列の情報の所にもApache Struts 2の対策済みバージョンリリースの情報が出てこないのはミスリードしたいんでしょうかね。
とはいえ、セキュリティ情報提供サービスからのS2-045の情報提供自体が遅いとか危険度情報がないとかかわいそうな感じがしなくもない。大量の脆弱性情報をひとつひとつ精査はしてられないだろうしな。リモートコード実行(RCE)とか書いていたなら、危機感もてよ、という感じもありますが。
Oracle vs Googleのやつ
単純に疑問に思ったことなど。
Androidの非互換性
従来Javaと非互換な実装で、従来Javaのエコシステムが破壊されてんの?私が知らないだけで、今時のJavaライブラリは#ifdefみたいに、VM実装確認してスイッチしたりしてるんだろうか。
Javaと非互換の癖にJava名乗るなみたいな話であれば、それはそれでわかる。
トップレベルパッケージ
Android はまず、名前衝突を避けるために定められたパッケージ名の naming convention を完全に無視し、勝手に android というトップレベル・パッケージ名を宣言しました。
Android以外にもパッケージにドメイン名を入れない例は多い。ぱっと思いつく例だと、Groovyとか、Wekaとか、OpenNLPとか。
OSSなので、組織名入れたくないみたいな、事情はあるかもしれない。だったら、org.androidでいいんじゃね、という気もしますが。
OSSとして
OpenJDKをGPLでリリースしておいて、その一部であるAPIを無断使用として訴えるというのはどゆことだろ。まぁ、AndroidはOpenJDKではなく、Apache Harmonyの派生なので、そんな単純でもないが、Apache Harmonyを放置しておいて、Apache Harmony派生のAndroidだけ訴えるというのは、それこそ道義的にどうなんだ、という気はする。
仮にOpenJDKの派生として作られたら、GPLに従っている限りは文句を言われる筋合いはないはずだよね。
その他
AndroidのString.indexOf が壊れている件はソースを見る限り、Apache Harmonyから引き継いだバグっぽいですね。
git の sha1_to_hex のやつ
すこし調べた。
Linus が普通に Mailing List で明言していた。
Nothing magical, it's just "rounded up from 40 + NUL character".
単に、40バイト+NUL文字用の1バイトで切り上げて50バイトらしい。
が、masterのやつを見たら全然違うので、もう少し歴史を見てみる。
最初のは read-cache.c にあった。initial commitですね。
char * sha1_to_hex(unsigned char *sha1) { static char buffer[50]; static const char hex[] = "0123456789abcdef"; char *buf = buffer; int i; for (i = 0; i < 20; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } return buffer; }
sha1_file.cに移動されたあと、ちゃんと毎回 NUL terminate されるようになる。commitは@1e80e0。
char * sha1_to_hex(const unsigned char *sha1) { static char buffer[50]; static const char hex[] = "0123456789abcdef"; char *buf = buffer; int i; for (i = 0; i < 20; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } *buf = '\0'; return buffer; }
static 領域のアドレスを返すためにエラーメッセージ作るのが面倒だとかそんな感じの文句が出たのか、簡易LRUキャッシュが導入される。commitは@dcb345。
char * sha1_to_hex(const unsigned char *sha1) { static int bufno; static char hexbuffer[4][50]; static const char hex[] = "0123456789abcdef"; char *buffer = hexbuffer[3 & ++bufno], *buf = buffer; int i; for (i = 0; i < 20; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } *buf = '\0'; return buffer; }
さらに hex.c に移動して、マジックナンバーをマクロで置き換え、バッファサイズも変更。commit は @aa1c6f。
char *sha1_to_hex(const unsigned char *sha1) { static int bufno; static char hexbuffer[4][GIT_SHA1_HEXSZ + 1]; static const char hex[] = "0123456789abcdef"; char *buffer = hexbuffer[3 & ++bufno], *buf = buffer; int i; for (i = 0; i < GIT_SHA1_RAWSZ; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } *buf = '\0'; return buffer; }
#define GIT_SHA1_RAWSZ 20 #define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
で、reentrant版の sha1_to_hex_r と非reentrant版のsha1_to_hexに分離して、だいたい今の形になっている。commitは@af49c6。
char *sha1_to_hex_r(char *buffer, const unsigned char *sha1) { static const char hex[] = "0123456789abcdef"; char *buf = buffer; int i; for (i = 0; i < GIT_SHA1_RAWSZ; i++) { unsigned int val = *sha1++; *buf++ = hex[val >> 4]; *buf++ = hex[val & 0xf]; } *buf = '\0'; return buffer; } char *sha1_to_hex(const unsigned char *sha1) { static int bufno; static char hexbuffer[4][GIT_SHA1_HEXSZ + 1]; return sha1_to_hex_r(hexbuffer[3 & ++bufno], sha1); }
こんな小さな関数でも結構変わっているもんですな。
s/20/40/
どうみても、40バイト書いていると思う。
近況
唐突にしばらく都内勤務になった。とりあえず、3月までの期限付きの予定。