final const readonly

値を書き換えるつもりのない変数を宣言することがある。ローカル変数や関数の引数の場合もあれば、メンバ変数の場合もある。
Javaの場合、このような変数を宣言するときにはfinalと書いておくと、コンパイル時にチェックできる*1
C++にもconstという似たものがある。詳しくは触れないけれど、Javafinalより凝った機能を提供している。
さてC#にもきっとJavafinalに相当するものがあるに違いない、そう思ってconstと書いてみたのだが、どうもうまくいかない。
調べてみたところ、C#にはconstのほかにreadonlyがあり、求めていたのはこちらだったようだ。ただし、メンバ変数にしか使えない。
constも値が書き換えられないという点は共通だが、静的に決まる値のみが許されるなど、「定数」としての意味が大きい。

まとめると次のようになる。

final const readonly
Java 変数の書き換え禁止    
C++   変数の書き換え禁止
オブジェクトへのconst操作以外禁止
 
C#   静的な定数 メンバ変数の書き換え禁止

名前から連想する意味にもっとも近いのはC#のものだと思う。ローカル変数にもreadonly使いたいなぁ。

*1:final変数の初期化し忘れ・final変数への代入は、どちらもコンパイルエラーになる。

finallyの中でreturn

Javaのfinallyはよくできていて、tryやcatchの中から抜けるときは必ずfinallyが実行される。

  • tryの中身の最後のステートメントが実行される
  • returnやcatchしてない例外でメソッドごと抜けようとする

という場合にも、必ず実行される。
returnの場合には

  1. まず返値が求められて
  2. その後finallyの中身が実行されて
  3. さっき求めた返値になる

という徹底具合。ちょっとbegin0っぽい?

さて問題。tryの中でreturnして、finallyの中でもreturnしたら、返値はどうなるだろう?

public class FinallyQuiz
{
    static int q() {
        try {
            return 0;
        } finally {
            return 1;
        }
    }
    public static void main(String[] args) {
        System.out.println("return value is " + q());
    }
}

パラメータで受け取った型のインスタンスを生成

C++のTemplateとJavaGenericsを比べるとき、

という話が出てくることがある。

import java.util.Vector;
class Elem
{
}
public class Test
{
    // しかるべき方法で初期化された、要素数nのVector<T>がほしい
    static <T> Vector<T> make_n_vector(int n)
    {
        Vector<T> result = new Vector<T>();
        while (n > 0)
        {
            T elem = new T(); // コンパイルエラー
            result.add(elem);
            n--;
        }
        return result;
    }
    public static void main(String[] args)
    {
        Vector<Elem> v = make_n_vector(10);
    }
}

これがうまくいかない原因は、型パラメータTはコンパイルされた後で消えてしまうため、どのクラスをnewすればいいか分からなくなるという点につきる。
逆に言うと、コンパイルされた後でも消えない方法で型についての情報を渡すだけでうまくいく。

import java.util.Vector;
class Elem
{
}
public class Test2
{
    static <T> Vector<T> make_n_vector(Class<T> elem_class, int n)
    {
        Vector<T> result = new Vector<T>();
        while (n > 0)
        {
            try {
                T elem = elem_class.newInstance(); // これならOK
                result.add(elem);
            }
            catch (IllegalAccessException iae)
            {
                // ここと
            }
            catch (InstantiationException ie)
            {
                // ここに失敗したときの処理
                // この例なら RuntimeException とか AssertionError を投げるのがいいかな?
            }
            n--;
        }
        return result;
    }
    public static void main(String[] args)
    {
        // 呼び出し側で、型パラメータの代わりにクラスリテラルを渡す
        Vector<Elem> v = make_n_vector(Elem.class, 10);
    }
}

2回適用の組み合わせ方

次のような関数daを考える。

(define ((da f) x)
  (f (f x)))

これが何をする関数なのか、日本語での説明を試みよう。

  • fを受け取って、「xを受け取って、xにfを2回適用する関数」を返す関数

「〜を受け取って〜を返す関数」という言い方が入れ子になっていて、ちょっと分かりづらい。
動作例を示そう。

続きを読む

(let (''a) quote)

Schemeの式

  • '1
  • ''1

は、ふつうの環境では以下のように評価される。

gosh> '1
1
gosh> ''1
'1

ところで、'aという式は、読み込まれるとき(quote a)の形に展開される。

だから、'1と書くかわりに(quote 1)と書いても、まったく同じ意味になる。

さてここからが本題。これを別のsyntaxと組み合わせたらどうなるだろう。

次の(ヘンテコな)例をみてほしい。

(let (''a) ;見た目に変なlet
  quote)   ;見た目どこにも出てこないquote

この式はどんな値に評価されるだろうか。

続きを読む