Skip to content

Instantly share code, notes, and snippets.

@nanase
Last active August 29, 2015 14:20
Show Gist options
  • Save nanase/9fc193e607ef0fdf89ee to your computer and use it in GitHub Desktop.
Save nanase/9fc193e607ef0fdf89ee to your computer and use it in GitHub Desktop.
Lury 問題点と方針

Lury 問題点と方針

ref問題

構想にて、キーワード 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は__指定されたメンバそのものにアクセスする__という意味で用いており、参照という言葉は使わない方針です。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment