ミシシッピ川以東のルイジアナ

わたしのブログへようこそ!出てけ

ITアルバイトについて

これは何

某IT企業でアルバイトをはじめてしばらく経ったので、どんな感じかレビューをしたいのと、大学生でIT系バイトを検討している人へ少しだけ私見を述べる。

筆者について

念の為軽く自己紹介をしておくと、普段は型推栄かたすいろんと名乗っている、電気通信大学という謎の大学に通うB4である。 専攻はコンピュータサイエンスで、特に型理論や計算可能性理論など計算理論・数学基礎論あたりの分野が専門*1だ。

よってプログラミングがそこまで得意というわけではなく、情報系学生のたしなみという程度の能力しかない。 メインのプログラミング言語というか親だと思っているのはD言語(違う世界線C++みたいな感じ)だが、最近は業務もありもっぱらC++ばかり書いている。

インターンについて

僕は2023年の秋くらいからインターン生として某IT企業で働いている。一応「有償の長期インターン」という名目ではあるが、つまるところアルバイトで、労働契約書にも実際そのように書かれていた。条件としてはこんな感じ。

  • 業務内容:モバイルアプリ開発
  • 労働時間:週20時間弱
  • 時給:1400円*2
  • 通勤時間:2時間弱
  • リモートなし

ということで、月80時間くらい働いて10万円ちょっとの給料をもらっている*3。これは一般的な電通大生としてはかなり働いてる方だと思う*4。 もちろん扶養控除の範囲(いわゆる103万の壁)に収まる訳がないので、超過したことで扶養者に課税された分は僕が払うことになっている。一応勤労学生控除が130万まであるので、上手いことこれを越えないようにはしている。

あまり詳しく書いて職場の人に身バレしたくないし、守秘義務とかに引っ掛かると最悪なのだが、そうでない範疇でここ1年半くらいのことを話そうと思う。

業務内容

今のバイトを始めて以来、僕はモバイルアプリを作る部署にいる。外注ではなく自社プロダクトで、ひたすら一つのアプリをデバッグしたり機能追加したりする仕事である。開発はPMを頂点に数十人のチームで行われていて、僕はその中の一人というわけだ。

とはいえ獅子の子落としが如く入社後すぐに一人で開発に放り込まれたわけではなく、最初は研修ということでC++の勉強とか電卓作りとかをさせられた。その後はメンターに助言をもらったりコードレビューしてもらったりしながら自分でタスクをこなすといった流れだ(今もそんな感じ)。

開発の流れ

先述の通り、仕事の中心にはあるアプリがあって、それに対してデバッグをしたり機能を実装したりという作業が主である。これらはチケットと呼ばれる作業単位で管理されている。

例えば誰かがバグを見つけたら新たにチケットを作成して不具合の内容を記録しておく。それを見たPMによってチケットが誰か(報告者のこともある)にアサインされ、作業者は原因を特定しコードを修正するといった流れである。 他の現場を知らないので確かなことは言えないが、こういった開発方法はそこそこ一般的なようだ。

また修正を行ってもそれが直ちに世の中に出回るわけではない。メインブランチから作業ブランチをフォークして、プルリクエストを作り、修正内容について上級のエンジニアのレビューを受け、指摘箇所を再び修正して……というサイクルを繰り返し、ゴーサインが出ればメインブランチにマージされる。さらにリリース時には部署全体でテストを行い、これを通過することで初めてメインブランチの内容がリリースされるという建て付けである。これもやはり普通の開発フローらしい。

ということで、プログラマとして働いているからといって四六時中プログラムを書けるわけではない。コーディングするにも規約はあるし、上では省略したが開発ブランチへのマージ時には単体テストが必要である。それなりに事務作業もある。

こういうソフトウェア開発の現場について知ることが出来たのは、今のアルバイト先を選んだことで最も得をしたと思っている点だ。現に同じ専攻の卒業生の多くがIT企業に出荷されており、自分も同じ道を辿る可能性は非常に高いので、就職前にどういうものかを知ることができたのは非常に嬉しい(そして同時に自分の耐えうる環境だと知ってほっとしている)。

要求される知識・能力

今のところ、大学で学んだ内容をバリバリ活用するような感じでは全くない。学部1, 2年でやるような数学さえ扱えれば十分である。

