(-> % read write unlearn)

My writings on this area are my own delusion

Uncaught TypeError: {(intermediate value)} is not a function

次の Javascript (HTMLだけど)は実行時エラーになります。なぜか分かりますか?

<!DOCTYPE html>
<html>
<body>
<script>
const a = { b: 'c' }
(async () => {
  console.log('hello')
})()
</script>
</body>
</html>

const a = { b: 'c' } の末尾にセミコロン ; が無いからです。 { b: 'c' } という名前の関数を呼び出していると解釈されてしまったわけです。 (async ...) の即時実行関数(IIFE)の丸括弧が引数の指定のように捉えられて。

この本で、次のようなイディオムをよく書くのですが のところのセミコロン漏れではまってしまいました。

let importObject = {
  js: {
    foo: function () {
      // ...
    }
  }
}; // ★

(async () => {
  let obj = await WebAssembly.instantiateStreaming(
    fetch('bar.wasm'), importObject);
  baz = obj.instance.exports.baz;
})();

なぜ冒頭のサンプルコードは JS だけじゃなくて HTML とインラインの JS だったか。 答え(?)は、生 JS を書いていれば Prettier のサポートで自動でセミコロンが補完されていてこんなミスしなかったから、という私の実行環境の都合を反映しています。

ちなみに厳密には問題の JS コードを Prettier のフォーマットにかけると次のようになりセミコロンは補完されません。されませんが、十分問題の所在には気付けてそうです。

const a = { b: "c" }(async () => {
  console.log("hello");
})();

似たようなミスしてる人は結構いますね。

~/.config/git/ignore や ~/.gitignore_global にフォルダ名を書くときは foo/* も検討する

例えば .vscode 内の設定は個人的な設定も含めて独自に色々いじるので基本的に常に ignore しておきたいとする。 そういうとき次のようなファイルにグローバルな設定を書いておくことがよくある。

  • ~/.config/git/ignore
  • ~/.gitignore_global

(ちなみに、 git はデフォルトで ~/.config/git/ignore を認識するそう。なので、~/.config/git/ignore を積極的に使おう。参考: ~/.gitignore_global を指定するのをやめ、デフォルトの置き場に置こう

ここで上記 ignore ファイルに

.vscode/

のように書くと、個別のワークスペースリポジトリ内で、部分的にその設定を打ち消す(つまり ignore しないようにする)ということができなくなる。

.vscode/*

としておくと、個別のワークスペースリポジトリ内の .gitignore 内で

!/.vscode/foo.json

とすることで foo.json だけはコミットできるように設定を上書きできる。

正確には、設定が上書きできること自体は Global 設定か否かには関係ない。 ただ、グローバルな設定をサブフォルダや個別リポジトリで上書き不可なのは厄介な場合がけっこうある気がする。

参考

Clojure 開発に VSCode の Code Spell Checker を使う

VSCodeClojure 開発を行っている人向け

背景

VSCodeClojure 開発をしているなら Calva を使っていると思う。 Calva は clojure-lsp も使っており、 clojure-lsp には clj-kondo が入っている。 cljstyle も同様なので、デフォルトで clj-kondo の Lint と cljstyle による Format の恩恵を受けている。

しかし、静的な型付けがない Clojure ではちょっとしたスペルミスや Typo によるエラーでそれに気づかず時間を使ってしまうということがある(自分だけだったらごめんなさい)。 もちろん、静的な型付けのある言語でも Typo ではまることはあるので Clojure や動的型付けの言語に限った話ではまったくない。 Spec や Schema を使えばいいというのもそのとおりで、それで解決する部分もある。 ただ、すべてにしっかり Spec 書いてるかというとそんなことないはず。(自分だけだったらごめんなさい)

というわけでスペルチェックを入れた。

インストール

まずは エクステンションを VSCode にインストール。

設定

1.Clojure に対する有効化とグローバルなユーザ辞書ファイル

settings.json

{
// ...省略...

  // Clojure にも有効にする
  "cSpell.enableFiletypes": [
    "clojure"
  ],
  // .clj だけでなく Clojurescript などのファイルも対象にする。 .clj と同じ扱いになる。
  "cSpell.overrides": [
    {
      "filename": "**/{*.cljs,*.cljc,*.edn}",
      "languageId": "clj"
    }
  ],
  // 「Spell: Add Words to User Settings」コマンドで辞書に単語を追加するとここに追加されていく
  "cSpell.userWords": [
  ],
  // この settings.json 内に単語直接追加していくと邪魔なので、辞書を独立したファイルに分離する設定。パスやファイル名は好きにどうぞ。
  "cSpell.customUserDictionaries": [
    {
      "name": "Custom",
      "description": "My custom user dictionary",
      "path": "~/.config/cSpell/cSpellCustomUserDictionary.txt",
      "addWords": true
    }
  ]
}

defn や defmethod など、普通にビルトインのマクロや関数も怒られるのでがんがん辞書追加する必要がある。 辞書への追加はコマンドパレットから

Spell: Add Words to User Settings

でできるが、その場合 settings.jsoncSpell.userWords にインラインで直接どんどん追加されていくので量が増えると邪魔。 なので cSpell.customUserDictionaries 設定を作って、

Spell: Add Words to User Dictionally

を使って単語の追加を行っていくことをおすすめします。

ここまでは、全ワークスペースに対して有効になるユーザ辞書の設定。

2.ワークスペース・オンリーの辞書ファイル

ワークスペース直下にワークスペース限定の設定を .vscode/settings.json として置くことができる。

.vscode/settings.json

{
  "cSpell.enableFiletypes": [
    "clojure"
  ],
  "cSpell.overrides": [
    {
      "filename": "**/{*.cljs,*.cljc,*.edn}",
      "languageId": "clj"
    }
  ],
  // Spell: Add Words to Workspace Settings」コマンドを使うとここに登録されていく。
  "cSpell.words": [
    "reitit" // <- 例
  ]
}

こんな感じにして、gitignore しないようにしておけば、チームで設定を共有することもできる。 さっきと同様にこの辞書を独立したファイルに分離することも設定可能。

defn とかビルトインの関数やマクロはグローバルなユーザ辞書でいいけど、ライブラリの名前やその関数やマクロはワークスペースの辞書に入れて分けるというやり方も考えられる。 そうしておくと、リポジトリを初めてチェックアウトしてきたときに辞書内の単語一覧を見ればどういったライブラリや関数が使わているのか一気に分かって面白い( shadow-cljs.edn や project.clj を見ればだいたい同じだろ、というのはある)。 そこにはプロジェクトのユビキタス言語から Derive した特殊な英単語や変数名などが入ってくることもあり、そのプロジェクトの特徴をある側面から抽出した情報に見えて楽しい。

辞書の単語で1つづつループしてワークスペース内のソースコードすべてを grep し登場回数を数えて集計すると、さらに面白いよ。

また、辞書ファイルを git blame すると、このライブラリ(あるいは関数)を初めにこのリポジトリに導入したのは 〜〜 さんか、とかこの人はどんどん新しいものを取り入れているな、という傾向が分かってやっぱりなんだか楽しい。