filter method_name1 method_name2 ...
リスト : filter の使用例1
oo::class create Foo {
filter baz1 baz2
method foo {a} {
puts "Foo::foo $a"
}
method bar {a b} {
puts "Foo::bar $a $b"
}
method baz1 args {
puts "Foo::baz1 called"
next {*}$args
puts "Foo::baz1 ended"
}
method baz2 args {
puts "Foo::baz2 called"
next {*}$args
puts "Foo::baz2 ended"
}
}
Foo create a
a foo 10
a bar 20 30
Foo::baz1 called Foo::baz2 called Foo::foo 10 Foo::baz2 ended Foo::baz1 ended Foo::baz1 called Foo::baz2 called Foo::bar 20 30 Foo::baz2 ended Foo::baz1 ended
% set a {1 2 3}
1 2 3
% list 1 2 3 $a 4 5 6
1 2 3 {1 2 3} 4 5 6
% list 1 2 3 {*}$a 4 5 6
1 2 3 1 2 3 4 5 6
リスト : filter の使用例2
oo::class create Foo {
method foo {a} {
puts "Foo::foo $a"
}
method bar {a b} {
puts "Foo::bar $a $b"
}
}
oo::class create Baz {
method baz1 args {
puts "Baz::baz1 called"
next {*}$args
puts "Baz::baz1 ended"
}
method baz2 args {
puts "Baz::baz2 called"
next {*}$args
puts "Baz::baz2 ended"
}
}
Foo create a
Foo create b
oo::objdefine a {
mixin Baz
filter baz1 baz2
}
a foo 10
a bar 20 30
b foo 1
b bar 2 3
Baz::baz1 called Baz::baz2 called Foo::foo 10 Baz::baz2 ended Baz::baz1 ended Baz::baz1 called Baz::baz2 called Foo::bar 20 30 Baz::baz2 ended Baz::baz1 ended Foo::foo 1 Foo::bar 2 3
リスト : filter の使用例3
oo::class create Baz {
method baz1 args {
puts "Baz::baz1 called"
next {*}$args
puts "Baz::baz1 ended"
}
method baz2 args {
puts "Baz::baz2 called"
next {*}$args
puts "Baz::baz2 ended"
}
}
oo::class create Foo {
mixin Baz
filter baz1 baz2
method foo {a} {
puts "Foo::foo $a"
}
method bar {a b} {
puts "Foo::bar $a $b"
}
}
oo::class create Bar {
superclass Foo
method foo {a} {
next $a
puts "Bar::foo $a"
}
method oops {a b c} {
puts "Bar::oops $a $b $c"
}
}
Bar create a
a foo 10
a oops 20 30 40
Baz::baz1 called Baz::baz2 called Foo::foo 10 Bar::foo 10 Baz::baz2 ended Baz::baz1 ended Baz::baz1 called Baz::baz2 called Bar::oops 20 30 40 Baz::baz2 ended Baz::baz1 ended
リスト : filter の使用例4
oo::class create A {
filter bar_a
method bar_a {} {
puts "A::bar_a"
next
}
method foo {} {
puts "A::foo"
}
}
oo::class create B {
superclass A
filter bar_b
method bar_b {} {
puts "B::bar_b"
next
}
method foo {} {
next
puts "B::foo"
}
}
oo::class create C {
superclass A
filter bar_c
method bar_c {} {
puts "C::bar_c"
next
}
method foo {} {
next
puts "C::foo"
}
}
oo::class create D {
superclass B C
filter bar_d
method bar_d {} {
puts "D::bar_d"
next
}
method foo {} {
next
puts "D::foo"
}
}
D create d
puts [info object call d foo]
d foo
{filter bar_d ::D method} {filter bar_b ::B method} {filter bar_a ::A method} {filter bar_c ::C method}
{method foo ::D method} {method foo ::B method} {method foo ::C method} {method foo ::A method}
D::bar_d
B::bar_b
A::bar_a
C::bar_c
A::foo
C::foo
B::foo
D::foo
forward method_name command_name arg ...
% oo::class create Foo {
forward foo test 1 2 3
}
::Foo
% proc test args {
puts "test $args"
}
% Foo create a
::a
% a foo
test 1 2 3
% a foo 4 5 6
test 1 2 3 4 5 6
% oo::class create Bar
::Bar
% Bar create b
::b
% oo::objdefine b {
forward foo test 10 20 30
}
% b foo
test 10 20 30
% b foo 40 50 60
test 10 20 30 40 50 60
リスト : forward の使用例
oo::class create Foo
oo::objdefine Foo {
variable x
method get_x {} {
return $x
}
method set_x {a} {
set x $a
}
}
oo::define Foo {
forward get_x Foo get_x
forward set_x Foo set_x
}
Foo set_x 1
puts [Foo get_x]
Foo create a
puts [a get_x]
a set_x 10
puts [a get_x]
1 1 10
% oo::object create a
::a
% oo::object create b
::b
% oo::objdefine b {
variable x
method getx {} {
return $x
}
method setx {a} {
set x $a
}
}
% b setx 10
10
% b getx
10
% a setx 100
unknown method "setx": must be destroy or foo
% oo::object create singleton
::singleton
% oo::objdefine singleton {
method foo {} {
puts "foo!!"
}
method baz {a} {
puts "baz $a"
}
}
% singleton foo
foo!!
% singleton baz 10
baz 10
% a foo
unknown method "foo": must be destroy
method unknown {method_name args} {
...
}
% oo::class create Foo {
method unknown {name args} {
Foo $name {*}$args
}
}
::Foo
% oo::objdefine Foo {
method foo {} {
puts "Foo foo!!"
}
method bar {a} {
puts "Foo bar $a"
}
}
% Foo create a
::a
% a foo
Foo foo!!
% a bar 123
Foo bar 123
% a baz
unknown method "baz": must be bar, create, destroy, foo or new
% info class subclasses oo::object ::oo::class ::oo::Slot % info class superclasses oo::class ::oo::object
info object isa class obj info object isa object obj
% info object isa typeof oo::object oo::class 1 % info object isa class oo::object 1 % info object isa typeof oo::object oo::object 1 % info object isa object oo::object 1 % info object isa typeof oo::class oo::class 1 % info object isa class oo::class 1 % info object isa typeof oo::class oo::object 1 % info object isa object oo::class 1
リスト : クラス変数 xx を有するクラスを生成 (test0.tcl)
oo::class create Foo {
superclass oo::class
variable xx
method getxx {} {
return $xx
}
method setxx {a} {
set xx $a
}
}
Foo create Bar {
variable a
forward getxx Bar getxx
forward setxx Bar setxx
constructor {} {
set a 0
}
method geta {} {
return $a
}
method seta {x} {
set a $x
}
}
% source test0.tcl ::Bar % info object isa metaclass Foo 1 % info object isa metaclass Bar 0 % Bar create x ::x % Bar create y ::y % % x setxx 100 100 % y getxx 100 % y setxx 1000 1000 % x getxx 1000 % x seta 10 10 % y seta 1 1 % x geta 10 % y geta 1
リスト : シングルトンパターン (test1.tcl)
oo::class create Singleton {
superclass oo::class
unexport create
variable obj
method new args {
if {![info exists obj]} {
set obj [next {*}$args]
}
return $obj
}
}
Singleton create Foo {
method foo {} {
puts "Singleton Foo!!"
}
}
Singleton create Bar {
variable x
constructor {a} {
set x $a
}
method bar {} {
puts "Singleton Bar $x"
}
}
% source test1.tcl ::Bar % Foo new ::oo::Obj14 % Foo new ::oo::Obj14 % [Foo new] foo Singleton Foo!! % Foo create a unknown method "create": must be destroy or new % Bar new 123 ::oo::Obj15 % [Bar new 456] bar Singleton Bar 123 % set b [Bar new 789] ::oo::Obj15 % $b bar Singleton Bar 123
クラスと継承の簡単な例題として、「連結リスト」とそれを継承した「制限付き連結リスト」を作成します。Tcl/Tk にはリストがあるので、連結リストを自作する必要はないのですが、TclOO の勉強ということで、あえてプログラムを作ってみましょう。
連結リストの概要は拙作のページ Python 入門第 5 回: 連結リスト と Python 入門第 6 回: 制限付きリスト をお読みください。
| 名前 | 機能 |
|---|---|
| LinkedList create (or new) | LinkedList の生成 |
| xs insert n x | 連結リスト xs の n 番目に x を挿入する |
| xs get n | 連結リスト xs の n 番目の要素を求める |
| xs set n x | 連結リスト xs の n 番目の要素を x に書き換える |
| xs delete n | 連結リスト xs の n 番目の要素を削除 |
| xs length | 連結リスト xs の要素数を返す |
| xs is_empty | 連結リスト xs が空であれば真 (1)を返す |
| xs print | 連結リスト xs を表示する |
| 名前 | 機能 |
|---|---|
| FixedList create (or new) size | 大きさ size の FixedList を生成する |
| xs insert n x | リスト xs の n 番目に x を挿入, 挿入できない場合はエラーを送出する |
| xs is_full | リスト xs が満杯ならば真 (1) を返す |
#
# linkedlist.tcl : 連結リスト (TclOO のサンプル)
#
# Copyright (C) 2019 Makoto Hiroi
#
# コンスセル
oo::class create Cell {
variable a d
constructor {x {y 0}} {
set a $x
set d $y
# puts "Cell new [self object]"
}
method car {} { return $a }
method cdr {} { return $d }
method set_car {x} { set a $x }
method set_cdr {y} { set d $y }
destructor {
# puts "Cell destroy [self object]"
}
}
# コンスセルか
proc consp {xs} {
info object isa typeof $xs Cell
}
# 連結リスト
oo::class create LinkedList {
variable header size
unexport nth
constructor {} {
set header [Cell new 0 0]
set size 0
}
destructor {
set cp $header
while {[consp $cp]} {
set cp1 [$cp cdr]
$cp destroy
set cp $cp1
}
}
# 作業用 : n 番目のセルを求める
method nth {n} {
set i -1
set cp $header
while {$i < $n} {
if {![consp $cp]} {
break
}
set cp [$cp cdr]
incr i
}
return $cp
}
# n 番目の要素を求める
method get {n} {
set cp [my nth $n]
if {![consp $cp]} {
error "List::get $n, out of range"
}
return [$cp car]
}
# n 番目の要素を書き換える
method set {n val} {
set cp [my nth $n]
if {![consp $cp]} {
error "List::set $n $val, out of range"
}
set old_val [$cp car]
$cp set_car $val
return $old_val
}
# n 番目に val を挿入
method insert {n val} {
set cp [my nth [expr $n - 1]]
if {![consp $cp]} {
error "List::insert $n $val, out of range"
}
set cp1 [Cell new $val [$cp cdr]]
$cp set_cdr $cp1
incr size
return $val
}
# n 番目の要素を削除
method delete {n} {
set cp [my nth [expr $n - 1]]
if {![consp $cp] || ![consp [$cp cdr]]} {
error "List::delete $n, out of range"
}
set cp1 [$cp cdr]
set val [$cp1 car]
$cp set_cdr [$cp1 cdr]
$cp1 destroy
set size [expr $size - 1]
return $val
}
# リストは空か
method is_empty {} {
expr ![consp [$header cdr]]
}
# 要素数
method length {} {
return $size
}
# 表示
method print {} {
set cp [$header cdr]
while {[consp $cp]} {
puts -nonewline "[$cp car] "
set cp [$cp cdr]
}
puts ""
}
}
# 制限付き連結リスト
oo::class create FixedList {
superclass LinkedList
variable limit
constructor {a} {
next
set limit $a
}
# n 番目に val を挿入
method insert {n val} {
if {[my length] >= $limit} {
error "FixedList::insert $n $val, over the limit"
}
next $n $val
}
# リストは満杯か
method is_full {} {
expr [my length] == $limit
}
}
# 簡単なテスト
LinkedList create a
puts [a is_empty]
puts [a length]
foreach x {0 1 2 3 4} {
a insert $x [expr $x + 1]
}
a print
puts [a is_empty]
puts [a length]
foreach x {0 1 2 3 4} {
puts [a get $x]
}
foreach x {0 1 2 3 4} {
a set $x [expr [a get $x] * 10]
}
a print
while {![a is_empty]} {
puts [a delete 0]
}
a print
puts [a is_empty]
puts [a length]
FixedList create d 5
d print
foreach x {1 2 3 4 5 6} {
if {[d is_full]} {
break
}
d insert 0 $x
}
d print
while {![d is_empty]} {
puts [d delete 0]
}
d print
foreach x {1 2 3 4 5 6} {
if {[d is_full]} {
break
}
d insert 0 $x
}
d print
C>tclsh linkedlist.tcl 1 0 1 2 3 4 5 0 5 1 2 3 4 5 10 20 30 40 50 10 20 30 40 50 1 0 5 4 3 2 1 5 4 3 2 1 5 4 3 2 1
error message [info] [code]
% expr 10 / 0
divide by zero
% set errorInfo
divide by zero
while executing
"expr 10 / 0"
% set errorCode
ARITH DIVZERO {divide by zero}
% proc foo {} { error "oops!" }
% foo
oops!
% set errorInfo
oops!
while executing
"error "oops!" "
(procedure "foo" line 1)
invoked from within
"foo"
% set errorCode
NONE
% proc bar {a} { error "oops!" "bar $a" "bar error"}
% bar 100
oops!
% set errorInfo
bar 100
(procedure "bar" line 1)
invoked from within
"bar 100"
% set errorCode
bar error
catch script var_name
% catch {expr 1 + 2} var
0
% set var
3
% catch {expr 1 + a} var
1
% set var
invalid bareword "a"
in expression "1 + a";
should be "$a" or "{a}" or "a(...)" or ...
% catch {error oops} var
1
% set var
oops
% catch {break} err
3
% set err
% catch {continue} err
4
% set err
% catch {return} err
2
% set err
%
% proc foo {} {puts "foo!"}
% proc bar {} {puts "bar!"; error "Global Exit!!"}
% proc baz {} {puts "baz!"}
% proc test {} {foo; bar; baz}
% if {[catch {test} err]} {
puts $err
}
foo!
bar!
Global Exit!!
throw type message
% throw {MY_ERR FOO} "oops! Foo!!"
oops! Foo!!
% catch {throw {MY_ERR FOO} "oops! Foo!!"} err
1
% set err
oops! Foo!!
% set errorCode
MY_ERR FOO
try {
...
}
on {完了コード} {var_name} {
...
}
...
trap {エラーコード} {var_name} {
...
}
...
finally {
...
}
% try {throw {MY_ERR FOO} "oops! Foo!!"} \
trap {MY_ERR FOO} {err} {puts "ERROR: $err"}
ERROR: oops! Foo!!
% try {throw {MY_ERR BAR} "oops! Bar!!"} \
trap {MY_ERR FOO} {err} {puts "ERROR: $err"}
oops! Bar!!
% try {throw {MY_ERR FOO} "oops! Foo!!"} \
trap {MY_ERR} {err} {puts "ERROR: $err"}
ERROR: oops! Foo!!
% try {throw {MY_ERR BAR} "oops! Bar!!"} \
trap {MY_ERR} {err} {puts "ERROR: $err"}
ERROR: oops! Bar!!
% try {error "oops! Foo!!"} \
trap {MY_ERR FOO} {err} {puts "ERROR: $err"} \
on {error} {err1} {puts "catch error: $err1"}
catch error: oops! Foo!!
% try {throw {MY_ERR FOO} "oops! Foo!!"} \
on {error} {err} {puts "catch errror: $err"} \
trap {MY_ERR} {err1} {puts "ERROR: $err1"}
catch errror: oops! Foo!!
% try {puts "OK!!"} finally {puts "cleanup!!"}
OK!!
cleanup!!
% try {error "NG!!"} on {error} {err} {puts "ERROR: $err"} finally {puts "cleanup!!"}
ERROR: NG!!
cleanup!!
% try {error "NG!!"} finally {puts "cleanup!!"}
cleanup!!
NG!!