むしろアプリ開発ということで、事業のドメイン知識は自分の専攻からはやや離れている。もちろんこれをソフトウェアに落とし込むのが我々の仕事なので、その過程で数学やコンピュータっぽい分析は多分に必要となる。

一方で実務的な能力があまりないので、これが結構キツい。例えば業務では日常的にGitを使う。最初は add, commit, push, pull くらいしか使ったことがなく、rebase とか言われて何のことだか意味不明という具合だった。まあ、しばらく働いていれば少しずつ慣れてくるものではあるが。

職場について

僕が今までにやったアルバイトは小売、塾講師、あと単発で倉庫仕分けくらいだが、それらに比べれば天国のような職場である。座ってお茶を飲みながらパソカタするだけでお金が貰えるし、有休も普通に取れるし、人付き合いも割と上手くいっている。おおむね満足している。

唯一にして特に苦々しく思っている問題点が通勤時間だ。最初に書いた通り、実家からオフィスまでは鉄道で片道2時間弱かかる。僕は朝が非常に苦手なのだが、9時に出勤するためには身支度も合わせると6時半くらいには起きなければならない。しかも使っているのが首都圏屈指の混雑路線なため、朝夕の満員電車にこれだけの時間拘束されるのは正直言って非常に辛い*5。これがリモート勤務可であれば言うことなしなのだが……

これからIT系のアルバイトを探す人へ

僕から言えるのは次のことである。

  • UnixコマンドとGitくらいは覚えたほうがよい
  • マトモな会社なら研修があるので、プログラミングの技能は学生として標準的なレベルなら大丈夫
  • 近場 or リモートに越したことはない

*1:正直全然詳しくはないが、それ以外に専門と呼べるものがない

*2:春からちょっとだけ上がるらしく、嬉しい

*3:実際には何だかんだ用事があり、稼働時間はもう少し短い

*4:弊学生のバイト代は月3〜5万円くらいが平均層だと聞いたことがある

*5:曜日によって勤務時間が違うので毎日ではないが

プラグインのアップデートで skkeleton が使えなくなったら疑うべきこと

これは何?

ハマったので記録です。

TL; DR

以下を確認すること。

  • :checkhealth denops はエラーを吐いていないか
  • Deno のバージョンは要求以上か
  • Neovim のバージョンは要求以上か

説明

上だけ押さえておけば大丈夫そうだが念の為補足しておく。

環境

Neovimのプラグインは自分でもよく把握していないくらいたくさん入っているのだが、関係ありそうなのは

あたりだと思う。あと、SKKの入力切り替えは(多くの人はそうだと思うが)

vim.api.nvim_set_keymap('i', '<C-j>', '<Plug>(skkeleton-enable)', {noremap = true})
vim.api.nvim_set_keymap('c', '<C-j>', '<Plug>(skkeleton-enable)', {noremap = true})
...

のようにして C-j へ割り当てている。

状況

Lazy updateプラグインをアップデートしたら skkeleton が動かなくなった。動かないというのは、具体的には以下のような状況である。

  • 挿入モードへは入れるし、このとき skkeleton_indicator.nvim 由来の「英字」というインジケータが表示されている
  • この状態で C-j を入力すると、C-cを除いて入力を受け付けなくなる。インジケータも消える。
  • C-c によってのみノーマルモードに戻れる。

原因

:checkhealth denops を見たところ、次のようなエラーが出ていた。

- Detected Neovim version: 0.9.5
- ERROR Unsupported Neovim is detected. You need to upgrade it to 0.10.0 or later.

ということでバージョンを上げて解決。

今までは生のアプリイメージをレポジトリから引っ張ってきていたが、面倒なのでHomebrewで管理することにした。 ちなみにaptには4年くらい前のバージョンしかないのでカスである。

その他の原因

類似の症状に陥ることはたまにある。今回のようにNeovimのバージョンが理由だったのは初めてで、今までには次のような原因があった。

  • denops.vim のバージョンが古い
  • Deno のバージョンが古い:この場合、Neovimの起動時に「denopsは無限ループを避けるために停止しました…」みたいなメッセージが出ていた気がする。

