競プロer視点のV言語について軽くしゃべる

初見さんは初めまして、わーはやです。

この間、AtCoderでV言語のLanguage Ownerになったので、今回はV言語について思ったことをおしゃべりします。 やったー

V言語の特徴

特徴というか似ている言語が主に3つあります。

まず、Rustに似ています。型に厳密なので、習いたての頃はこれに苦しめられ、AtCoderのA問題を解くだけでもINF回CEを吐きました。Option型/Result型があったり、型の束縛や変数を変更する時にmutを用いたりするのも似ている点に上げられます(これがある言語をあまり知らない)。また、この言語特有の型のルールがあります。例えば、配列のインデックスにはint型(Rustだとusize)を入れないといけません。

次に、Pythonに似ています。splitメソッドがあったり、import文があったり、import文をasで省略できたり、似ている点がいくつかあります。また、main関数を省略してPythonっぽく書くこともできます。math.bigモジュールを使えば、多倍長整数も使えます。(使用感はJavaのBigIntegerの方が似ているかも)

最後にGoに似ています。変数宣言をする時に:=を使うのですが、Goでもこれを用います。また構造体の見た目も非常に似ており、構造体のコンストラクタがない点や、new関数、構造体のメソッドの作り方はほぼGoのそれと酷似しています。なので、UnionFindのライブラリはほぼGoのやつをパクった。

まあこんなところでしょうか。RustとPythonとGoのキメラとでも思ってもらえればいいと思います多分。

V言語の書き方

これを読みましょう。

github.com

英語が読みたくない方はこれを読みましょう。大体書いてあります。

qiita.com

V言語の良い所

速い!

AtCoder ProblemsVirtual ContestsでよくABCなにかに出てそこでVの練習をすることが多いのですが、昔の問題を解いていると、いつの間にかFAを取ることがあります。そのくらい速いです。

簡単!

型変換やキャストが簡単です。

a:='23'
println(a.int()+3// 26
mut b:=i64(0)
b+=100000000000000
println(b)  // 100000000000000

シンタックスハイライトがついていますが、Goのものを使っています。 Vのやつがないので。

結構直感的に書けるので一回リファレンスを見れば、書き方を忘れても大体書けます。

また、構造体の演算子を作るのが簡単です。

struct Modint {
    num i64
    mod i64
}
fn (a Modint)+(b Modint) Modint {
    assert a.mod==b.mod
    m:=a.mod
    mut x:=if a.num>=m{a.num-m} else{a.num}
    y:=if b.num>=m{b.num-m} else{b.num}
    x+=y
    return Modint{
        num: if x>=m{x-m} else{x}
        mod: m
    }
}

+しか作っていないですが、内部では+=も作ってくれています。偉い。

また、この言語、比較演算子を2つ作るとその他の比較演算子を自動で作ってくれます。すごい。

こんな感じで書くのが簡単で速い静的型付け言語といった所感です。

V言語の悪い所

速くて簡単というだけでかなり良いと思っていたのですが、ここなんとかしてくれ、が多く見られました。

データ構造が乏しい

V言語のデータ構造でよく使うものに、map(だけbuiltinのところにある), Set, Queue, Stack, MinHeapなどがあります。 なお、mapとSetはハッシュマップ、ハッシュセット(std::unordered_map, std::unordered_set)なので、キーに構造体を入れることができません。 ここでC++と比べるとmap, set, dequeがありません。この3つはよく使うので使えないのが結構辛いです。 しかし、幸いなことにdequeはDoublyLinkedListでなんとかごまかせます。ただし、ランダムアクセスを要求されると死んでしまいます。

謎のTLE, MLE

事の発端はABC314 - D POWER。 提出コードがこちら。

atcoder.jp

map::clearがクリアできてなくね、となり無限に奮闘していました。 この問題はmap::clearの部分を初期化に割り当てることでACしました。(そのかわりメモリがとんでもないことに)

このように内部構造がどうなっているのか私もよくわかっていないですが、C++で書いたコードをVに書き換えるだけで普通にTLEしたりMLEしたりすることがあります。

データ構造も正直言って信用できるデータ構造がSetくらいしかないです。助けてくれ。

AC

atcoder.jp

WA

atcoder.jp

まあこの言語、AtCoderのバージョンが0.4.0なので結構ガバガバな所もあるのかもしれないです。 いずれリリースされるバージョン1のVが待ち遠しいです。

AtCoder側のバージョン

現状、Vの最新のバージョンが0.4.2です。一方、AtCoder側の環境が0.4.0なので使える標準ライブラリに少し差異があります。 使えないのはarray::sortedarrays::uniqなど。 なくても困ることはあまりないですが、自分の環境とAtCoderの環境との差でたまにCEが発生します。

atcoder.jp

C++erが気を付けること

私はC++erなので、Vのlower_bound, upper_boundなどの二分探索系の関数の返り値には驚きました。C++std::lower_boundstd::upper_boundは条件を満たす最初のイテレーターを返しますが、Vのlower_bound, upper_boundは条件を満たす値を返します。

また、binary_searchの方もstd::binary_searchと挙動が違って値を返すので注意してください。値が存在しないとエラー文を返します。(値がないことを  O(\log N) で判別したいとき面倒)

最後に

変な言語を使う必要はありません。C++を使いましょう。

追記

今はない。