2011-01-25 10 views
11

私はScalaがALGOLの名前による呼び出しをサポートしていることを知っています。その意味を理解していると思いますが、C#、VB.NET、C++のようにScalaが呼び出しを参照することはできますか?私はJavaが参照による呼び出しを行うことができないことを知っていますが、この制限が言語またはJVMのみに起因するかどうかはわかりません。Scalaは参照によって呼び出し可能ですか?

これは、膨大なデータ構造をメソッドに渡したいが、そのコピーを作成したくない場合に便利です。この場合、参照による呼び出しは完璧なようです。

+1

私は、あなたがScalaで価値のあるデータ構造を渡すことはできないと思いました。 – Gabe

+0

@Gabeこれはまだ[値渡し/通話]です(http://en.wikipedia.org/wiki/Evaluation_strategy)(AnyRefの型の値渡しの値渡しのオブジェクト参照とPython/Javaの人々はこれを「参照渡し」という言葉を悪用するのが好きです。しかし、pass/by-by-referenceは、関数*で変数*を設定すると渡された変数の値を設定することを意味します(VBではC++では '&ref'、VBでは' ByRef'、C#では 'out/ref') 。これは渡されたオブジェクトと状態の突然変異で*エミュレートされますが、同じではありません(Cはポインタで参照される値を変更することでCをエミュレートできます)。 –

+1

@pst:私は「メソッドに膨大なデータ構造を渡す」部分を参照していました。 Scalaには、データ構造を関数に渡すときにデータ構造をコピーすることを知らされていなかったか、またはデータ構造がすでに参照渡しされていて、OPからの引用は無関係です。 – Gabe

答えて

34

JavaとScalaはどちらも、値がプリミティブまたはオブジェクトへのポインタのいずれかであることを除いて、呼び出しを値だけで使用します。オブジェクトに変更可能なフィールドが含まれている場合は、これと参照との間には実質的な差はほとんどありません。

オブジェクトにポインタを常に渡しているので、オブジェクト自体ではなく、巨大オブジェクトを繰り返しコピーする必要はありません。

ちなみに、名前によるスカラの呼び出しは、値による呼び出しを使用して実装されています。値は、式の結果を返す関数オブジェクトへのポインタです。

+0

効果がある変更可能なフィールドに関するあなたの要点について詳しく説明できますか? – royco

+1

さて、変数 'x'を変更したいとします。 Cで 'int * x'として渡すことができます。 Scalaでは、クラスに 'class X(var x:Int)'という変数を保持させます。そのクラスをあるメソッドに渡すと、 'x'の値を変更できます。 –

+11

スカラが値の呼び出しを排他的に使用すると、その言語とその実装を混同しているとします。アセンブラに行くと、すべての言語が排他的に値で呼び出されます。 Scala _could_は、参照またはプリミティブを渡すためのコンテナオブジェクトを作成し、呼び出しが返ったときにそのコンテナから読み取るなど、JVMでの参照による呼び出しをサポートします。 –

0

「すべてがオブジェクトです」、オブジェクト参照にアクセスできない言語(例: JavaおよびScalaの場合、すべての関数パラメータは、言語より下の抽象レベルで渡される参照です。しかし、言語抽象化のセマンティクスの観点からは、関数が参照されたオブジェクトのコピーを提供されているかどうかによって、参照による呼び出しまたは値による呼び出しがあります。この場合、共有による呼び出しという用語には、抽象化の言語レベルでの参照による呼び出しと値による呼び出しの両方が含まれています。したがって、Javaは、言語セマンティクスよりも抽象度が低い(つまり仮想マシンの場合はCまたはバイトコードに変換される方法と比較して)抽象度の高い値で呼び出され、JavaおよびScalaは、 "すべてがオブジェクトです"という抽象概念のセマンティクスで参照渡し(組み込み型を除く)です。

JavaおよびScalaでは、組み込み型(a/k/aプリミティブ)の型は自動的に値渡し(intまたはIntなど)され、すべてのユーザー定義型が渡されます(つまり、彼らは彼らの価値だけを渡す)。

注これをより明確にするために、WikipediaのCall-by-sharing sectionを更新しました。

おそらく、ウィキペディアは、値渡しと呼び出しによる呼び出しの区別について混乱しているのでしょうか?代入式や関数の適用に適用されるように、値渡しがより一般的な用語であると私は考えました。私はWikipediaでその訂正をしようとする気にはならなかった。

オブジェクトが不変の場合、参照によるコールと値渡しの間に「すべてがオブジェクトです」というセマンティクスのレベルに違いはありません。したがって、値による呼び出しと参照による呼び出しの宣言を可能にする言語(私が開発しているScalaのような言語のような)は、オブジェクトが変更されるまで値のコピーを遅らせることによって最適化することができます。


これを明らかに投票した人々は、「共有による呼び出し」が何であるか分かりません。

以下、評価戦略について議論している私のCopute言語(JVMをターゲットにしています)の書き込みを追加します。


純粋であっても、チューリング完全言語再帰を可能にする)は、評価戦略を選択しなければならないため、完全に宣言的です。評価戦略は、関数とその引数の間の相対的なランタイム評価順序です。関数の評価戦略は、すべての式が関数であるため、それぞれ厳密または怠惰と同じ厳密または非厳密にすることができます。 Eagerは、関数の前に引数式が評価されることを意味します。 lazyは引数の式が関数内での最初の使用の実行時にのみ評価されることを意味します。 評価戦略は、パフォーマンス、決定論、デバッグ、およびオペレーショナルセマンティクスのトレードオフを決定します。純粋なプログラムの場合、評価順序の不可欠な副作用は、メモリ消費、実行時間、待ち時間、および非終端ドメインで非決定性を引き起こす(すなわち、断定的に限定される)ため、意味的セマンティクスの結果を変更しません。入力が1つの純粋な関数であり、バイナリ演算子は2つの入力を持つ純粋な関数であり、コンストラクタは関数であり、さらには制御文でもあります(例えば、)。 if、for、while)を関数でモデル化することができます。これらの関数を評価する順序は、構文では定義されていません。 f(g())はgの結果をfに評価することができ、fの中でその結果が必要なときにlをゆっくりと評価することができる。