よって checkhealth で分からなければ、まずはこの二つを疑うのがよいだろう。

まとめ

そもそも環境のアップグレードは安易にすべきでない(健常者エミュレータの記事)

「hikki氏『愛は地球を救うのか?』を読んで」になるはずだった記事

これは何

本来はhikki氏のnote記事『愛は地球を救うのか?』(以下「原記事」)

https://note.com/hikki0000/n/n48a3d5c1f53fnote.com

および原記事中で引用されているXへのポストと,そこにぶら下がった一連の会話

を読んで思った感想を書く予定だった.だがそのつもりで本稿を書いていたところ,原記事は非公開となった. 取り下げられた文章に対して批評を行うのは自分の望むところではないので,先程まで書いていた内容はお蔵入りになる.

しかし,氏が論理に対してどのような認識を抱いているかという点が原記事から不明瞭にしか読み取れなかったことが気にかかる.そこで本稿は,浅学ながら僕の論理に対する認識を述べた上で,氏はどうであるかを問うための質問状としたい.

論理

「論理」や「論理的」という言葉は頻繁に喧伝されるが,それが指すところを確認したい.まず「論理」と辞書で引くとどう書いてあるだろうか.

1 考えや議論などを進めていく筋道。思考や論証の組み立て。思考の妥当性が保証される法則や形式。「—に飛躍がある」

2 事物の間にある法則的な連関。

3 「論理学」の略。

デジタル大辞泉より)

2はともかく,1と3の関係について考える.1でいう思考や論証のことをまとめて推論と呼びたい.推論とはいくつかの命題からある結論を得るような営みのことである.1の意味での論理とは,この推論のうち「妥当」なものを選んできてやはり「妥当」に組み合わることや,その組み合わせたもののことであるとする.本稿ではこれを人間の論理と呼ぶ*1

ここでは差し当たり次のような構図を信ずる.人間の理性なるモノが備わっていて*2,推論を行ったり推論の妥当性を判定したりすることができる(上記の1).それらを研究・応用するために形式的な規則によって推論を再現する仕組みこそが,数理論理学*3で扱っている形式論理である(上記の3).

では形式論理における推論が人間による推論に全く一致するかというと,この問題には一考の余地がある.そもそも形式論理の体系はいくつも考えられていて,それぞれ妥当な推論の範疇が異なる.最も一般的(標準的)な体系は古典論理と呼ばれるもので*4,古くからの暗黙的合意形成によって妥当とされる推論の再現である.僕が知る限り,数学基礎論を除いた大抵の数学的議論はこの古典論理に基づいて記述することができる.だがそれ以外の体系は単に実験的な目的で定義されたのではなく,いくつかは哲学的に「正しい」と信じられる妥当性の基準*5を再現するためのものである.

また,形式論理の推論と人間による推論の妥当性がどのように一致するかもより詳しく考えよう.論理体系には意味論と証明論が考えられる.意味論は(多くは集合論的な道具によって)論理式の解釈を与えるもので,人間による推論のモデル化になっている.証明論はそこから一歩離れてより機械的な演繹によって推論を定義する.そしてよく知られるような性質のよい体系においては,意味論によって妥当と判定される推論と証明論によるそれは互いに一致する.詳しくは健全性と完全性について調べるとよい.

要約するとこのようになる.形式論理の体系は人間の論理の再現であって,誤解の余地がないよう明確に記述されている.さらにある前提の元ではある体系における妥当な推論と人間の推論が一致するので,人間の推論で述べられるべき現実的問題について体系上の推論で議論できる.だがその前提が常に採用されるとは限らず,今のところそういった社会的共通認識もないので,全ての現実的問題に使える銀の弾丸のような形式論理の体系はない.

とりもなおさず,甚だ身も蓋もない話ではあるが何もかも前提次第ということになる.前提が個々人によって違えばどれだけ論理的であっても個別の論理により推論される帰結は単なる個人の感想でしかなく,前提を共有することではじめて複数の人間が同じ帰結を得ることができる.

ここにはもちろん全ての人間の理性が同様の推論を与えるという了解があるが,僕はそれすらも怪しいと感じている.種々の論理を眺めていると,我々が真に普遍的であると認めることのできる推論の形式は,モーダス・ポネンス*6くらいしかないのではないだろうか.

