「Example11.1」の編集履歴(バックアップ)一覧はこちら
Example11.1 - (2011/02/24 (木) 08:52:41) の1つ前との変更点
追加された行は緑色になります。
削除された行は赤色になります。
#co(){
11.1 Stateful Objects
We normally view the world as a set of objects, some of which have state that changes over time. Normally, state is associated with a set of variables that can be changed in the course of a computation. There is also a more abstract notion of state, which does not refer to particular constructs of a programming language: An object has state (or: is stateful) if its behavior is influenced by its history.
}
** 11.1 状態を持つオブジェクト (Stateful Object)
我々は世界をオブジェクトの集合としてとらえ、オブジェクトの中には時間と共に変化する状態を持つものもあります。通常、状態は計算の過程で変化しうる変数の集合と結びついています。プログラミング言語の特定の構文に触れずに、状態を抽象化して言うと、「もしオブジェクトの振る舞いがその履歴に影響されるなら、オブジェクトは&bold(){状態を持つ} (&bold(){ステートフル}である)。」となります。
#co(){
For instance, a bank account object has state, because the question "can I withdraw 100 CHF?" might have different answers during the lifetime of the account.
}
たとえば、銀行口座オブジェクトは状態を持ちます。なぜなら「100スイスフラン引き出せるか?」は口座の存続期間、異なる答を持ちうるからです。
#co(){
In Scala, all mutable state is ultimately built from variables. A variable definition is written like a value definition, but starts with var instead of val. For instance, the following two definitions introduce and initialize two variables x and count.
}
Scala ではすべてのミュータブルな状態は、結局のところ、変数から作られます。変数定義は値定義と同じように書きますが、val の代わりに var で始まります。たとえば、次の2つの定義は2つの変数、x と count を導入し初期化します。
var x: String = "abc"
var count = 111
#co(){
Like a value definition, a variable definition associates a name with a value. But in the case of a variable definition, this association may be changed later by an assignment. Such assignments are written as in C or Java. Examples:
}
値定義と同様に変数定義は、名前と値を結びつけます。しかし変数定義の場合、この結びつきは後から代入によって変更できます。そのような代入は C や Java と同じように書きます。たとえば
x = "hello"
count = count + 1
#co(){
In Scala, every defined variable has to be initialized at the point of its definition. For instance, the statement var x: Int; is not regarded as a variable definition, because the initializer is missing(*2) . If one does not know, or does not care about, the appropriate initializer, one can use a wildcard instead. I.e.
}
Scala では定義する変数はすべて、定義の時点で初期化しければなりません。たとえば文、 var x: Int; は変数定義とみなされません。なぜなら初期値が無いからです(*2)。適切な初期値を知らない、あるいは気にしない場合は、代わりにワイルドカードを使えます。たとえば、
val x: T = _
#co(){
will initialize x to some default value (null for reference types, false for booleans, and the appropriate version of 0 for numeric value types).
}
は、x を何かデフォルト値 (参照型には null を、論理型には false を、数値型には適切な 0 を) で初期化します。
#co(){
Real-world objects with state are represented in Scala by objects that have variables as members. For instance, here is a class that represents bank accounts.
}
実世界のオブジェクトは、Scala では変数をメンバに持つオブジェクトとして表現されます。たとえば銀行口座を表現するクラスです。
class BankAccount {
private var balance = 0
def deposit(amount: Int) {
if (amount > 0) balance += amount
}
def withdraw(amount: Int): Int =
if (0 < amount && amount <= balance) {
balance -= amount
balance
} else error("insufficient funds")
}
#co(){
The class defines a variable balance which contains the current balance of an account. Methods deposit and withdraw change the value of this variable through assignments. Note that balance is private in class BankAccount - hence it can not be accessed directly outside the class.
}
このクラスは、口座の現在の残高を入れておく変数 balance を定義しています。メソッド deposit と withdraw は、代入によってこの変数の値を変更します。クラス BankAccount において、balance が private であることに注意して下さい。この結果、クラスの外からは直接アクセスできません。
#co(){
To create bank-accounts, we use the usual object creation notation:
}
銀行口座を作成するには、通常のオブジェクト生成の記法を使います。
val myAccount = new BankAccount
#co(){
Example 11.1.1 Here is a scalaint session that deals with bank accounts.}
&b(){例 11.1.1 } 次は銀行口座を扱う scala セッションです。
scala> :l bankaccount.scala
Loading bankaccount.scala...
defined class BankAccount
scala> val account = new BankAccount
account: BankAccount = BankAccount$class@1797795
scala> account deposit 50
unnamed0: Unit = ()
scala> account withdraw 20
unnamed1: Int = 30
scala> account withdraw 20
unnamed2: Int = 10
scala> account withdraw 15
java.lang.Error: insufficient funds
at scala.Predef$error(Predef.scala:74)
at BankAccount$class.withdraw(<console>:14)
at <init>(<console>:5)
scala>
#co(){
The example shows that applying the same operation (withdraw 20) twice to an account yields different results. So, clearly, accounts are stateful objects.
}
この例は、同じ操作 (withdraw 20) を口座に2回適用して、異なる結果が生じることを示します。したがって口座がステートフルなオブジェクトであることは明らかです。
#co(){
Sameness and Change. Assignments pose new problems in deciding when two expressions are "the same". If assignments are excluded, and one writes
}
&b(){同一性と変化 } 代入は2つの式が「同じ」かを判定する際に新しい問題をもたらします。もし代入が排除されている場合には、次のよう、
val x = E; val y = E
#co(){
where E is some arbitrary expression, then x and y can reasonably be assumed to be the same. I.e. one could have equivalently written
}
ただし E は何か任意の式であるとする、と書いた場合、x と y は無理なく同じと考えられます。つまり次のように書いても等価です。
val x = E; val y = x
#co(){
(This property is usually called referential transparency). But once we admit assignments, the two definition sequences are different. Consider:
}
(この性質は通常、&bold(){参照透過性}と呼ばれます) しかしもし代入を許したなら、上の2つの定義は異なります。次を考えて下さい。
val x = new BankAccount; val y = new BankAccount
#co(){
To answer the question whether x and y are the same, we need to be more precise what "sameness" means. This meaning is captured in the notion of operational equivalence, which, somewhat informally, is stated as follows.
}
この問題、x と y は同一であるか、に答えるには、「同一」の意味をより明確にしなければなりません。この意味は&bold(){操作的等価性}としてとらえられ、くだけた言い方をするなら、次のようになります。
#co(){
Suppose we have two definitions of x and y. To test whether x and y define the same value, proceed as follows.
}
仮に x と y の2つの定義があるとします。x と y とが同じ値を定義しているか調べるには、次のようにします。
#co(){{
- Execute the definitions followed by an arbitrary sequence S of operations that involve x and y. Observe the results (if any).
- Then, execute the definitions with another sequence S' which results from S by renaming all occurrences of y in S to x.
- If the results of running S' are different, then surely x and y are different.
- On the other hand, if all possible pairs of sequences {S, S'} yield the same results, then x and y are the same.
}}
- 定義を実行し、引き続いて x と y とを含む任意の操作列 S を実行し、(もしあれば) 結果を調べる。
- 次いで、定義を実行し、S 中のすべての y の出現を x で置き換えた、S から得られた列 S' を実行する。
- もし S' を実行した結果が異なれば、x と y は確かに異なる。
- もしすべての可能な操作列の組 {S, S'} に対して、同じ結果が得られるなら、x と y は同一である。
#co(){
In other words, operational equivalence regards two definitions x and y as defining the same value, if no possible experiment can distinguish between x and y. An experiment in this context are two version of an arbitrary program which use either x or y.
}
別の言い方をすれば、操作的等価性は2つの定義 x と y を、もしどんな実験でも x と y を区別できないなら、同じ値だとみなします。この文脈における実験とは、x あるいは y を用いる任意の2つのプログラムです。
#co(){
Given this definition, let's test whether
}
この定義を用いて、
val x = new BankAccount; val y = new BankAccount
#co(){
defines values x and y which are the same. Here are the definitions again, followed by a test sequence:
}
が、値 x と y を等しく定義するか確かめましょう。定義を再度行い、次いでテスト列を。
> val x = new BankAccount
> val y = new BankAccount
> x deposit 30
30
> y withdraw 20
java.lang.RuntimeException: insufficient funds
#co(){
Now, rename all occurrences of y in that sequence to x. We get:
}
さて、y のすべての出現を x に置き替えます。すると
> val x = new BankAccount
> val y = new BankAccount
> x deposit 30
30
> x withdraw 20
10
#co(){
Since the final results are different, we have established that x and y are not the same. On the other hand, if we define
}
最終結果が異なるので、x と y が異なることが証明されました。その一方で、もし
val x = new BankAccount; val y = x
#co(){
then no sequence of operations can distinguish between x and y, so x and y are the same in this case.
}
と定義すると、どんな操作も x と y を区別できません。したがってこの場合、x と y は等しくなります。
#co(){
Assignment and the Substitution Model. These examples show that our previous substitution model of computation cannot be used anymore. After all, under this model we could always replace a value name by its defining expression. For instance in
}
&b(){代入と置き換えモデル } これらの例が示すことは、以前の計算の置き換えモデルは、もう使えないということです。結局のところ、このモデルでは変数の名前を定義式で常に置き換え可能なのですから。たとえば
val x = new BankAccount; val y = x
#co(){
the x in the definition of y could be replaced by new BankAccount. But we have seen that this change leads to a different program. So the substitution model must be invalid, once we add assignments.
}
の、y の定義中の x は new BankAccount で置き換え可能です。しかしその変更は異なるプログラムを導くことを見てきました。したがって置き換えモデルは、代入を加えると、妥当ではありません。
#co(){
(*2) If a statement like this appears in a class, it is instead regarded as a variable declaration, which introduces abstract access methods for the variable, but does not associate these methods with a piece of state.
}
(*2) もしこのような文がクラス中に現れたなら、そうではなく変数宣言とみなされ、変数に対する抽象アクセスメソッドを導入しますが、これらのメソッドを状態とは結びつけません。
#center(){[[前ページ>Chapter 11 Mutable State]] [[ 11 章>Chapter 11 Mutable State]] [[目次>ScalaByExample和訳]] [[次ページ>Example11.2]]}
----
#comment
#co(){
11.1 Stateful Objects
We normally view the world as a set of objects, some of which have state that changes over time. Normally, state is associated with a set of variables that can be changed in the course of a computation. There is also a more abstract notion of state, which does not refer to particular constructs of a programming language: An object has state (or: is stateful) if its behavior is influenced by its history.
}
#setmenu2(ex-r-menu)
** 11.1 状態を持つオブジェクト (Stateful Object)
我々は世界をオブジェクトの集合としてとらえ、オブジェクトの中には時間と共に変化する状態を持つものもあります。通常、状態は計算の過程で変化しうる変数の集合と結びついています。プログラミング言語の特定の構文に触れずに、状態を抽象化して言うと、「もしオブジェクトの振る舞いがその履歴に影響されるなら、オブジェクトは&bold(){状態を持つ} (&bold(){ステートフル}である)。」となります。
#co(){
For instance, a bank account object has state, because the question "can I withdraw 100 CHF?" might have different answers during the lifetime of the account.
}
たとえば、銀行口座オブジェクトは状態を持ちます。なぜなら「100スイスフラン引き出せるか?」は口座の存続期間、異なる答を持ちうるからです。
#co(){
In Scala, all mutable state is ultimately built from variables. A variable definition is written like a value definition, but starts with var instead of val. For instance, the following two definitions introduce and initialize two variables x and count.
}
Scala ではすべてのミュータブルな状態は、結局のところ、変数から作られます。変数定義は値定義と同じように書きますが、val の代わりに var で始まります。たとえば、次の2つの定義は2つの変数、x と count を導入し初期化します。
var x: String = "abc"
var count = 111
#co(){
Like a value definition, a variable definition associates a name with a value. But in the case of a variable definition, this association may be changed later by an assignment. Such assignments are written as in C or Java. Examples:
}
値定義と同様に変数定義は、名前と値を結びつけます。しかし変数定義の場合、この結びつきは後から代入によって変更できます。そのような代入は C や Java と同じように書きます。たとえば
x = "hello"
count = count + 1
#co(){
In Scala, every defined variable has to be initialized at the point of its definition. For instance, the statement var x: Int; is not regarded as a variable definition, because the initializer is missing(*2) . If one does not know, or does not care about, the appropriate initializer, one can use a wildcard instead. I.e.
}
Scala では定義する変数はすべて、定義の時点で初期化しければなりません。たとえば文、 var x: Int; は変数定義とみなされません。なぜなら初期値が無いからです(*2)。適切な初期値を知らない、あるいは気にしない場合は、代わりにワイルドカードを使えます。たとえば、
val x: T = _
#co(){
will initialize x to some default value (null for reference types, false for booleans, and the appropriate version of 0 for numeric value types).
}
は、x を何かデフォルト値 (参照型には null を、論理型には false を、数値型には適切な 0 を) で初期化します。
#co(){
Real-world objects with state are represented in Scala by objects that have variables as members. For instance, here is a class that represents bank accounts.
}
実世界のオブジェクトは、Scala では変数をメンバに持つオブジェクトとして表現されます。たとえば銀行口座を表現するクラスです。
class BankAccount {
private var balance = 0
def deposit(amount: Int) {
if (amount > 0) balance += amount
}
def withdraw(amount: Int): Int =
if (0 < amount && amount <= balance) {
balance -= amount
balance
} else error("insufficient funds")
}
#co(){
The class defines a variable balance which contains the current balance of an account. Methods deposit and withdraw change the value of this variable through assignments. Note that balance is private in class BankAccount - hence it can not be accessed directly outside the class.
}
このクラスは、口座の現在の残高を入れておく変数 balance を定義しています。メソッド deposit と withdraw は、代入によってこの変数の値を変更します。クラス BankAccount において、balance が private であることに注意して下さい。この結果、クラスの外からは直接アクセスできません。
#co(){
To create bank-accounts, we use the usual object creation notation:
}
銀行口座を作成するには、通常のオブジェクト生成の記法を使います。
val myAccount = new BankAccount
#co(){
Example 11.1.1 Here is a scalaint session that deals with bank accounts.}
&b(){例 11.1.1 } 次は銀行口座を扱う scala セッションです。
scala> :l bankaccount.scala
Loading bankaccount.scala...
defined class BankAccount
scala> val account = new BankAccount
account: BankAccount = BankAccount$class@1797795
scala> account deposit 50
unnamed0: Unit = ()
scala> account withdraw 20
unnamed1: Int = 30
scala> account withdraw 20
unnamed2: Int = 10
scala> account withdraw 15
java.lang.Error: insufficient funds
at scala.Predef$error(Predef.scala:74)
at BankAccount$class.withdraw(<console>:14)
at <init>(<console>:5)
scala>
#co(){
The example shows that applying the same operation (withdraw 20) twice to an account yields different results. So, clearly, accounts are stateful objects.
}
この例は、同じ操作 (withdraw 20) を口座に2回適用して、異なる結果が生じることを示します。したがって口座がステートフルなオブジェクトであることは明らかです。
#co(){
Sameness and Change. Assignments pose new problems in deciding when two expressions are "the same". If assignments are excluded, and one writes
}
&b(){同一性と変化 } 代入は2つの式が「同じ」かを判定する際に新しい問題をもたらします。もし代入が排除されている場合には、次のよう、
val x = E; val y = E
#co(){
where E is some arbitrary expression, then x and y can reasonably be assumed to be the same. I.e. one could have equivalently written
}
ただし E は何か任意の式であるとする、と書いた場合、x と y は無理なく同じと考えられます。つまり次のように書いても等価です。
val x = E; val y = x
#co(){
(This property is usually called referential transparency). But once we admit assignments, the two definition sequences are different. Consider:
}
(この性質は通常、&bold(){参照透過性}と呼ばれます) しかしもし代入を許したなら、上の2つの定義は異なります。次を考えて下さい。
val x = new BankAccount; val y = new BankAccount
#co(){
To answer the question whether x and y are the same, we need to be more precise what "sameness" means. This meaning is captured in the notion of operational equivalence, which, somewhat informally, is stated as follows.
}
この問題、x と y は同一であるか、に答えるには、「同一」の意味をより明確にしなければなりません。この意味は&bold(){操作的等価性}としてとらえられ、くだけた言い方をするなら、次のようになります。
#co(){
Suppose we have two definitions of x and y. To test whether x and y define the same value, proceed as follows.
}
仮に x と y の2つの定義があるとします。x と y とが同じ値を定義しているか調べるには、次のようにします。
#co(){{
- Execute the definitions followed by an arbitrary sequence S of operations that involve x and y. Observe the results (if any).
- Then, execute the definitions with another sequence S' which results from S by renaming all occurrences of y in S to x.
- If the results of running S' are different, then surely x and y are different.
- On the other hand, if all possible pairs of sequences {S, S'} yield the same results, then x and y are the same.
}}
- 定義を実行し、引き続いて x と y とを含む任意の操作列 S を実行し、(もしあれば) 結果を調べる。
- 次いで、定義を実行し、S 中のすべての y の出現を x で置き換えた、S から得られた列 S' を実行する。
- もし S' を実行した結果が異なれば、x と y は確かに異なる。
- もしすべての可能な操作列の組 {S, S'} に対して、同じ結果が得られるなら、x と y は同一である。
#co(){
In other words, operational equivalence regards two definitions x and y as defining the same value, if no possible experiment can distinguish between x and y. An experiment in this context are two version of an arbitrary program which use either x or y.
}
別の言い方をすれば、操作的等価性は2つの定義 x と y を、もしどんな実験でも x と y を区別できないなら、同じ値だとみなします。この文脈における実験とは、x あるいは y を用いる任意の2つのプログラムです。
#co(){
Given this definition, let's test whether
}
この定義を用いて、
val x = new BankAccount; val y = new BankAccount
#co(){
defines values x and y which are the same. Here are the definitions again, followed by a test sequence:
}
が、値 x と y を等しく定義するか確かめましょう。定義を再度行い、次いでテスト列を。
> val x = new BankAccount
> val y = new BankAccount
> x deposit 30
30
> y withdraw 20
java.lang.RuntimeException: insufficient funds
#co(){
Now, rename all occurrences of y in that sequence to x. We get:
}
さて、y のすべての出現を x に置き替えます。すると
> val x = new BankAccount
> val y = new BankAccount
> x deposit 30
30
> x withdraw 20
10
#co(){
Since the final results are different, we have established that x and y are not the same. On the other hand, if we define
}
最終結果が異なるので、x と y が異なることが証明されました。その一方で、もし
val x = new BankAccount; val y = x
#co(){
then no sequence of operations can distinguish between x and y, so x and y are the same in this case.
}
と定義すると、どんな操作も x と y を区別できません。したがってこの場合、x と y は等しくなります。
#co(){
Assignment and the Substitution Model. These examples show that our previous substitution model of computation cannot be used anymore. After all, under this model we could always replace a value name by its defining expression. For instance in
}
&b(){代入と置き換えモデル } これらの例が示すことは、以前の計算の置き換えモデルは、もう使えないということです。結局のところ、このモデルでは変数の名前を定義式で常に置き換え可能なのですから。たとえば
val x = new BankAccount; val y = x
#co(){
the x in the definition of y could be replaced by new BankAccount. But we have seen that this change leads to a different program. So the substitution model must be invalid, once we add assignments.
}
の、y の定義中の x は new BankAccount で置き換え可能です。しかしその変更は異なるプログラムを導くことを見てきました。したがって置き換えモデルは、代入を加えると、妥当ではありません。
#co(){
(*2) If a statement like this appears in a class, it is instead regarded as a variable declaration, which introduces abstract access methods for the variable, but does not associate these methods with a piece of state.
}
(*2) もしこのような文がクラス中に表れたなら、そうではなく変数宣言とみなされ、変数に対する抽象アクセスメソッドを導入しますが、これらのメソッドを状態とは結びつけません。
#center(){[[前ページ>Chapter 11 Mutable State]] [[ 11 章>Chapter 11 Mutable State]] [[目次>ScalaByExample和訳]] [[次ページ>Example11.2]]}
----
#comment