|
Vino 言語仕様の予定 ver. 0.02 2002/11/20
おそらく、Vino の考え方で一番難しいと思われるところ。継承という概念ではなく、Java
の interface に近いので、そう思っていただくと理解しやすいでしょう。
クラスの書き方は C/C++ とは大きく異なる。
class は関数(func)の延長であるという考え方であり、例えば、classのインスタンスとは、関数funcの戻り値と同じ意味になる。
よって、メンバを持たない class は、戻り値を持たない関数(func)と同じ意味になる。
out は C++/Javaでの public と同じような意味になる。
| 予約語 |
class out dtor
|
|
| class |
class Foo -- クラス Foo の定義文
{
...
}
end class Foo ; -- end はコメントのようなもの(省略できる)
|
|
◆まずは、簡単な例。
| class |
class Foo -- クラス Foo の定義文
{
m_counter $ 0 ; -- メンバ
out func puts -- メソッド out は public の意味
{
sys.put( "{m_counter}\n"
) ;
++ m_counter ;
}
}
end class Foo ;
foo : Foo() ; -- インスタンス生成 関数の呼び出しとほぼ同じ
sys.put( foo.m_counter ) ; -- NG コンパイルエラー(private参照不可)
foo.puts() ; -- 0 を表示
foo.puts() ; -- 1 を表示
sys.put( foo.type_name() ) ; -- class:Foo{} を表示
sys.put( foo.Puts.type_name() ) ; -- func:Puts{} を表示
|
|
◆詳しく書くと
メンバはC++/Javaのメンバと同じようにカプセル化される。class内部で宣言された定数や変数はメンバとなる。
ただし、out 宣言しないとprivateとなり、classの外からアクセスできない。
また、func との違いは、dtor メソッド(デストラクタ)が書けること。というかfuncとclassの差はほとんどない。
| class |
class Foo
-- クラス Foo の定義文
{
in_a : int in[0] ; -- 引数(初期化時)関数の引数と同じように書く
m_boo $ 100 ;
-- 変数や定数は、そのままメンバ変数になる(プライベート)
out m_foo : 200 ; -- 定数(参照可能、public)
out m_woo $ 300 ; -- 変数(更新可能、public)
m_boo += in_a ; -- コンストラクタの処理がいきなり書ける
m_woo += in_a ; -- コンストラクタの処理がいきなり書ける
out func foo -- メソッド(関数)fooの書き方
{
in_a : in[0] ; -- これはメソッドfooの引数
out : 1 ; -- これはメソッドfooの戻り値
.m_boo += 1 ;
-- メンバ変数にアクセス
.m_woo += 1 ;
-- メンバ変数にアクセス
}
end func foo ;
dtor -- デストラクタ
{
...
-- func では dtor は書けない
.foo( 10 ) ; -- メンバ関数にアクセス
}
end dtor ;
} ;
-- end は省略
{
a : Foo( 100 ) ; -- 初期化引数 100(更新可能メンバ m_woo も更新不可)
b $ Foo( 100 ) ; -- 初期化引数 100(メンバ m_woo 更新可能)
sys.put( a.m_boo ) ; -- NG コンパイルエラー(参照不可)
sys.put( a.m_foo ) ; -- 200 を表示
sys.put( a.m_woo ) ; -- 300 を表示
a.m_foo ++ ; -- NG コンパイルエラー(更新不可)
a.m_woo ++ ; -- NG コンパイルエラー(更新不可)
b.m_foo ++ ; -- NG コンパイルエラー(更新不可)
b.m_woo ++ ; -- 301
sys.put( a.type_name() ) ; -- class:Foo{in:int,} を表示
sys.put( b.type_name() ) ; -- $class:Foo{in:int,} を表示
} ; -- スコープが切れるところで、デストラクタが走る。
|
|
C/C++ にはインターフェースという構文は無い。Java にはあるが、Vino では使い方が少し違うので注意が必要。
Javaのinterfaceと同じだと思っていただいても良いです。ただ、記述の仕方が違います。
interface はインスタンスを生成できない。主に、クラスの中に取り込まれる形でインスタンスとなりその機能を発揮する。初期値は記述できまるが、メソッド(関数)の処理までは記述できない。
| 予約語 |
interface
|
|
| interface |
interface _Foo -- インターフェース _Foo の定義文
{
...
}
end interface _Foo ; -- end はコメントのようなもの(省略できる)
interface _Foo -- インターフェイス _Foo の定義文
{
in_a : int in[0] ; -- 引数(初期化時)
m_boo $ 100 ; -- NG privateな変数や定数は書けない。すべてpublicとして扱われる。
out m_foo : 200 ; -- OK 定数(外部から参照可能)
out m_woo $ 300 ; -- OK 変数(外部から更新可能)
m_woo += in_a ; -- NG 実行文は書けない
out func foo -- メソッド(関数)の書き方
{
in, -- fooメソッドの引数(型は何でもOK)
in:int, -- fooメソッドの引数(型はint固定)
out:string, -- fooメソッドの戻り値(型は string )
.m_woo += 1 ; -- NG 実行文は書けない
}
end func foo ;
}
end interface _Foo ; -- end はコメントのようなもの(省略できる)
class Foo -- クラス Foo の定義文
{
use _Foo ; -- クラス Foo がインターフェイス _Foo を包含しているかチェック。
...
};
|
|
◆ interface の使い方(class に包含する普通の使い方)
| interface |
interface _At -- インターフェース _At の定義文
{
out func at{ in:int, out, } ; -- このメソッドがあること。
} ;
class Boo -- クラス Boo の定義文
{
use _At ; -- _At (at()メソッド)を包含しているかチェックするという意味
out func at -- このメソッドがあればOK。無いclassはコンパイルエラーになる。
{
in_a : int in [0] ;
out : in_a * 3 ;
} ;
} ;
class Foo -- クラス Foo の定義文
{
use _At ; -- _At (at()メソッド)を包含しているかチェックするという意味
out func foo -- at() メソッドでないのでNG。コンパイルエラー。
{
in_a : int in[0] ;
out : in_a * 4 ;
} ;
} ;
class Woo -- クラス Woo の定義文
{
use _At ;
out func at
{
out : in[0] / 2 ;
} ;
} ;
boo : Boo ;
foo : Foo ; -- NG
woo : Woo ;
sys.put( boo.at( 10 ) ) ; -- 300 が表示される
sys.put( boo[ 1 ] ) ; -- [] は .at() のシンタックスシュガーなので 3 が表示される
sys.put( woo.at( 7.0 ) ) ; -- NG 引数は int で宣言されている
sys.put( woo[ 7 ] ) ; -- 3 が表示される
a $ _At boo ; -- inertface名で変数インスタンスを作ることができる
sys.put( a.at( 5 ) ) ; -- 15 が表示される
a = woo ; -- 変数インスタンスなので変更が可能
-- 厳密には違うがオブジェクト指向のポリモーフィズム(動的なバインド)のような機能を実現する
sys.put( a.at( 5 ) ) ; -- 2 が表示される
|
|
◆ interface内の定数の使い方(C++ のnamespaceのような使い方)
| interface |
interface _Math
{
m_pi : real 3.1415926535 ; -- π
...
} ;
r : 5.0 ;
circumference : 2.0 * _Math.m_pi * r ; -- inertface内の定数を直接参照できる
sys.put( circumference ) ; -- 31.1415926535 が表示される
|
|
◆ interface でコンテナ(配列)をつくる
おそらく、この考え方が Vino の一番の特徴になるのではないかと思う。
継承ではなくて、interface を使って、多態性(ポリモーフィズム)のような動作を実装する。
interface _Foo を含む boo や woo は vector[_Foo] に登録することができる。同じ
_Foo であると解釈されるため、woo 特有の func something_gaa はアクセスできない。
interface _Foo に登録されている func do_something は boo と woo の区別無くアクセスできる。
interface
多態性 |
interface _Foo
{
out func do_something{} ; -- 何かをする(引数は無し)
} ;
boo : class Boo
{
use _Foo ; -- インターフェース_Foo を使う(チェックする)
out func do_something
{
sys.put( "boo\n"
) ; -- booを表示
} ;
} ;
woo : class Woo
{
use _Foo ; -- インターフェース_Foo を使う(チェックする)
out func do_something
{
sys.put( "woo\n"
) ; -- wooを表示
} ;
out func something_gaa -- interfaceに無いfuncも実装できる
{
sys.put( "gaa\n"
) ; -- wooを表示
} ;
} ;
foo_tbl : vector[_Foo] boo, woo, boo, woo, ;
sys.put( foo_tbl.type_name() ) ;
-- vector[interface:_Foo{}] が表示される
sys.put( foo_tbl.size() ) ;
-- 4 が表示される
sys.put( foo_tbl[3].do_something() ) ; -- woo が表示される
sys.put( foo_tbl[0].type_name() ) ; -- interface:_Foo{} が表示される
foo_tbl.each(
func {
-- sys.put( in.type_name() ) ; -- interface:_Foo{} が表示される
in.do_something() ; -- boo woo boo woo が表示される
} ) ;
|
|
以下、工事中
■4章 ライブラリ
標準ライブラリ sys
拡張ライブラリ Rex
◆ 省略時の引数(in) 引数の宣言を省略することができる。
sys と
Rex |
sys.each( -- 標準入力から
func{
-- sys.put( in.type_name() ) ; -- string が表示される
line_str : in[0] ;
r : Rex( '^From:' ) ; -- rex の ^ は正規表現で「先頭」と言う意味
r.match( line_str, { sys.put( in[0] ) ; } ) ;
} ) ;
-- line_str, r を省略
sys.each(
func{
Rex( '^From:' ).match in[0],
{
sys.put( in[0] ) ;
} ;
} ) ;
|
|
◆ ファイルのアクセス(標準入出力のアクセス)
次のようにして、ファイルが書き込み可能かどうかなどを検査することができる。
File,
FileStatus |
-- class File ファイル名で指定する
{
fp $ File( 'file.txt' ) ;
fp.write_open
{
in[0] <<= 'test ok'
;
} ;
} ; -- デストラクタでファイルをクローズ
File( 'file.txt' ).write_open
{
in[0] <<= 'test ok' ;
} ;
File( 'file.txt' ).read_open().each(
func {
sys.put( in[0] ) ; -- in[0].type_name() : string
} ) ;
--- class FileStatus を用いた確認
status : FileStatus( 'file.txt' ) ;
status.read_ok ? sys.put( "読み込み可能\n" ) ;
|
|
class FileStatus では次のような検査が可能です。(UNIXでしか意味の無い物も多いです)
| FileStatus |
read_ok -- 読み込み可能であれば(bool)
write_ok -- 書き込み可能であれば(bool)
exec_ok -- 実行可能であれば(bool)
size -- ファイルサイズを返す(int)
is_empty -- サイズが0であればtrue(bool)
is_file -- 通常ファイルであればtrue(bool)
is_dir -- ディレクトリであればtrue(bool)
is_link -- シンボリックリンクであればtrue(bool)
is_pipe -- 名前付きパイプであればtrue(bool)
|
|
4章の後半につづきます。
|