チケット #68 (new discussion)

登録: 1 年 前

最終更新: 1 年 前

Thread: next, error, event, interrupted, timeout でのパラメータ受け渡し

報告者: yossy 担当者: yossy
優先度: major マイルストーン: ActionScript Thread Library 1.1
コンポーネント: Thread キーワード:
関係者:

チケットの概要 (最終更新者: yossy)

Thread.next で、次のようにパラメータを次の実行関数に受け渡せたら便利じゃないですか?

protected override function run():void
{
    next(func, ['abc', 123]);
}

private function func(s:String, n:uint):void
{
    trace(s, n); // abc 123
}

interrupted と timeout も同様。

で、こっからがちょっと議論で、エラーハンドラとイベントハンドラで、毎回引数書くのは面倒じゃないか? (いらない場合も多い) ということで、次の二つの提案。

ひとつめは、引数からは外して、Thread のインスタンスプロパティにしてしまうという方法。次のような感じ。

protected override function run():void
{
    error(Error, errorFunc);
    event(eventFunc, target, 'event');
}

private function errorFunc():void // e:Error と t:Thread 引数が無くなる
{
    trace($error, $errorThread); // 代わりに $error と $errorThread プロパティで取れる (名前は暫定)
}

private function eventFunc():void // e:Event 引数が無くなる
{
    trace($event); // 代わりに $event プロパティで取れる (名前は暫定)
}

受け渡しパラメータつきの場合は

protected override function run():void
{
    error(Error, errorFunc, ['abc', 123]);
    event(eventFunc, target, 'event', ['abc', 123]);
}

private function errorFunc(s:String, n:uint):void // e:Error と t:Thread 引数が無くなる, 引き渡されたパラメータわたってくる
{
    trace($error, $errorThread); // 代わりに $error と $errorThread プロパティで取れる (名前は暫定)
}

private function eventFunc(s:String, n:uint):void // e:Event 引数が無くなる, 引き渡されたパラメータわたってくる
{
    trace($event); // 代わりに $event プロパティで取れる (名前は暫定)
}

ふたつめは、パラメータ指定に入れ込むという方法。

protected override function run():void
{
    error(Error, errorFunc, [$ERROR, 'abc', $ETHREAD, 123]); // $ERROR, $ETHREAD (名前は暫定) でエラーとエラースレッドが引数として欲しい!と宣言
    event(eventFunc, target, 'event', [$EVENT, 'abc', 123]); // $EVENT (名前は暫定) でイベントが引数として欲しい!と宣言
}

private function errorFunc(e:Error, s:String, t:Thread, n:uint):void // 指定された部分に渡ってくる
{
}

private function eventFunc(e:Event, s:String, n:uint):void // 指定された部分に渡ってくる
{
}

こうしたほうがいい、ああしたほうがいい、いやこうだろ、ああだろ、そもそもこんなのいらない、いやいるよなどご意見募集です!!

添付ファイル

チケットの履歴

2009/03/04 16:30:56 更新者:yossy

捕捉。error と event の引数をなくす件についてはドラスティックな変更になるので (互換性が無くなる)、実装するのであれば、一旦これを入れずにパラメータ引渡しだけ実装して 1.1 を出して、その後引数なくしたバージョンを 1.5 なんかで出すことになるかと思います。

2009/03/04 16:31:51 更新者:yossy

  • 説明 が更新されました。

2009/03/04 22:59:31 更新者:nobu

next で設定した実行関数に引数を渡せるのって素敵ですねー。

LoaderThread や URLLoaderThread なんかを、わざわざプロパティとして持っておく必要が無くなるので、ものっそい省エネな香りがします。 で、個人的には可変長引数で渡せたら良いなぁ。なんて。

protected override function run():void
{
    //  コレよりかは、
    next(func, ['abc', 123]);

    //  こっちが良いと思うんだ。
    next(func, 'abc', 123);
}

private function func(s:String, n:uint):void
{
    trace(s, n);    //  abc 123
}

