[nim]Ruby使いがnimを使いだしてハマったポイント

広告

元々Rubyを使っていた私が、処理速度の向上を目指してnimという言語を使っていろいろ試しています

当たり前ですが、言語の違いによる戸惑いがあります。日本語のドキュメントもあまりないこともあり、基本中の基本も含めハマったポイント(エラーメッセージ中心に)を整理しておきます

SIGSEGV: Illegal storage access.

「SIGSEGV: Illegal storage access.(Attempt to read from nil?)」

このエラーメッセージを見て、nil値を読み込む処理をしているつもりはなかったのですが、結果としては対象変数の初期化が必要だっただけでした

エラーが起きたコードは、以下のようなコードでした

type
  Xmlloader* =ref object of RootObj
    filename*:string #読み込むファイル名
    company_name*:string #劇団名
proc load*(xl:Xmlloader):string {.discardable.} =
  xl.company_name.add("test")

上記のモジュール(簡略しています)をunittestモジュールから実行すると以下のようなメッセージがでます

xmlloader.nim(15)        load
SIGSEGV: Illegal storage access. (Attempt to read from nil?)

xmlloader.nimの15行目とは「xl.company_name.add(“test”)」の行にあたります

addする前に一度、初期化が必要でした(rubyでも同様なのですが、ちょっとエラーメッセージに惑わされました

以下のように一度空文字を代入することで対応できました

type
  Xmlloader* =ref object of RootObj
    filename*:string #読み込むファイル名
    company_name*:string #劇団名
proc load*(xl:Xmlloader):string {.discardable.} =
  xl.company_name=""
  xl.company_name.add("test")

first type mismatch at

このエラーは、引数のタイプミスマッチという形でエラーになりました
当初、引数のタイプは一致しておりかなり悩みましたが、そもそも第一引数には、(nimでクラスっぽくtypeを使うなら)対象オブジェクトを入れるということが抜けていたのが原因でした
以下のような演劇の公演(Show)の集合を扱うモジュールを書きました

type
  Shows* =ref object of RootObj
    show_seq*:seq[Show] #公演の配列

#Showのidを指定して、該当するShowを取得する
proc getbyid*(id:string): Show =
(以下略)

getbyidプロシジャは、Showのプロパティとして設定しているidという文字列をキーにShowを取得しようとしています

以下のようなテストコード(一部)でテストを実行しました

  
 test "showidでshowを特定する":
    var s:Show
    s=shows.getbyid("test2")
    check(s.title=="テスト2")

すると以下のようなメッセージが表示されます

type mismatch: got 
but expected one of: 
proc getbyid(id: string): string
  first type mismatch at position: 1
  required type: string
  but expression 'shows' is of type: Shows

主に英語力の問題で、最初の「type mismatch:got Shows,string」の部分しか読んでおらず、第一引数としてstring文字列を渡してるのに、なんでShowsを要求されているのかわけが分かりませんでした

しかし、nimの言語仕様は以下のようになっています

プロシジャー(引数1,引数2,…)は、引数1.プロシジャー(引数2,…)と記述できる

僕自身は、この言語仕様を読んだ時に、引数1.プロシジャーという書き方が、メソッドの書き方っぽくて良いなと思い、typeをクラスとして利用する一方で、procをメソッドっぽく書く方法に統一して書いていたのですが、そのくせでprocの定義にも第一引数として設定すべきtypeを設定していなかったのが原因です

上記のコードの「s=shows.getybid(“test2″)」は、nimの本来の記述の仕方に翻訳すると「s=getbyid(shows,”test2”)」となります

当然に、procの定義も、「proc getbyid(shows:Shows,id:string)」と第一引数に、Showsを定義しておく必要がありました

type
  Shows* =ref object of RootObj
    show_seq*:seq[Show] #公演の配列

#Showのidを指定して、該当するShowを取得する
proc getbyid*(s:Shows,id:string): Show =

上記のように、定義部分を変更することで対応できました

invalid indentation

これも、ハマりました。名前の通り「indentation」つまり、インデントがダメなんだと思ってその行のインデントを何度も入力しなおしました
半角スペース2個がインデントのルールなのですが、それがタブや全角スペースになっていないかを確認したり、
nimはpython同様にインデントが文法に組み込まれている為、そこに意識が終いってしまったのですが、このエラーメッセージの場合大概問題があるのは、その前の行です

  
  if s.count==0
    for x in s.show_seq:
    s.count=s.count+1

上記のようなコードの場合、2行目の「for x in s.show_seq」の行を指して以下のようなエラーメッセージが出ます

show_test.nim(2, 5) Error: invalid indentation

しかし問題なのは、その前の行の文末に「:」がついてないこと

  
  if s.count==0:
    for x in s.show_seq:
    s.count=s.count+1

このif文やcase文の中で条件分岐を書く際に、最後に:が必要というのが抜けがちでちょくちょく同じエラーに苦しまされています

以上 ruby使いがnimを利用する時にハマったポイントでした(多分まだまだ続く)
ちなみに、インストールから、unittestできるところまでは以下の記事にまとめました

広告

コメントを残す

メールアドレスが公開されることはありません。