2

編集: この質問の原因となったバグは修正されました。


Scala リファレンスで、私は読むことができます (p. 86):

単純変数 x = e への割り当ての解釈は、x の定義によって異なります。x が変更可能な変数を表す場合、代入によって x の現在の値が式 e の評価結果に変更されます。e の型は x の型に適合することが期待されます。x が何らかのテンプレートで定義されたパラメーターなしの関数であり、同じテンプレートにセッター関数 x_= がメンバーとして含まれている場合、代入 x = e はそのセッター関数の呼び出し x_=(e) として解釈されます。同様に、パラメーターなしの関数 x への代入 f .x = e は、呼び出し f.x_=(e) として解釈されます。

したがって、たとえば、次のようなものがうまく機能します。

class A {
  private var _a = 0
  def a = _a
  def a_=(a: Int) = _a = a
}

私はそれから書くことができます

val a = new A
a.a = 10

しかし、このようにクラスを定義すると、型パラメーターをメソッド a に追加します。

class A {
  private var _a = 0
  def a[T] = _a
  def a_=(a: Int) = _a = a
}

その後、それは機能しなくなります。error: reassignment to valと書くと が得られますa.a = 10。面白いことに、たとえば、型パラメーターがなくても暗黙的なパラメーター リストが使用されても機能します。

おそらく、この例では、型パラメーターはあまり役に立ちませんが、DSL の設計では、getter に型パラメーターがある場合でも、setter メソッドが呼び出されると便利です (ちなみに、setter に型パラメーターを追加します)。許可され、正常に動作します)。

だから私は3つの質問があります:

  1. 回避策はありますか?
  2. 現在の動作はバグと見なす必要がありますか?
  3. コンパイラが getter メソッドを強制して setter に構文糖衣を使用できるようにするのはなぜですか?

アップデート

これが私が本当にやろうとしていることです。かなり長いです。申し訳ありませんが、避けるつもりでしたが、省略した方が混乱を招くことに気付きました。

私は Scala で SWT を使用して GUI を設計しており、Dave Orme のXScalaWTを使用して非常に楽しんでいます。これにより、必要なコードの量が大幅に削減されます。Composite°C を °F 度に変換する SWT の作成方法に関する彼のブログ投稿の例を次に示します。

var fahrenheit: Text = null
var celsius: Text = null

composite(
  _.setLayout(new GridLayout(2, true)),

  label("Fahrenheit"),
  label("Celsius"),

  text(fahrenheit = _),
  text(celsius = _),

  button(
    "Fahrenheit => Celsius",
    {e : SelectionEvent => celcius.setText((5.0/9.0) * (fahrenheit - 32)) }
  ),
  button(
    "Celsius -> Fahrenheit",
    {e : SelectionEvent => fahrenheit.setText((9.0/5.0) * celsius + 32) })
  )
)

ウィジェットを構築する各メソッドの引数は type(WidgetType => Any)*であり、いくつかの便利な暗黙の変換があります。これにより、たとえば、setText()メソッドを持つウィジェットの文字列を直接指定できます。すべてのコンストラクター関数は、シングルトン オブジェクトからインポートされます。

最後に、次の行に沿って何かを書きたいと思います。

val fieldEditable = new WritableValue // observable value

composite(
  textField(
    editable <=> fieldEditable,
    editable = false
  ),
  checkbox(
    caption = "Editable",
    selection <=> fieldEditable
  )
)

これにより、テキストフィールドの編集可能なプロパティが、WritableValue 変数を介してチェックボックスの選択にバインドされます。

まず、名前付き引数はここでは適用できないため、行editable = falseはどこかから来ている必要があります。したがって、シングルトン オブジェクトのウィジェット構築メソッドに沿って、概念的には次のように記述できます。

def editable_=[T <: HasEditable](value: Boolean) = (subject: T) => subject.setEditable(value)

...しかし、これはゲッターも存在する場合にのみ機能します。すばらしい: <=> でデータバインディングを実装するには、とにかくゲッターが必要です。このようなもの:

def editable[T <: HasEditable] = new BindingMaker((widget: T) => SWTObservables.observeEditable(widget))

これが機能すれば、BindingMaker で <=> を定義でき、この優れた構文を使用できるため、人生はうまくいくでしょう。しかし残念なことに、ゲッターの型パラメーターはセッターを壊します。したがって、私の最初の質問: この単純な型パラメーターが、コンパイラーがセッターを呼び出すための構文糖衣を使用するかどうかに影響するのはなぜですか?

これで少しわかりやすくなったと思います。読んでくれてありがとう…</p>

4

1 に答える 1

4

UPDATE新しい情報に照らして、以前の回答全体を削除しました。

ここでは非常に奇妙なことがたくさん起こっているので、私はあなたがこれまでに持っているものについての私の理解を説明しようと試みます:

def editable_=[T <: HasEditable](value: Boolean) = (subject: T) => subject.setEditable(value)

これはセッターメソッドであり、DSLで名前付きパラメーターを使用しているように見せるために純粋に存在します。何も設定せず、実際に関数を返します。

textField(
  editable <=> fieldEditable,
  editable = false
)

これは、名前付きパラメーターのように見えるtextFieldファクトリメソッドを呼び出していますが、実際には以前に定義されたセッターメソッドです。

驚くべきことに、コンパイラがこれを名前付きパラメータとして認識し、構文エラーを生成するという私の最初の懸念にもかかわらず、このアプローチは機能しているようです。私はそれを単純な単相(非ジェネリック)メソッドでテストしましたが、セッターがそのように見えるようにゲッターメソッドを定義する必要があります-あなたがすでに指摘した事実です。

DSLを作成する際には、ある程度の「賢さ」が必要になることがよくあります(そうでなければ完全に禁止されます)。したがって、当初の意図が不明確だったのは当然のことです。これはおそらく、Scalaではこれまで見られなかったまったく新しい手法です。セッターとゲッターの定義のルールは、それらをゲッターとセッターとして使用することに基づいていたので、このように境界を押したときに少しひびが入っても驚かないでください。

ここでの本当の問題は、タイプパラメータの使用方法にあるようです。この式では:

def editable_=[T <: HasEditable](value: Boolean) = (subject: T) => subject.setEditable(value)

コンパイラには、提供された引数から特定のものを推測する方法がないTため、許可されている最も一般的な型(HasEditableこの場合)を使用します。メソッドを使用するときに型パラメーターを明示的に指定することでこの動作を変更できますが、それはあなたが達成しようとしていることの全体的なポイントを打ち負かすように思われます。

関数をジェネリックにすることはできない(メソッドのみができる)ことを考えると、型の境界さえ必要だとは思えません。したがって、試すことができる1つのアプローチは、それらを削除することです。

def editable_=(value: Boolean) = (subject: HasEditable) => subject.setEditable(value)
def editable = new BindingMaker((widget: HasEditable) => SWTObservables.observeEditable(widget))
于 2011-02-11T09:55:42.403 に答える