Open
8

JVMで動くRustっぽい言語のアイデア

JVMというGC前提の環境においては自前のメモリプールやoff-heapメモリを使わない限りは所有権ベースのメモリ管理を模倣する必要がないわけだが、GCが関与しないファイルハンドル等のリソース管理については所有権という仕組みが有用。
RustはRefCellとかあるんで、mutはどちらかというと安全性のためのものだと思いますが、JVMベース言語においては可変性を明示することによる設計上のメリットのほうがありそう。
所有権に比べるとトリビアルな話としては、struct A{}struct (A) があるやつとか enum 、パターンマッチで{a, b, ..}によるフィールドの部分マッチができる等が便利。

静的に解決されるtraitというのは必要だろうか?(サブタイピングと相性悪そう)
具体化されるタイプのgenericsは有用。

ぜんぶ静的に解決してやろうという思想は大変かっこよいが、動的なメソッド解決が一級市民であるJVMにそれを持ち込むとバランスが難しそう。しかしsubtypingを捨てるとJVMらしさが……

  • プリミティブの値型: int, boolean, ...
  • 不変な参照型: String, ...
  • 可変な参照型: String[], ...
  • リソースを表現する参照型: FileInputStream, ...

大部分は非リソース型なので、Tと書けばプリミティブ/通常の参照型を指すとして、リソース型はmove T/&T/&mut Tと表記する。とか。

fn string_array_len(arr: String[]) -> int = arr.len()

fn string_array_set(arr: mut String[], i: int, value: String) {
  ar[i] = value
}

fn read_all(fis: move FileInputStream) -> byte[] {
  fie.readAll()
  // fis.close() called automatically.
}

fn read_some(fis: &mut FileInputStream) -> byte[] {
  // ...
}

struct + trait + class + interface + type classがあると最強っぽい。OCamlのような強いモジュールシステムがあるとさらに良いが、その方面にはいま興味がないので……

Rustが想定する過酷な環境においては、静的に解決される呼び出しとvtable経由の呼び出しを明示的に区別したいという要求があったわけだが、JVM言語においてそこまでは必要なさそう(記法は統一し、可能なときはコンパイラが裏で最適化すればよい)。ただgenericsの特殊化を入れる場合は考慮する必要があるか?

ウーム

// Error: FIS is "owned class"  beacuse it implements AutoCloseable
new FileInputStream("a")
// OK
new own FileInputStream("a")
enum own? Option<+T: ?Own> {
  Some(T), None
}
impl Option<T> {
  fn map<U: ?Own, F: FnOnce(T) -> U>(self, f: F) {
    self.match { None => None, Some(t) => Some(f(t)) }
  }
}

fn read_file(file: Option<String>) {
  let ifs: own Option<own FileInputStream> = file.map { f => new own FileInputStream(f) }
  let reader =  ifs.map { a => new own InputStreamReader(a) }
  // ifs is unusable here
  reader.map { r => r.read() }
  // Call reader.close() implicitly
}

fn make_reader(is: own InputStream) {
  new own InputStreamReader(is)
}

// if T <: U, own T <: own U
make_reader(new own FileInputStream("foo"))

fn read_byte(is: &mut InputStream) { is.read_byte() }
read_byte(&mut is)
extern own class InputStream {
  fn close(self);
}

let is = new own FileInputStream("foo")

// all extern methods are unsafe unless extern type definition available
unsafe { is.read() }

is.close()
// `is` unusable here

Scalaのvarlet mut x: &mut T相当、vallet x: &mut T相当。

Rustだと&mut Tに対して*ref = another_valueできるが、JVMでこれをやるのは無理がある(オーバーヘッドを許容すればいけるが……)

C++のconst参照的なもののほうがJVMには合っている。

ログインするとコメントできます