Scala

色々ブログを見ていたらScalaすごいということに気がついた。単なる関数型言語など勉強している場合ではないと思った。Cleanの記事をさらっと勉強して早急にScalaに取り組まなくては。以下Wikipediaを見てすごいと思った点。

  • オブジェクト指向関数型言語、手続き型のマルチパラダイム
  • JVM上で動作し、既存のJavaプログラムと容易に連携可能
  • Java.NET Frameworkの豊富なライブラリが使える
  • メインはJavaプラットフォームであるが、他も.NET Framework、また携帯電話で使われている
  • 静的型付け関数型言語のため、開発生産性が非常に高い
  • 型(クラス)をJavaなどと比べてより容易に作ることができ、型に積極的な意味を持たせてのプログラミングが可能
  • 既存のクラスを拡張したような記述が可能(Smalltalk的な要素?)
  • スケーラビリティがある。同じ概念で、小さいプログラムも大きなプログラムも記述できる


パーフェクト!!


自作アプリを作成した際には組み込み言語をCPythonにしようと思ったが、GUIJavaベースで作成したいので親和性が問題となる。JVM上で動く言語ならJythonでもScalaでも何でもOKというようにした方が良いかもと思った。ヘタしたら本体もScalaベースでも良いかな。という訳でPythonJavaScalaを極める!!

モジュールによるmixinの実現

Pythonでも実はRubyのmixinのようなことが可能である。

def mixin(template, mod_name):
    import new, sys
    m = new.module(mod_name)	
    m.__dict__.update(**template())
    sys.modules[mod_name] = m

def template():
    def foo(self):
        return 'foo'
    def bar(self, x):
        return x*10
    return locals()
	
class Foo(object):
    mixin(template, 'mod1')
    from mod1 import *

f = Foo()
print f.foo()
print f.bar(1)

# 実行結果
test.py:14: SyntaxWarning: import * only allowed at module level
  class Foo(object):
foo
10

mixin()関数に"(関数名, 関数オブジェクト)ペアの辞書"とモジュール名の2つを渡すと、指定したモジュール名でモジュールを登録してくれる。後はクラス定義の中で、"from モジュール名 import *"するだけ。


全て取り込むときにワーニングが出てしまう。全て取り込めないと不便なので後で回避方法考える。個別に取り込みたいときは、"from mod1 import foo,bar"のようにする。この場合ワーニングが出ない。


あと、"from mixin(template) import *"と書きたかったが、fromの後は構文に制限がありわざと2行に分けた。__import__()も調べたが良い方法が見つからなかった。


以下のようにクラス定義の属性に追加する方法もあるが、新スタイルクラスのFoo.__dict__はdictproxyでupdate()が使えないので1つずつsetattrする必要があるし、旧スタイルクラスは普通のdictであるが、どっちにしてもクラス定義の外で追加しないといけないので分かりづらい。

clas Foo:pass

Foo.__dict__.update(template())

キャストの仕組み

昨日のつづき。


昨日の日記に対してodzさんがコメントしてくれたみたいで、TがObjectになってしまう理由は分かった。以下、自分の理解。

  • 仮にTがDuck型しか受け取らないにしても他の型(例えばFoo型)も受け取れる可能性がある
  • TがDuck型しか受け取っていない実装ならTをDuckに推論しても良いが、そういう仕組みはない
  • コンパイル後の生成物で実装が複数できるわけでなく1つしかできない
  • 仮に推論してTをDuckに置き換えても、後から別ファイルでFooの定義を追加し、そこからFooのインスタンスでfoo()を呼び出したとき問題が起こる。foo()を定義している箇所をリコンパイルしないといけなくなる
  • 結果的に推論せず全てObjectで置き換えるだけしか不可能(ワイルドカードなどを使用しない限り)


つまりTと書くとObject型にしかなり得ない。


しかし分からないのは、どういう仕組みでキャストが挿入されるのかがいまいち分からない。例えば以下のようなコードを作成してみた。

class Duck {
    public void quack() { System.out.println("gaaa"); }
}

class Foo {
    public void quack() { System.out.println("...."); }
}

class test {
    public static <T> void func(T ducky) {
        Duck ducky1 = ducky;
        ducky.quack();
    }

    public static void main(String[] args) {
        func(new Duck());
        //func(new Foo());
    }
}

func()メソッドの内部でducky1にduckyを代入しているので、そのタイミングでキャストを挿入してくれると思った。しかし、コンパイル時に以下のエラーが出る。

test.java:11: 互換性のない型
検出値  : T
期待値  : Duck
                Duck ducky1 = ducky;
                              ^
test.java:12: シンボルを見つけられません。
シンボル: メソッド quack()
場所    : java.lang.Object の クラス
        ducky.quack();
             ^
エラー 2

明らかにキャストを入れてくれていない。ではどういうタイミングでキャストが入るのだろうか?