あくまでも個人の好みなのですが、 [] とか {} とかがネストされまくってるのを見ると、それだけで萎えてしまうので、 出来る限りそれを無くしたいな。って思うのです。速度面は実装面は全くもって考慮せずに書いている訳ですが。 interrupted や timeout も同じ感じで出来ると楽できて良いですよね。

で、ココから議論の部分。

エラーハンドラやイベントハンドラは、既存の状態で十分考えられていて使いやすいし、イベントハンドラに関しては addEventListener と同じインターフェイスだし、 この2つに関しては、このままで変更する必要は無いような気がしますよ。 これらまで任意の引数を取れるようにしてしまうと、なんとなく黒魔術的な雰囲気が見え隠れしてしまって、個人的には好きくありません。

next, interrupted, timeout が引数を取れるようになるだけで、抜群に使い勝手が上がると思いまーす :-)

2009/03/04 23:15:42 更新者:yossy

レスありがとうございます!

まず可変長引数について。僕も最初は可変長引数がいいなーと思ってたのですが、event が問題児で、可変長引数にしてしまうと、余計な引数 (priority とか) も指定しなきゃならなくなるので (そしてこれらよりはパラメータの方が優先順位高いかなと思ったので)、配列という形で四番目に持ってきました。event だけ配列指定なのは混乱を招くので、他もそれに揃えた次第です。

んで、エラーハンドラやイベントハンドラ。確かに黒魔術的な雰囲気は否めないのですが、もしパラメータ受け渡しを実装するのであれば、やはりこいつらがパラメータ受け渡せないのはおかしいだろうと。特定のイベントが起こった場合に割り込みを掛けたい場合など、やはりプロパティとして持たなきゃいけなくなるので、残念な感じです。

黒魔術的な雰囲気が好ましくないということであれば、error, errorThread, event 引数は今まで通り固定で、これらに引き渡しパラメータが追加されるという案はどうでしょう?

2009/03/04 23:35:04 更新者:nobu

さすがレスポンス早いですね!

やっぱ可変長引数には、なにかしら問題があったんですねー。納得です。それならば無理に可変長にするよりかは、全て配列で渡すように統一するほうがスマートですね。

エラーハンドラ・イベントハンドラに関しても、現状の引数は固定で、その上でさらに任意の引数が取れる。ってのは素敵ですねー。やっぱイベントハンドラに追加でパラメータを渡したい。ってニーズも全然有る訳ですしね。

ここまで出来れば、今までしゃーなしでプロパティに持たせてたパラメータが、ずいぶんと減らせそうですよね :-)

2009/03/04 23:44:10 更新者:yossy

なるほど了解です!

というわけで、単に今までの引数にパラメータが追加されるというのも候補に入れたいと思います。

protected override function run():void
{
    error(errorFunc, ['abc', 123]);
    event(eventFunc, target, 'event', ['abc', 123]);
}

private function errorFunc(e:Error, t:Thread, s:String, n:uint):void // 引き渡されたパラメータは Error と Thread の後に来る
{
}

private function eventFunc(e:Event, s:String, n:uint):void // 引き渡されたパラメータは Event の後に来る
{
}

2009/03/05 00:14:56 更新者:yossy

  • マイルストーンActionScript Thread Library 1.1 に更新されました。

( フォローアップ: ↓ 11 ) 2009/03/05 01:32:38 更新者:kaikoga

パラメータの渡し方の議論に先立ち、next()でのパラメータの受け渡しを今のThreadで頑張って書こうとしたら書けてしまいました。

protected override function run():void
{
	next(function():void { func('abc', 123); } );
}

private function func(s:String, n:uint):void
{
	trace(s, n); // abc 123
}

errorとかeventもこのままで動くかどうかはあまり確かめてませんがたぶん似たような感じで書けてしまうでしょう。(実行関数の連鎖がThreadオブジェクトを飛び出してしまうのは、Threadのデザインパターン的にとても非推奨な書き方のような気がするのはさておき)

private function hoge():void
{
	error(Error, function(e:Error, t:Thread):void { errorFunc(e, t, 'abc', 123); } );
	event(target, 'event', function(e:Event):void { eventFunc(e, 'abc', 123); } );
}

