構想にて、キーワード ref
は関数を参照するために用いると記述しました。Luryでは、引数のない関数を括弧なしで呼び出せます。
def func:
return 1
value = func + func # value == 2
このとき、関数funcそのものを参照したいときにref
を用いないとfuncが実行され、その返却値が式の値となってしまいます。
def judge(cond, f):
f if cond
i = 42
judge(i > 10, func) # func == 1
judge(i > 10, ref func) # func is Function
ところで、プロパティの場合は ref get
および ref set
でgetterとsetterを参照することができます。
ここからが本題。問題となったのは、ref
を関数以外のオブジェクトに使った場合の挙動と意味です。これまではref
を関数オブジェクト以外に用いることは__実行時にエラーとする__よう構想されていました。関数(とプロパティ)以外のオブジェクトは識別子から直接そのオブジェクトを参照することができ、ref
を使う必要などなかったからです。
integer = 42
string = 'hogehoge'
object = new Object
function = () => 3.5
integer_ref = integer # 実際は参照コピーではなく値コピー
string_ref = string
object_ref = object
function_ref = ref function
ところがLuryは動的(実行時)に変数の型が決定するため(動的型付け言語)、関数型であるかどうかをチェックする際にref
問題が発生します。
value = user_read()
if (value > 3):
function = () => 3.5
else:
function = 5
if ref function is Function:
function()
else:
function++
上記の例では関数の実行箇所の括弧を省略せずに記述しました。もしref
が関数オブジェクト以外のときエラーとなるなら、2つ目のif文では実行時にエラーが発生し、賢明なユーザならばこの条件文をtry...catch文で囲むでしょう。上記の処理は極端な場合ですが、同様の問題は関数型であるかをチェックする処理全てで発生します。
extended class List:
extended def replace(list, condition, replacer):
for i in list:
if (ref condition is Function || condition(i)) && condition:
if ref replacer is Function:
yield replacer(i)
else:
yield replacer
else:
yield i
data = [1, -5, 3, 4, -7, 2, 1]
data.replace(n => n < 0, n => -n) # data == [1, 5, 3, 4, 7, 2, 1]
解決策として_ref
を関数オブジェクト以外の参照にも使えるようにする_と考えています。こうすることで、エラーを防ぎ、煩雑な例外処理の配置も必要がなくなります。
integer = 42
string = 'hogehoge'
object = new Object
function = () => 3.5
integer_ref = ref integer # 実際は参照コピーではなく値コピー
string_ref = ref string
object_ref = ref object
function_ref = ref function
ただしここで問題が残ります。上記の integer_ref
が参照コピーではなく値コピーであることです。
integer = 42
integer_ref = ref integer
integer_ref++
println(integer) # 42
println(integer_ref) # 43
もしこの変数integer
を参照したい場合は関数などで間接的にアクセスさせる必要があります。
integer = 42
property integer_ref:
get => integer
set => integer = value
integer_ref++
println(integer) # 43
println(integer_ref) # 43
integer = 42
def add(ref value):
return value++
println(add(integer)) # 43
println(integer) # 43
しかし関数の引数にref
を使って、値渡しから参照渡しにするという用法もあります。関数の引数以外の場所でref
を使うことで、「値型のオブジェクトを参照型のように扱える」という誤解が生じる恐れは払拭できません。そもそも値型は必要なのかという議論も再燃する恐れもあります。(検証が必要)
結局のところ、ref
は__指定されたメンバそのものにアクセスする__という意味で用いており、参照という言葉は使わない方針です。