(究極的には全ての主張は個人の感想であって,原記事も本稿もこれらを読んだ読者諸氏の意見も,「全ての主張は個人の感想である」というこの言明すらも感想に過ぎないだろう.しかしそれだけでは埒が明かないから,その中でどのように合意を形成してどのような前提を共有するかこそ,社会の構成や建設的議論には重要であろうと考えていることを申し添えておく.)

したがって論理的であるための要件は常に提示されるべきである.いや,日常生活やビジネスにおける「ロジカルシンキング」とかいう場面において,そういう話をする必要はないだろう.しかし哲学的姿勢を掲げており,その上で論理的であるか否かを問うのであれば,その場合の論理とは何であるか明示しないのはフェアでない.

これは別に,形式論理のように堅苦しく記号的に定義を述べよということを意味せず,議論の前提を共有せよということに過ぎない.それもなく自他に対して論理的である,論理的でないとラベリングをするのはナンセンスである.

件のポストについて

また,このポストで行われている論証には些かギャップがある.

命題  P は「女子枠の導入に賛同(今の状態は差別の結果)」と書かれているが,この括弧書きが意味するところが不明瞭に思われる.おそらく「女子枠の導入に賛同している」と「今の状態は差別の結果である」という2つの命題が同値である(よって同一視してよい)という意図であろうが,そう考えてもやはり

  1. 「賛同する」とは何か? ある人物Aについて「Aは女子枠の導入に賛同している」とも取れるし,「女子枠は導入されるべきである」という義務の主張にも解釈できる.
  2. これらは本当に同値か?

という疑問は解消されない.ここでは前者については問わず,また同値であることも認めるとして,命題を

  •  P' :今の状態は差別の結果である

と書き換える.その上で

  • not  P' : 今の状態は自由意志の結果である

 \lnot P' の「今の状態は差別の結果でない」と本当に一致するのかもやはり明らかでない.もちろん  Q にも同様の疑問がある.

齟齬が生じた原因は「賛同する」とか「結果である」とか「差別」「自由意志」のような言葉の定義が不十分であることであって,もちろんより厳密に定義すれば解消されるのかもしれないが,そもそも形式論理によってこの問題を扱おうこと自体ナンセンスに思える.

元を正せば件のポスト自体が(氏いわく)実験的試みであって,その仔細ないし女子枠に関する議論自体が彼の興味の範疇にないのかもしれないし,だとすればこれらの指摘は全く的外れということになる.とはいえ私は興味があるので,できれば上記について氏の教授を得たいものである.

*1:メタ論理とも呼べるかもしれないが,一般的な用法とはズレるように感じる.どうなんだろう.

*2:これは理性でなくてもよくて,常識でも観念でもちくわ大明神でも,ともかくそういう働きをする概念があればよい.

*3:数理論理学というのは形式論理学記号論理学のほぼ同義語であるが,論理学には非形式論理学と呼ばれる分野もあって,今回の場合に適用するにはこちらの方が好ましいのかもしれない.ただ僕はこの分野について全くと言ってよいほど知らない.

*4:もちろん古典論理と一口に言っても古典的な一階命題論理とか一階述語論理とか,具体的な体系は色々ある.

*5:すなわち,古典論理が立脚する標準的な基準は正しくないという立場である.

*6:前件肯定 (modus ponens).「Aである」「AならばBである」という2つの前提から「Bである」という結論を得る推論のこと.

日本語との別れ

これは何

日記です。

近況報告

ちょっと前に入試を受けたばかりだと思っていたのだが、何もせずうだうだしているうちに気がつけば大学生活も4年目ということで、めでたく4年生進級&研究室配属と相成った。

僕の専攻は一応計算機科学ということになっているのだが、僕が元々やりたかったのは数理論理学や公理的集合論といった計算機どこやねん*1分野で、数値計算系の研究室が主である電通大にはそういうことを学べる場所があまりないので、割と進路が迷子になりつつあった。

そんなこんなで最終的に配属された研究室は組み合わせ最適化を看板に掲げてはいるものの、全然違うことをしている人もいるのでよくわからない。僕はというと最近は型理論 (type theory) に興味があって、何だかんだ計算機寄りの分野に戻ってきた形だ。卒業研究もこれについてできればいいなと思いつつ教科書や論文を読み漁っている。

