isa演算子・asa演算子
ここからは、型を使ったより実践的な処理について説明します。any変数を引数で利用した場合などデータ型を判定し、その種類によって処理を分けたい場合について考えます。
今、複数の引数の平均値を計算するプロシージャaverageを考えます。処理を単純化するために、引数には整数(int)、実数(double)、文字列(String)のどれかが渡されるとします。引数の型をチェックするために、if式の条件判断にisa演算子を使います。変数をanyから特定の型にキャストするために、asa演算子を使います。
{curl 7.0 applet} {curl-file-attributes character-encoding = "shift-jis"} || if を使ったプロシージャ || {define-proc public {average ...:any}:double let sum:double = 0 let count:int = 0 {for data:any in ... do {if data isa int then let i-data:int = data asa int {inc sum, i-data} elseif data isa double then let d-data:double = data asa double {inc sum, d-data} elseif data isa String then let s-data:String = data asa String {inc sum, {s-data.to-double}} else {error {format "無効なデータ:%s", data}} } {inc count} } {return {if count > 0 then sum / count else 0.0}} } average = {average 4, 6, 2.3, 4, "12", "5.2", 1, 3.1, "12.4", 1.9}
実行結果です(図3)。
switch式(マクロ)
今度は、先ほどのサンプルプログラムをswitch式で書いてみます。switch式では、switch の後に書かれた変数と case で指定された値と比較を行う演算子の指定ができます。今回は、isa演算子を使った比較を行いたいので、switch の後に、using isa を指定しています。
{curl 7.0 applet} {curl-file-attributes character-encoding = "shift-jis"} || switch ... using isa を使ったプロシージャ || {define-proc public {average ...:any}:double let sum:double = 0 let count:int = 0 {for data:any in ... do {switch data using isa case int do let i-data:int = data asa int {inc sum, i-data} case double do let d-data:double = data asa double {inc sum, d-data} case String do let s-data:String = data asa String {inc sum, {s-data.to-double}} else {error {format "無効なデータ:%s", data}} } {inc count} } {return {if count > 0 then sum / count else 0.0}} } average = {average 4, 6, 2.3, 4, "12", "5.2", 1, 3.1, "12.4", 1.9}
type-switch式(マクロ)
switch式では、using isa で比較に使用する演算子を指定して、その値を asa演算子でキャストして利用しました。その2つを同時に行ってくれるのが、type-switch式になります。type-switch式でサンプルプログラムを書き直してみます。
{curl 7.0 applet} {curl-file-attributes character-encoding = "shift-jis"} || type-switch を使ったプロシージャ || {define-proc public {average ...:any}:double let sum:double = 0 let count:int = 0 {for data:any in ... do {type-switch data case i-data:int do {inc sum, i-data} case d-data:double do {inc sum, d-data} case s-data:String do {inc sum, {s-data.to-double}} else {error {format "無効なデータ:%s", data}} } {inc count} } {return {if count > 0 then sum / count else 0.0}} } average = {average 4, 6, 2.3, 4, "12", "5.2", 1, 3.1, "12.4", 1.9}
switch の内部がとてもすっきりしました。
最後に
Curl言語の中枢にあるデータ型について見てきました。プリミティブ型、クラス型、プロシージャ型などがあり、すべてオブジェクトとして扱うことが可能です。データ型のすべてがTypeクラスのサブクラスのインスタンスとして関連付けられていました。Typeクラスおよびそのサブクラスを利用することで、強力なリフレクション機能を実現できます。
最後にデータ型の判定方法をサンプルプログラムを通して説明しました。データ型は簡単そうに見えて、奥が深い世界です。いろいろ試してみてください。