小さな問題を分からないといい続けないでさっさと目の前の問題を解けという声が聞こえる。
続きを読むC++: 本日のハマり
class A { public: int id = 0; }; class B : public A { public: B() : id(100) {} };
これエラーになる。この辺よくわかってなかった。
hoge.cpp: In constructor ‘B::B()’: hoge.cpp:7:9: error: class ‘B’ does not have any field named ‘id’ B() : id(100) {} ^
B() : id(100) {}
はダメなのでB() { id = 100 }
でOKだった。よく分からんね。
本題はここから。以下のようなプログラムはA
と出力する。
#include <iostream> class A { public: std::string s = "A"; A(); virtual ~A(); }; A::A(){} A::~A(){} class B : public A { public: std::string s = "B"; B() : s("hoge") {} ~B() override = default; }; int main () { A a = B(); std::cout << a.s; return 0; }
気づくのに1時間くらいかかってしまった。
プログラミング: 今日の問題
プログラミングの問題。なんか全然綺麗にかけなかったので記事にする。
続きを読むきつね: キツネ村にいくぞ!!!
keenさんと話していたやつ
- キツネ村にいくぞ(唯一無二の目的) http://zao-fox-village.com/
- キツネなんだからLLVMじゃね?開発合宿やるか
- 直近の知り合い2ホイップくらいで旅行にいきたいですねーーー
- 3月にやります、知り合いっぽい人は声かけるので是非ご参加下さい
- 東北大学工学部の最終講義もある(3/9、外山先生が退官される)
やること
- 日程決め(3/9から2泊にするか)
- インターネットがあって小会議室が予約できるホテル(蔵王の近くで)
- 好きそうな知り合いに声をかける
C++: 返り値として自分自身を返すメソッドにshared_ptrを使う
#include <vector> #include <memory> #include <utility> class A { public: int x; A(int x) : x(x) {} std::shared_ptr<A> f() { return std::shared_ptr<A>(this); } }; int main() { auto a = std::shared_ptr<A>(new A(123)); auto v = std::vector<std::shared_ptr<A>>(); v.push_back(a->f()); v.push_back(a->f()); return v.size(); }
*** Error in
./a.out': free(): invalid pointer: 0x00007ffcc80eb1cc ***`という素敵なメッセージとともに異常終了する。
それはアブナイのでstd::enable_shared_from_thisを継承した上でshared_from_thisして下さい
— 秋津早苗 (@akitsu_sanae) 2018年1月29日
教えていただいた方法で試してみる。
#include <vector> #include <memory> #include <utility> class A : public std::enable_shared_from_this<A> { public: int x; A(int x) : x(x) {} std::shared_ptr<A> f() { return shared_from_this(); } }; int main() { auto a = std::make_shared<A>(A(123)); auto v = std::vector<std::shared_ptr<A>>(); v.push_back(a->f()); v.push_back(a->f()); return v.size(); }
これは正常に終了する。めでたしめでたし。
ただしこれ、必ずthisがshared_ptrにより管理されていなければならず、そうでない場合にはエラーが発生するっぽいのでなかなかこわい。
例えば上の例ならばmainの中にauto b = new A(256); b->f();
という行があったならば、
terminate called after throwing an instance of 'std::bad_weak_ptr' what(): bad_weak_ptr
といってしんでしまう。
OCaml: 型変数の雑い話
これはMLアドベントカレンダーの1日目の記事です。 今年で3年目のアドベントカレンダーですが、あまり埋めるということは意識せず、MLユーザが記事を書いてワイワイするという目的でやっていければいいな、という感じです。
1日目なのでゆるくOCamlコンパイラの型周りの実装の話をしたいと思います。 最近あまり体調が良くなく、小ネタみたいな形です(すみません)。 どこかで喋った覚えもあるので聞いたことがある人がいたらすみません。
OCamlでは型変数は基本的に整数のid
で表されています。
それにレベルという概念を導入して、どのネストのletで導入された型変数なのかをわかるようにしている、というのは以前書いたとおりです。
また型変数がgeneralizeされているかどうを表すためにも利用されていて、Btype.generic_level = 100000000
と定義されています。まぁ常識的にこの深さのネストとかやらんやろということで再利用しているんだと思います。
気になるのは、型変数をid
という形で整数で表してしまうと、idが衝突するのではないのかということです。例えばcmi
ファイルからロードする際に他のファイルから型をインポートするときに混じったりということが考えられます。
この手の情報は手軽に見ることができます。compiler-libs
さまさまです。
utop
かなにかで読み込んで、プリティープリントさせてみましょう。
// 前やったときはできたと思うんですが、なんか今はできませんでした。 // utopまわりで色々変わったのかもしれません、すみません
utop[0]> #require "compiler-libs";; utop[1]> read_cmi
これを見ると、cmiの世界の中では型変数のidはマイナスの数になっていることがわかります。
これを自分たちの、いまコンパイルしようとしている世界にむけてidを差し替えます。それには型とかモジュールを表すデータ構造をあれそれ置き換えるためのモジュールSubst
を利用します。
Subst.typexp: Subst.t -> Types.type_expr -> Types.type_expr
は型を表すデータ構造をトラバースして、型変数を見つけたら置き換える関数です.
(* Similar to [Ctype.nondep_type_rec]. *) let rec typexp s ty = let ty = repr ty in match ty.desc with Tvar _ | Tunivar _ as desc -> if s.for_saving || ty.id < 0 then let ty' = if s.for_saving then newpersty (norm desc) else newty2 ty.level desc in save_desc ty desc; ty.desc <- Tsubst ty'; ty' else ty ......
idが負であれば何やら怪しい方法でコピーしています。
for_saving
は普通の場合ではfalse
です。
ちなみにこのfor_saving
というのはこの逆で、型変数のid
を外に書き出したりするときにtrue
になる変数です。newpersty
がid
を負になるように置き換えます。
上のようなことが起きるのは、下の関数の中身くらいでです。
read_signature read_pers_struct acknowledge_pers_struct components_of_module'
ちなみにOcamlコンパイラの中身ではモジュールの並び順的にあとのモジュールに入っている関数を利用するために関数のref
みたいなものをたくさん作っており、'
がつくものはその印です。
読んでみた感想なのですが、OCamlの型検査周りの実装というのは本当に複雑で、色々手に終えないです。型付けのためのデータ構造が効率のため一時的にしか現れないはずもの(Tlink, Tsubst
など)、といったものなどもありかなり複雑で、やはり関数型言語で書けば可読性が上がるなどといった話は嘘なんだなと強く確信がもてます(この手の話では関数型言語はHaskell、それもGHCしか指さないという話もありますが)。
気づいたらocaml/typing
の中に素敵なことにHACKING.adoc
というファイルができていました。
https://github.com/ocaml/ocaml/blob/trunk/typing/HACKING.adoc
これは本当に素晴らしいことで、突然開発者が交通事故にあっても大丈夫なようにOSSといえども実装をドキュメントとして残していく必要があります。 ソースコードに全て書いてあるなどと言うのは開発者の怠慢で後で読む人に一生懸命考古学させる、ドキュメントを書きましょう。。。
最後に今年の振り返りですが、今年のOCaml活動はコンパイラの同人誌をOCamlで書いたこと・ML勉強会を一応開催できたことは良かったです。 あまり最近OCamlをかけていないのですが、来年度はドンドンやっていきたいと思います!
nomaddo.booth.pm ml-lang.connpass.com
次はポケバさん@pocketberserkerさんです。
一般の話: 技術書典3で追記部分
技術書典3お疲れ様でした!
取り急ぎ、今回入稿した文の修正分についてお知らせします。
今回入稿したデータが間違っていたのか、印刷所が間違えたのか、私の追記部分が抜けて落ちております。
そのため最適化の部分だけPDFをアップロードしますので是非御覧ください。
電子書籍版では既にアップロード済みです。