消える日本語

そんな話をして何を言いたいかというと、研究活動を始めてから英語を読む機会が非常に多くなったということである。世の技術者や研究者は日常的に英語を用いているというので、そんなものなのだろうが。

型理論の鉄板本に B. C. Pierce "Types and Programming Languages" というものがあり、『型システム入門 プログラミング言語と型の理論』(オーム社)という題名で和訳もされている。

mitpress.mit.edu

www.ohmsha.co.jp

しかし現在は絶版で、ブックオフくらいでしか調べてはいないが中古本もなかなか手に入らず、今から読もうとすると電子書籍を買わざるを得ない。しかしこれが中々に高い(原著で$95*2、和訳ですら7000円近くする)こともあって本書は避け、代わりにネットを漁って H. Geuvers*3 "Introduction to Type Theory" を見つけた。

https://www.cs.ru.nl/~herman/onderwijs/provingwithCA/paper-lncs.pdf

査読論文や出版社の書籍ではなく、著者がウルグアイだかで行った講演の講義ノートだ。もちろん全文英語で、機械翻訳に突っ込んでも微妙なものしか出力されなかったので、諦めて最初から原文で読むことにした。

本稿で主に扱っているのは単純型、多相型、依存型あたりの話題で、後半二つはそこまで詳しく解説されているわけではない。他の体系も知りたいのでどちらにせよ他の資料も並行して読まなければならないのだが、インターネッツに転がっているのは大体英語で書かれた記事である。 例えば特に気になっているのがModal Type Theoryであるが、ネットで検索しても日本語の情報が全く出てこないので、仕方なくnLabの記事を眺めている。

ncatlab.org

結果として最近の僕は今までの人生でダントツに英語を読んでいる。元々英語は非常に苦手であり、文法まで含めてちゃんと読もうとすると時間が掛かって仕方ないのだが、特徴的な単語だけ拾っていけば意外とスラスラ進むものだ(教科書や技術文書の殆どを構成するテクニカルタームは視覚的に目立ちやすく、かつ一つの意味しか持たないことが多いので楽である。逆に日常会話のような内容は多義語が多く、文構造をちゃんと考えないといけないので全然わからない)。

すると自分でも驚いたことに、次第にそれらの単語を英語”そのまま”に思考し、解釈するようになってきた。この感覚を言葉で正確に表現することは難しいが、例えば『型付け』*4という概念を非言語的にぼんやりと考えるとして、そこから「型付け」でなく "typing" という単語が即座に想起されたり、もしくは思考領域へのラベリングに用いられるというイメージである。そのことを自覚した僕は薄ら寒さを感じた。

言語的相対論

言語的相対論は言語が思考を決定づける*5と考える理論のことで、特に20世紀前半に盛んに扱われた。同世紀後半にはチョムスキー生成文法の立場から批判を浴びるようになるが、言語学認知科学については全然詳しくないのでそうした議論は考えない。

例えば交通信号機における進めの灯火は「青信号」と呼ばれることが多いが、大抵の場合青信号は緑に近い色をしている。これは日本語における「青」の指す範囲が広いことに起因しており、我々日本人は緑色のものもなお広義の青色の範疇として自然に認める(青葉、青海苔、青虫など)。同じような文化は中国語やベトナム語にもあるらしいが、少なくとも英語圏では一般的でなく、青信号は "green light" と呼ばれる。 逆に英語は我々が単に「牛」と呼ぶものに対しても(明らかに形態素的にそれぞれ独立した)多くの語彙を持ち、雌牛は "cow" で雄牛は "bull" だし、牛肉は "beef" である。

こうした違いはもちろん各々の言語が話されてきた地域の歴史的経緯に影響を受けたものであるが、そうした背景情報を知らなかったとしても、日本語話者が青色だと思う灯火を英語話者が同じ様に青色だと思うことはない。

そしてこの論によれば、僕の思考が捉える世界もやはり思考に用いる言語によって異なることになる。今は技術的議論の一部が英語に置き換えられたに過ぎないが、もし将来的に僕が日常会話から仕事まで全てのコミュニケーションを日本語でない言語で行うようになったとしたら、その僕はもはや日本語で思考する僕とは別の人間と言っても近しいのではないか。

