Jython を学ぶ(2)

前回(http://d.hatena.ne.jp/Monolithic/20080824/1219582882)の例のよくない点を訂正します。

  • Python の callable オブジェクトを実行する、 Runnable を実装したクラス PyCallableRunnable を用意。いちいちクラスを作るのは Pythonic ではありませんでした。
  • Runnable を AWT スレッドで実行するのに、 javax.swing.SwingUtilities#invokeLater を使っていたのを java.awt.EventQueue#invokeLater を使うように訂正。これは単に、 AWT スレッドで実行するのに Swing の API を使うのは奇妙ではないかと私が思ったというだけで、たいした違いではないでしょう。
  • from ... import ... で import * するのをやめて、クラス一つ一つをインポートするように訂正。
#! jython
from java.lang import Runnable
from java.awt import Rectangle
from java.awt import EventQueue
from javax.swing import JFrame
class PyCallableRunnable(Runnable):
	def __init__(self, pyCallable):
		self.pyCallable=pyCallable
		return
	def run(self):
		self.pyCallable()
		return
def initializeAWT():
	def windowClosing(e):
		window=e.getWindow()
		window.visible=False
		window.dispose()
		return
	JFrame(
		windowClosing=windowClosing, 
		bounds=Rectangle(800, 600), 
		title="Hello, world! ", 
		visible=True
		)
	return
if __name__=="__main__":
	EventQueue.invokeLater(PyCallableRunnable(initializeAWT))

ソースコードの解説

このコードを test.py に保存し、そのディレクトリで以下のコマンドを実行します。

jython test.py


すると Swing のウインドウが現れるはずです。ウインドウを閉じると、しばらくしてプログラムも終了するはずです。


Python スクリプトがトップレベルとして実行されると、モジュール名( __name__)は"__main__"になります。このため、if __name__=="__main__": の中身はこのスクリプトをトップレベルで実行したときにのみ実行されます。


PyCallableRunnable クラスはコンストラクタの引数に python の関数を取り、それを run メソッドで実行する、 java.lang.Runnable インターフェースを実装したクラスです。


initializeAWT 関数は、大きさが幅 800px 、高さ 600px 、タイトルが"Hello world! "、生成時に可視状態になり、閉じると破棄される JFrame クラスのインスタンスを生成します。このとき Python の名前付き引数で Java Beans のプロパティ(bounds, title, visible)を設定しています。


windowClosing 関数はウインドウが閉じられると呼ばれ、ウインドウを不可視にした後 java.awt.Window#dispose を呼び出します。


Jython は JFrame の WindowListener を自動的に登録し、WindowListener#windowClosing が windowClosing プロパティに指定された関数を呼び出すようにしてくれています。おかげで Listener インターフェースを実装した冗長なクラスを記述する必要がありません。


java.awt.EventQueue#invokeLater メソッドは、引数に与えられた Runnable オブジェクトを AWT スレッドで実行します。AWT 関連の(そして Swing 関連の)API の多くは AWT スレッドで呼び出さなければなりません。


initializeAWT をコンストラクタの引数にとった PyCallableRunnable クラスのインスタンスを invokeLater メソッドに与えることで、AWT スレッドで initializeAWT 関数が実行されます。




ウインドウを閉じると windowClosing 関数が呼び出され、ウインドウは dispose されます。全てのトップレベルウインドウが dispose されるとAWT スレッドがシャットダウンし、他にnon-daemon スレッドが走っていなければ JVM がシャットダウンすると思います。これについてはhttp://java.sun.com/javase/ja/6/docs/ja/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdownに書いてあります。

さて次回は

Apache Batik を Jython から使う例を解説する予定。

Jython を学ぶ(1)

私が書くようなプログラムは「なんか予想外の事態になったら例外吐いて停止すればいい」ものがほとんどです。
そう考えると Scala より Jython が適切な選択ではないかと思い直しました。

#! jython
from java.lang import *
from java.awt import *
#from java.awt.event import *
from javax.swing import *
class Application(Runnable):
	def run(self):
		def windowClosing(e):
			window=e.getWindow()
			window.visible=False
			window.dispose()
			#import sys
			#sys.exit()
		JFrame(
			windowClosing=windowClosing, 
			bounds=Rectangle(800, 600), 
			title="Hello, world! ", 
			visible=True
		)
if __name__=="__main__":
	SwingUtilities.invokeLater(Application())

jython test.py

VC のイントリンシック命令

イントリンシックとはコンパイラ組み込みの関数のことです。
Visual C++ 9.0 のイントリンシック命令は MSDN の以下の URL に載っています。

Intrinsics Available on All Architectures:

http://msdn.microsoft.com/ja-jp/library/5704bbxw.aspx

_Interlocked** 擬似関数

Windows API には Interlocked*** という名前の関数群があって、それらを呼び出すことによってC言語では書けない atomic な操作、例えば他のスレッドに邪魔されずに変数をインクリメントしたりすることが必要なコードを簡単に書くことができます。_Interlocked*** という名前のイントリンシック命令は Interlocked*** 関数のイントリンシック版のようですね。
また、私は使ったことがないのですが GCC でもバージョン 4.1 以降で atomic な操作を行うためのイントリンシック命令が導入されたようです。

gcc-4.1からatomic関係の関数がビルトインに

http://d.hatena.ne.jp/tasukuchan/20060810

atomic だとかスピンロックだとかいう話はまたいずれしたいと思います。

C 標準ライブラリの関数のイントリンシック版

memcpy だとか strcpy だとか言ったメモリ関連・文字列関連の標準関数や、数学計算関連の関数がイントリンシック命令として用意されています。
これらの関数はコンパイラ組み込みの擬似関数ですから、 CRT をリンクしなくても使うことができます。

Scala 関連 URL

The Scala Programming Language(本家)

http://www.scala-lang.org/

Scala言語の入門書の紹介

http://d.hatena.ne.jp/HHa/20080116

Scala を学ぶ(1)

とりあえず Swing でウインドウを出すコードを書いてみた

Java 版(HelloWorld.java)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class HelloWorld{
  public static void main(String arg[]){
    SwingUtilities.invokeLater(new Runnable(){
        public void run(){
          final JFrame frame=new JFrame();
          frame.setBounds(new Rectangle(800, 600));
          frame.setTitle("Hello, world! ");
          frame.addWindowListener(new WindowAdapter(){
              @Override
              public void windowClosing(WindowEvent e){
                frame.setVisible(true);
                frame.dispose();
              }
          });
          frame.setVisible(true);
        }
    });
  }
}

javac HelloWorld.java
java -classpath . HelloWorld

Scala 版(test.scala)
import java.awt._
import java.awt.event._
import javax.swing._
object HelloWorld{
  def main(args: Array[String]){
    SwingUtilities invokeLater new Runnable{
      def run(){
        val frame=new JFrame
        frame setBounds new Rectangle(800, 600)
        frame setTitle "Hello, world! "
        frame addWindowListener new WindowAdapter{
          override def windowClosing(e:WindowEvent){
            frame setVisible false
            frame dispose
          }
        }
        frame setVisible true
      }
    }
  }
}

scalac test.scala
java -classpath .;\lib\scala-library.jar HelloWorld


Java 版を直訳しただけであんまりいい例じゃないな

色々な JVM 実装(1)

いろんな JVM の実装と簡単な紹介を列挙してみる

Sun の HotSpot http://openjdk.java.net/groups/hotspot/

Sun の Java についてるやつ。
Java1.2 でアドオンとして搭載され、Java1.3 でデフォルトの VM となった。
というか 1.0 から 1.2 までは JIT じゃなかったらしい。そりゃ遅いだろ……
SmallTalk VM や Self VM の技術が転用されたとか聞くけどよく知らない。
HotSpot と呼ばれるのは、最適化すべき場所(HotSpot)だけ JIT コンパイルするかららしい。
C++アセンブリ言語で書かれている。
対応 CPU は x86, x64, SPARC

JNode の JVM http://www.jnode.org/

JNode は最小限のアセンブリ言語Java で書かれた OS 。
JNode は Java のネイティブコンパイラを持っているようだ。
http://www.jnode.org/node/37
この辺の仕組みがよくわからない。AOT と JIT の中間みたいな動作をするのだろうか。
JNode をちょっと使ってみて驚いたのは、結構実用的に動いたことだ。いずれこのことについては詳しく書こうと思う。

Jikes RVM http://jikesrvm.org/

ほとんど Java で書かれた JVM
IBM のプロジェクトがオープンソース化したらしい。
Unix ライクな OS で動くようだ。
そこで MacOSX でビルドしてみようとしたけど失敗した。よく調べればできるのかもしれないがあまり興味もないので放棄。

つづく