以上のような事を考えると、真に必要なのは「追加のパラメータを実行関数の引数として渡せる」ことではなく、「実行関数として使うための、指定した関数にパラメータを渡して実行させるクロージャ(のようなもの)をよりわかりやすく記述できる」ことなのではないでしょうか?
(実装が本当にクロージャの生成になっているかどうかには関わらず)

たとえばこんな風に、Functionの代わりにArrayを渡すと中身のFunctionにパラメータを渡して呼び出してくれるという書き方が考えられるでしょう。(当然今までのようにFunctionをそのまま渡すのもアリで)

protected override function run():void
{
	//next(func);
	next([func, 'abc', 123]);
}

この書き方の最大の利点としては、errorとかeventの引数を1.0の渡し方で書いたコードはそのまま使える事が挙げられます。

private function hoge():void
{
	error(Error, errorFunc1);
	error(Error, [errorFunc2, 'abc', 123]);
	event(eventFunc1, target, 'event');
	event([eventFunc2, 'abc', 123], target, 'event');
}

nextの引数として関数も配列も渡せるというのがすごく説明しづらい(例えば、String.replace()を黒魔術と感じるかどうかは人それぞれ)というわりと重大な欠点があるので、参考意見として取ってくれるとありがたいです。

(親コメント: ↑ チケットの概要 ; フォローアップ: ↓ 12 ) 2009/03/05 01:37:35 更新者:yoshihiko

毎回引数書くのは面倒じゃないか?

これ解決したらすごく便利です!!

ここからは実験してないので、勝手な想像になるのですが、errorやeventを単体のクラスとして作成して、それぞれのインスタンスにハンドラーとかを割り当て、スコープをインスタンスにするのってできますかね? イメージとしてはこんな感じ。

protected override function run():void
{
  var error = new Error();
  error.setHandler(this, errorFunc, ['abc', 123]);//ターゲットと関数を指定
  error.throw = "エラーメッセージ";
  error.trace = "trace用エラーメッセージ";
  error.console = "FireBugs用エラーメッセージ";

  Error.setHandler(root, defaultErrorFunc); //静的メソッドを利用して、このエラーが発生した際の共通ハンドラーを登録
}
private function errorFunc(s:String, n:uint):void
{
  //関数実行時のscopeはerrorインスタンスに設定→thisでerrorインスタンスのプロパティを取得
  trace(this.target) //エラー処理のターゲット
  trace(this.thread) //エラースレッド
}

private function defaultErrorFunc():void //rootにあると仮定
{
  //このエラーが出たら必ず終了
  this.target.end();
}

静的メソッドで共通ハンドラーを指定することで、同じエラー処理を何度も書かなくてすませられるとよいかも。

イベントも同じような感じで

protected override function run():void
{
  var event = new Event(); //引数にターゲットを指定
  event.setHandler(Event.INIT, this, eventFunc);
  event.setHandler(Event.COMPLETE, this, eventFunc2, ['abc', 123]);
}
private function eventFunc():void
{
  //関数実行時のscopeはeventインスタンスに設定→thisでeventインスタンスのプロパティを取得
  trace(this.target) //イベント実行時のターゲット
  trace(this.event) //イベント名
}
private function eventFunc2(s:String, n:uint):void
{
}

こんな感じでインスタンスとして扱えるようになれば、エラーやイベントクラスの拡張時にインスタンスプロパティを宣言するだけでハンドラー内で利用できるのと、メッセージの出力などを前もって宣言できるのではないかと。

インスタンスにしなくても、error()関数実行時にスコープ引き渡すだけでthis以下で取れるだけで便利ですが。

以上、いろいろ勝手に書いてみました。

2009/03/05 01:38:41 更新者:yossy

  • 説明 が更新されました。

(親コメント: ↑ 8 ; フォローアップ: ↓ 13 ) 2009/03/05 01:42:33 更新者:yossy

kaikoga さんありがとうございます!

まず、今まで説明の部分で error のエラーの型指定が抜けていたので、もしそれのことを言われていたらごめんなさい。

