SML# - Java Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

''Java/SML#''を使えば、 SML# から Java オブジェクトを操作することができる。

次のJavaコードは、HTTP経由でデータを取得している。
  
  import java.net.*;
  import java.io.*;
  
  public class HTTPGet
  {
    static PrintStream out = System.out;
  
    public static void main(String args[])
    {
      try{
        URL url = new URL("http://www.pllab.riec.tohoku.ac.jp/smlsharp/");
        URLConnection connection = url.openConnection();
        InputStream inStream = connection.getInputStream();
        BufferedReader input =
          new BufferedReader(new InputStreamReader(inStream));
  
        while (input.ready()){
          out.println(input.readLine());
        }
      }
      catch(IOException e){
        out.println(e.toString());
      }
      catch(Exception e){
        e.printStackTrace();
      }
    }
  }

このJavaコードとおなじ処理を、SML#では次のように書ける。

  open java.lang;
  open java.io;
  open java.net;
  
  structure HTTPGet =
  struct
    val out = PrintStream(System.get'out())
  
    fun main(args) =
        let
          val url =
              URL.new'String(SOME "http://www.pllab.riec.tohoku.ac.jp/smlsharp/")
          val connection = URLConnection($url#openConnection())
          val inStream = InputStream($connection#getInputStream())
          val input =
              BufferedReader.new'Reader
                  ($$(InputStreamReader.new'InputStream($$inStream)))
        in
          while $input#ready()
          do
            $out#println'String ($input#readLine())
        end
          handle Java.JavaException throwable =>
                 if IOException.isInstance throwable
                 then
                   $out#println'String ($(IOException(throwable))#toString())
                 else
                   $(Exception(throwable))#printStackTrace();
  end;

!!!インスタンス生成
クラスのインスタンスを生成するには、各クラスにnewあるいはnew'で始まる名前の関数として定義されたコンストラクタを呼び出す。
  URL.new'String(SOME "http://www.pllab.riec.tohoku.ac.jp/smlsharp/")
この例はURLクラスのインスタンスを生成する。
newのあとの'Stringは、オーバーロードされたコンストラクタを区別するためのもの。
また、SML#のstringをJavaのjava.lang.Stringへの参照として渡せることにも注目。null参照を渡すにはNONEを指定する。

!!!インスタンスメンバーアクセス
インスタンスメソッドの呼び出しは
  Java.call [インスタンス] #[メソッド名] 引数
という形式になる。
上の例では
  val $ = Java.call
と定義した$をつかって
  $url#openConnection()
のように呼んでいる。

オーバーロードされたメソッドを呼び出すには
  $out#println'String ($input#readLine())
このprintlnメソッドのように、引数の型を含めた名前を指定する必要がある。

インスタンスフィールドの読み書きには、
  get'[フィールド名]
  set'[フィールド名]
という名前で定義されたアクセサメソッドを使用する。

!!!クラスメンバーアクセス
クラスメソッド(staticメソッド)は
  [クラス名].[メソッド名] 引数
という形式で呼び出す。

クラスフィールド(staticフィールド)の読み書きは
  [クラス名].get' [フィールド名] ()
  [クラス名].set' [フィールド名] 引数
という形式になる。
  System.get'out()
この例はSystemクラスのoutフィールドを取り出している。

!!!インスタンスとオブジェクト参照
JavaとStandard MLの型システムの相違のため、現在のJava/SML#インタフェイスでは、Javaオブジェクトへの参照を二通りに使い分ける必要がある。
これを ''インスタンス'' と ''オブジェクト参照'' と呼んでいる。
  type ('members, 'classes) instance
  type Object
''インスタンス''はクラスの型情報を持つが、''オブジェクト参照'' は持たない。

クラスのコンストラクタはインスタンスを返す。
インスタンスメソッドを呼び出す際には型情報が必要なのでインスタンスをつかう。

メソッドへの引数やメソッドからの返り値はオブジェクト参照である。

インスタンスをメソッドへの引数として渡す際には、Java.referenceOf をつかってオブジェクト参照に変換する。
上の例では、
  val $$ = Java.referenceOf
と定義された$$を使っている。
  InputStreamReader.new'InputStream($$inStream)

オブジェクト参照をインスタンスに変換するには''キャスト関数''を使う。
キャスト関数は、クラスと同じ名前で定義されている。
  val out = PrintStream(System.get'out())
これは、System.get'outが返すオブジェクト参照を、PrintStreamクラスのインスタンスに変換している。

!!!例外処理
MLコードから呼び出されたJavaメソッドが例外をthrowすると、Java/SML#は、Java.JavaException例外をMLコードにraiseする。

Javaでは、例外のクラスにもとづいて例外ハンドラが自動的に選択される。
しかしMLでは
  handle Java.JavaException throwable =>
         if IOException.isInstance throwable
         then (IOExceptionに対する例外ハンドラ)
         else (その他の例外に対する例外ハンドラ)
のように手動で例外のクラスを判定して例外ハンドラを決定する手間が必要になる。

!!詳細情報
*[[Overview|http://www.pllab.riec.tohoku.ac.jp/smlsharp/tools/Java/README.txt]]
*[[API|http://www.pllab.riec.tohoku.ac.jp/smlsharp/tools/Java/doc/api/]]