前者(eager)はコールバイバリュー(CBV)であり、後者(lazy)はcall-by-name(CBN)です。 CBVには、Java、Python、Rubyなどの現代的なOOP言語で広く使われている、別の呼び出しごとのバリアントがあります。 CBNには、関数の引数が一度しか評価されない(関数をメモする関数と同じではない)バリアントコールバイニング(CBN)もあります。指数関数的に高速であるため、コールバイニングは名前の代わりにほとんど常に使用されます。通常、CBNの両方のバリアントは、宣言された関数階層と実行時の評価順序の間の不協和音のために純粋にしか現れません。

言語には通常、デフォルトの評価方法があり、一部にはオプションで、デフォルト以外の機能で評価されるように強制するための構文があります。デフォルトで熱望している言語は、通常、第2オペランドが第2オペランドではないため、論理演算子(a/k/a "と" & &)と論理和(a/k/a "または"、||場合の半分に必要な、すなわち真実||何か==真と偽& &何か== false。

+0

ここに参考文献があります:http://lambda-the-ultimate.org/node/4180#comment-64168 –

0

Scalaで参照パラメータをエミュレートする方法は次のとおりです。

def someFunc(var_par_x : Function[Int,Unit]) { 
    var_par_x(42) // set the reference parameter to 42 
} 

var y = 0 
someFunc((x => y=x)) 
println(y) 

まあ、PascalやC++のプログラマーがよく慣れているものではありません。 Scalaではごくわずかです。これは、呼び出し側に、パラメータに送信される値でできることをより柔軟にすることができる点です。例えば。

someFunc((x => println(x))) 
関連する問題