で、これなんですが、

private function hoge():void
{
	error(Error, errorFunc1);
	error(Error, [errorFunc2, 'abc', 123]);
	event(eventFunc1, target, 'event');
	event([eventFunc2, 'abc', 123], target, 'event');
}

これって

private function hoge():void
{
	error(Error, errorFunc1);
	error(Error, errorFunc2, ['abc', 123]);
	event(eventFunc1, target, 'event');
	event(eventFunc2, target, 'event', ['abc', 123]);
}

とほとんど変わらなくないですか?(event だけはちょっと変わってしまいますが) 1.0 での書き方ももちろん出来ます。

問題となるのは、errorFunc と eventFunc 側の引数な気がします。

(親コメント: ↑ 9 ) 2009/03/05 01:51:57 更新者:yossy

yoshihiko さんありがとうございます!

なるほどなるほどー!ただちょっと複雑さが増してしまう感がありますね…。アイデアは面白いので、ちょっと温めてみます!!

(親コメント: ↑ 11 ) 2009/03/05 02:26:28 更新者:kaikoga

yossy への返信

レスありがとうございます。

引数の件ですが、関数と引数の両方を Array の中に入れてしまうのは、オプション引数を含めた引数の位置を 1.0 と合わせることによって error と event 側の互換性を確保し、これらの呼び出しを書き直さなくても良いようにするためです。

private function hoge():void
{
	error(Error, errorFunc1, true); //1.0
	error(Error, errorFunc2, ['abc', 123], true); //1.1
	event(eventFunc1, target, 'event', false, 0, true); //1.0
	event(eventFunc2, target, 'event', ['abc', 123], false, 0, true); //1.1
}

このような場合、 1.0 の書き方と 1.1 の書き方を両方受け入れるようにするのはあまり良くなさそうな気がします。

かといって、 error や event の呼び出しを書き直す必要性が生じるとしたら、どっちみち 1.0 との互換性がなくなるので 1.1 をすっ飛ばしてバージョン 1.5 で良いと思います。

オプション引数なんて誰も使ってねーよとの事でしたら、ごめんなさい。

( フォローアップ: ↓ 15 ) 2009/03/05 03:09:32 更新者:anonymous

書き方の問題かもしれませんが、

protected override function run():void
{
     var loader:Loader=new Loader();
     var t:LoaderThread=new LoaderThread(new URLRequest("hoge.swf"),null,loader));
     t.start()
     t.join()
     next(nextFunc)
}

てな風にローカル変数使う事が多く、 nexfuncにloaderわたしたいなーとか、

同様にeventでThreadに割り込みたいときなどに、インスタンス変数においとくのが少し面倒だったので、 引数渡せると便利きわまりないです。

これがいいと提案等はできないのですが、上で言われてるように、 「error, errorThread, event 引数は今まで通り固定で、これらに引き渡しパラメータが追加されるという案」 が、僕の中ではしっくりくるきがします。

(親コメント: ↑ 14 ) 2009/03/05 03:15:18 更新者:yossy

ありがとうございます!

なるほどー、やっぱり渡したいですよね。1.0 の流れからいくと、「error, errorThread, event 引数は今まで通り固定で、これらに引き渡しパラメータが追加されるという案」がやっぱり一番自然で受け入れやすいとは思います。

2009/03/05 12:20:35 更新者:muta244

開発お疲れさまです!

今までの話の流れに水を差す感じになってしまいますが、 一つ目の提案の Event と Error のインスタンスは Thread のプロパティで扱うというのが良いんじゃないかと思います。 二つ目(現在も)だと interrupted(func) で指定する func だけが特定の引数を取らないので、どうだっけ?ってなってしまう気がします。

Thread で指定するハンドラ関数は基本的には引数を取らない(ユーザー指定の引数のみ取る)という形に統一しておく方が、 使う側が迷うことも無くなるのかなと個人的には思いました!

まだ、Ver.1 なんで変更するなら今のうちですしね。


追記/更新 #68 (Thread: next, error, event, interrupted, timeout でのパラメータ受け渡し)