日本語への愛着

上記のような話とは別に、僕は単純に日本語に愛着を持っている。曲がりなりにも僕の母語であるし、僕の家族や友人らの母語であるし、二十余年来育ってきた日本の(事実上の)公用語であり、今までほとんどの場面において日本語で学問をしてきたからである。

駄々をこねてもどうにかなる問題ではないが、今さら英語で学問をするというのは正直とても癪に障る。

自己防衛、投資、あと海外移住、日本脱出

とはいえ何事も国際化が叫ばれる昨今、かつ社会保障や労働問題の将来について希望の持てない情報を連日流し込まれる我々にとって、日本国外での生活ないし少なくとも日本語を主としない生活を全く考えないことは不可能である。

あ〜〜〜〜〜〜〜超好景気でアホほど仕事があって日本語が公用語の国ができねえかなぁ〜〜〜〜〜〜〜〜〜〜

*1:もちろん近くはあるのだが

*2:円安がカスすぎる

*3:Radboud Universityというオランダの大学にいるらしい

*4:ある体系における項(ラムダ式など)について、各々の文脈における型を付与すること

*5:あるいはウォーフのより弱い表現を借りれば、思考の習性を与える

unique_ptrのメンバをnullptrで初期化する必要はない

はじめに

初歩的なミスだが、かなりハマったので念のため残しておく。

環境

C++14を前提に話を進めるが、恐らくそれ以降のC++でも状況は変わっていないと思われる。

$ g++ --version
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

TL;DR

std::unique_ptrインスタンスの宣言時、 unique_ptr<T> hoge = nullptr のように初期化すると代入演算子reset() を呼び出すので T の定義をインクルードしなければならない。

hoge をメンバに持つクラスの定義ヘッダなど、余計なインクルードをしたくないときには unique_ptr<T> hoge; だけでも同様に初期化される。

解説

経緯

今回詰まったのは次のような状況だった。

/* Hoge.h */
#ifndef HOGE_H
#define HOGE_H

#include <iostream>

class Hoge {
protected:
    int x = 0;
public:
    Hoge(int x_) {
        std::cout << "Hoge::Hoge()" << std::endl;
        x = x_;
    }

    void printX() const {
        std::cout << "Hoge::x = " << x << std::endl;
    }
};

#endif
/* Fuga.h */
#ifndef FUGA_H
#define FUGA_H

#include <memory>
class Hoge;

class Fuga {
protected:
    std::unique_ptr<Hoge> hoge = nullptr;
public:
    Fuga();
    ~Fuga();
    void func();
};

#endif
/* Fuga.cpp */
#include <iostream>
#include <memory>
#include "Hoge.h"
#include "Fuga.h"

Fuga::Fuga() {
    std::cout << "Fuga::Fuga()" << std::endl;
}

Fuga::~Fuga() {}

void Fuga::func() {
    hoge = std::make_unique<Hoge>(100);
    hoge->printX();
}
/* main.cpp */
#include "Fuga.h"

int main() {
    Fuga fuga;
    fuga.func();

    return 0;
}

Fuga.h では Hoge の具体的な実装を知っている必要はないので、 Hoge.h をインクルードする代わりに Hoge の前方宣言を行っている。

しかしこれをコンパイルしようとすると、「Hogeのサイズがわからんが?」とunique_ptrのデストラクタからお叱りが飛んでくる。

$ g++ -std=c++14 main.cpp Fuga.cpp -o unique  
In file included from /usr/include/c++/9/memory:80,
                 from Fuga.h:4,
                 from main.cpp:1:
/usr/include/c++/9/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Hoge]’:
/usr/include/c++/9/bits/unique_ptr.h:292:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Hoge; _Dp = std::default_delete<Hoge>]’
Fuga.h:9:34:   required from here
/usr/include/c++/9/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘Hoge’
   79 |  static_assert(sizeof(_Tp)>0,
      |   

もちろん Fuga.h#include "Hoge.h" すれば解決はするが、こんなにバカバカしい話はない。

原因は代入演算子

このエラーは、Fuga.h における hoge の宣言を次のように訂正することで解消される。

std::unique_ptr<Hoge> hoge;

コンパイラのエラーを読むと発生箇所がデストラクタになっているので分かりづらいが、実は原因は unique_ptr::~unique_ptr() でなく unique_ptr::operator=() 側にある。

/* unique_ptr.h */

// 中略

/// Reset the %unique_ptr to empty, invoking the deleter if necessary.
unique_ptr&
operator=(nullptr_t) noexcept
{
    reset();
    return *this;
}

ということで、代入時にreset()が呼ばれるのが原因であった*1

C++標準化文書にもある通り、普通に constexpr unique_ptr() noexcept が呼ばれた場合でも中身は nullptr となる*2。よってわざわざ = nullptr と書かなくてもnullチェックには問題ないし、むしろしないほうがよい。

timsong-cpp.github.io

$ g++ -std=c++14 main.cpp Fuga.cpp -o unique 
$ ./unique 
Fuga::Fuga()
Hoge::Hoge()
Hoge::x = 100

はい。

デストラクタの定義場所

ところでerror: invalid application of ‘sizeof’ to incomplete typeググるとデストラクタの宣言をヘッダに、定義をソースに書けという内容がヒットする。

実際これは正しい情報で、上のコードからデストラクタを削除するとやはり同様のコンパイルエラーが発生する。 fuga が破棄されるとき ~unique_ptr() が呼ばれるが、~Fuga() がソース側で定義されていない(デフォルトデストラクタ含む)とヘッダ側で Hoge の型情報が必要になるということであろう。

おわりに

今回の問題はインターン先の開発中に遭遇した出来事で、実は原因を教えてくれたのも自分ではなく某先輩である。ここでも改めて感謝申し上げる。

業務内容に直接関わりのある話ではないので大丈夫だとは思うが、もし万に一つでもお叱りを受けた場合には本稿は削除する。

*1:上の内容は nullptr の場合だが、他の引数でも reset() は呼び出される。

*2:文書には "Constructs a unique_ptr object that owns nothing,..." としか書かれていないが、get() が nullptr.get_deleter() と等価になるのは保証されている。

bashからzshに乗り換え

はじめに

環境構築シリーズです。前回↓

jj1lis.hatenablog.com

Neovim がいい感じになったので、次は bash から zsh に乗り換えます。

きっかけ

今のところ自宅環境は万物が bash 前提で構築されているのだが、バイト先では色々あり zsh を使っている。bash とは10年弱を共に過ごした仲(?)なので思い入れがないわけではないが、設定が共通でないと何かと不便であるからこの際 zsh に移行する。

環境

$ cat /etc/lsb-release 
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=20
DISTRIB_CODENAME=ulyana
DISTRIB_DESCRIPTION="Linux Mint 20 Ulyana"
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

こうしてみると bash 古いな(ここのところ毎回のように言ってる気がする)。

zsh

そもそも zsh (Z SHell) とは Brian Fox が1990年に開発したコマンドシェルの一つで、1989年に公開された bash と地味にタメを張る大御所シェルである。

www.zsh.org

有名どころのシェルの機能を全て備えた上でいろいろと追加されており、bash に比べると多機能なシェルということになっている。

インストール

とりあえず、兎にも角にも本体がないと話にならない。

$ sudo apt install zsh

ここでいきなりログインシェルを zsh にしてもいいのだが、流石に使いづらいので先に.zshrcの方をある程度整えておきたい。

.zshrc

bash でいうところの .bashrc のように、zsh も対話シェル起動時には .zshrc を読む。

結論から言うとこんな感じになった。

github.com

これを期に整えたりしたが、基本的には bash の内容そのままで問題ない。ただ、プロンプトだけは zsh の記法が使えるので使っていきたい。

プロンプト

bash環境変数 $PS1 でプロンプト(シェルで入力するときに出てる user@hostname: ~ $ みたいなアレ)の見た目を変更できたが、zsh では$PROMPTで設定できる。上のリンク先ではここにあたる。

PROMPT="%B%F{red}%n%f%F{green}@%M%f: %F{blue}%~ \$%f%b "

$PROMPT に指定した文字列がプロンプトになるのだが、一部の情報はパラメータを使って動的に表示できる。上に書いたものでいうと

パラメータ 内容
%n ユーザ名
%M ホスト名
`%~ カレントディレクト

など。またHTMLのタグのように %X...%x と書いて囲った内部の文字列の体裁を変えるものもある。

パラメータ 内容
%B...%b 太字
%F{color}...%f color色に着色

他にもいろいろあるので、詳しくは勝手に調べてほしい。

ちなみに bash のときは同じ内容を設定しようと思うと PS1="\[\e[1;31m\]\u\[\e[1;32m\]@\H\[\e[1;37m\]:\[\e[1;34m\]\w $\[\e[m\]" のように最悪の可読性だったのだが、 zsh は随分と読みやすくて感動した。

sheldon

sheldonBash/Zsh 対応のプラグインマネージャである。

github.com

インストール

Homebrew があれば brew install sheldon でいけるのだが、ないので Cargo を使う。

$ rustup update stable
$ cargo install sheldon

セットアップ

sheldon の設定は ${XDG_CONFIG_HOME}/sheldon/plugins.toml で行う。以下のように、sheldon init で使いたいシェルに応じて(といっても変数の値がちょっと違うだけだけど)plugins.tomlを生成してくれる。

$ sheldon init --shell zsh
Initialize new config file `~/.config/sheldon/plugins.toml`? [y/N] y
Initialized ~/.config/sheldon/plugins.toml
# `sheldon` configuration file
# ----------------------------
#
# You can modify this file directly or you can use one of the following
# `sheldon` commands which are provided to assist in editing the config file:
#
# - `sheldon add` to add a new plugin to the config file
# - `sheldon edit` to open up the config file in the default editor
# - `sheldon remove` to remove a plugin from the config file
#
# See the documentation for more https://github.com/rossmacarthur/sheldon#readme

shell = "zsh"

[plugins]

# For example:
#
# [plugins.base16]
# github = "chriskempson/base16-shell"

一番下にbase16を入れる用例が載っているが、このように

[plugins.<plugin>]
github = "<repo>"

の要領で追記しておくことで自動的にプラグインをインストールしてくれる。

とりあえず鉄板の zsh-autocomplete を入れておく。

[plugins.zsh-autocomplete]
github = "marlonrichert/zsh-autocomplete"

sheldon はこれらのプラグインを適用するスクリプトsheldon sourceで吐き出す。

$ sheldon source
source "/home/jj1lis/.local/share/sheldon/repos/github.com/marlonrichert/zsh-autocomplete/zsh-autocomplete.plugin.zsh"

よって、 .zshrc にでもeval "$(sheldon sourece)" と書いておけば、起動時にプラグインを有効化できる。

$ zsh
Loaded ~/.config/sheldon/plugins.toml
    Cloned https://github.com/marlonrichert/zsh-autocomplete
Locked ~/.local/share/sheldon/plugins.lock

入れたプラグイン

とりあえず列挙するので、詳細はリンク先を見ていただきたい。

zsh-autocomplete

github.com

プロンプトに文字列を入力するとファイルやコマンド、オプションなどを表示してくれたり、コマンド履歴から候補を持ってきて補完したりしてくれる。便利。

zsh-syntax-highlighting

github.com

コマンドは緑、ファイルは下線、文字列は黄色など、入力した文字列に色をつけてくれる。存在しないコマンド名は赤色になるので typo に気づきやすい。便利。

zsh-z

github.com

行ったことのあるディレクトリを記憶しておいて、ちゃんと指定しなくても高速で移動してくれる。

例えば最近行った ~/hoge/fuga/foo/bar/xxx/yyy/zzz/somedir というディレクトリに戻りたいとき、 z somedir と打つと一発で飛ぶことができる。何なら z some のような入力でも気を利かせて移動してくれる。便利。

該当するディレクトリが複数あるときは頻度や一致度から適当に選ばれるっぽい。一応候補は下に出るので自分で選ぶこともできる。

セットアップスクリプト

前回の Neovim と併せて、自動でセットアップを行うシェルスクリプトを書いた。

github.com

環境構築が楽ちんでとてもよい。

おわりに

僕の土日はdotfiles盆栽で消えました゜