0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

fluorite-7 日本語リファレンス オブジェクト指向

Last updated at Posted at 2020-09-11

日本語チュートリアルトップ

基礎

{ }でオブジェクトが作れる。

{
  key : "value";
}

オブジェクトの値はobject.keyで得られる。

{
  key : "value";
}.key
$ fl7 '{key : "value"}.key'
value

オブジェクトに{ }を後置すると継承したオブジェクトが作れる。
object.keyでは親の値も見える。

parent : {
  key : "value";
};
obj : parent {
  key2 : "value2";
};
obj.key, obj.key2
$ fl7 'parent : {key : "value"}; obj : parent {key2 : "value2"}; obj.key, obj.key2'
value
value2

これを利用すると「クラス」が作れる。

object::method(args)で、object.method(object; args)の動きをする。

Obj : {
  get_value : this -> this.value;
};
obj : Obj {
  value : "value!!!";
};
obj::get_value()
$ fl7 'Obj : {get_value : this -> this.value}; obj : Obj {value : "value!!!"}; obj::get_value()'
value!!!

オブジェクト生成

オブジェクト生成演算子

オブジェクト生成演算子{entries}は、オブジェクトを生成する括弧類である。
entriesには;区切りで0個以上のエントリーを記述する。

宣言エントリー

key : valuekeyという名前を宣言しつつキーにvalueを代入するエントリーである。
keyは宣言されたオブジェクト内のどこからでも参照できる。

{
  x : y - 1;
  y : 100;
  z : y + 1;
}
$ fl7 '{x : y - 1; y : 100; z : y + 1}'
{x:99;y:100;z:101}

これを使って循環参照を行うこともできる。

obj : {
  f : n -> n === 0 ? 1 : f(n - 1) * n;
};
obj.f(5)
$ fl7 'obj : {f : n -> n === 0 ? 1 : f(n - 1) * n}; obj.f(5)'
120

keyは数値・文字列リテラル・括弧であってもよい。
その場合、文字列に変換されてキーとして認識される。

{
  E : "identifier";
  100 : "number";
  "#" : "string";
  (PI) : "formula";
}
$ fl7 '{E : "identifier"; 100 : "number"; "#" : "string"; (PI) : "formula"}'
{100:number;E:identifier;#:string;3.141592653589793:formula}

代入エントリー

key = valuekeyというキーにvalueを代入するエントリーである。

x : 20;
{
  x = x;
}
$ fl7 'x : 20; {x = x}'
{x:20}

代入エントリーでは名前を宣言しないため、意図せず循環参照に陥ることがない。

その他のことは概ね宣言エントリーと同様である。

即席代入エントリー

keykeyというキーにkeyを代入するエントリーである。

x : 20;
{
  x;
}
$ fl7 'x : 20; {x}'
{x:20}

その他のことは概ね代入エントリーと同様である。

Tips 即席代入はコンストラクタメソッド内でよく使われる。

Obj : {
  new : class, value -> class {
    value;
  };
  get_value : this -> this.value;
};
Obj::new("Value!")::get_value()
$ fl7 'Obj : {new : class, value -> class {value}; get_value : this -> this.value}; Obj::new("Value!!!")::get_value()'
Value!!!

継承つきオブジェクト生成演算子

継承つきオブジェクト生成演算子parent {entries}は、parentを継承したオブジェクトを生成する後置演算子である。
entriesは、オブジェクト生成演算子{entries}と同じ仕様を持つ。
継承つきオブジェクト生成演算子の結合優先度はその他の後置演算子と等しい。
その他の挙動は、概ねオブジェクト生成演算子と等しい。

親オブジェクト参照子

親オブジェクト参照子^は、オブジェクト内でその親オブジェクトを参照できる式である。

parent : {
  a : 10;
};
obj : parent {
  a : 20;
  c : ^.a;
};
obj.c
$ fl7 'parent : {a : 10}; obj : parent {a : 20; c : ^.a}; obj.c'
10

クラスの表現ができる

継承つきオブジェクト生成演算子は、オブジェクト指向におけるClass-Object間の関係を表すのに使うことができる。

Obj : {
  new : class, value -> class {
    value;
  };
  get_value : this -> this.value;
};
Obj::new("Value!!!")::get_value()
$ fl7 'Obj : {new : class, value -> class {value}; get_value : this -> this.value}; Obj::new("Value!!!")::get_value()'
Value!!!

クラスの継承の表現ができる

継承つきオブジェクト生成演算子は、オブジェクト指向におけるSuper Class-Sub Class間の関係を表すのに使うことができる。

Obj : {
  new : class, value -> class {
    value;
  };
  get_value : this -> this.value;
};
SubObj : Obj {
  new : class, value -> ^.new(class; value);
  get_value : this -> ^.get_value(this) * 2;
};
SubObj::new("Value!!!")::get_value()
$ fl7 'Obj : {new : class, value -> class {value}; get_value : this -> this.value}; SubObj : Obj {new : class, value -> ^.new(class; value); get_value : this -> ^.get_value(this) * 2}; SubObj::new("Value!!!")::get_value()'
Value!!!Value!!!

上記のコードのSubObj::new("Value!!!")::get_value()は次のように等価に変形できる。

次のコードは変形前の状態である。

SubObj::new("Value!!!")::get_value()

SubObj::new("Value!!!")は、SubObj.new(SubObj; "Value!!!")に変形できる。

SubObj.new(SubObj; "Value!!!")::get_value()

SubObj.new(SubObj; "Value!!!")を展開する。

Obj.new(SubObj; "Value!!!")::get_value()

Obj.new(SubObj; "Value!!!")を展開する。

obj : SubObj {
  value = "Value!!!";
};
obj::get_value()

obj::get_value()を展開する。

obj : SubObj {
  value = "Value!!!";
};
obj.get_value(obj)

SubObjの子obj自身にはプロパティget_valueが存在しないため、一つ上の親であるSubObjが持つプロパティget_valueがヒットする。
obj.get_valueSubObj.get_valueで置換できる。

obj : SubObj {
  value = "Value!!!";
};
SubObj.get_value(obj)

SubObj.get_valueを展開する。

obj : SubObj {
  value = "Value!!!";
};
Obj.get_value(obj) * 2

Obj.get_valueを展開する。

obj : SubObj {
  value = "Value!!!";
};
obj.value * 2

objはプロパティvalueを持っており、その値はここでは"Value!!!"である。
これをobj.valueに代入する。

"Value!!!" * 2

"Value!!!" * 2を計算する。

"Value!!!Value!!!"

fl7におけるオブジェクトの継承はこのようにして成り立っている。

エントリーストリームからの生成

エントリーストリームからのオブジェクト生成演算子{[entries]}は、entriesをエントリーのストリームと解釈し、それらで構成されるオブジェクトを生成する括弧類である。

{[
  1 .. 5 | {
    key : _;
    value : _ * 11;
  }
]}
$ fl7 '{[1 .. 5 | {key : _; value : _ * 11}]}'
{1:11;2:22;3:33;4:44;5:55}

アクセス

メンバアクセス

メンバアクセス演算子object.keyは、objectのメンバkeyを取得する後置演算子である。
ここでkeyは識別子の名前そのものを表す。
結合優先度はその他の後置演算子と等しい。

メンバアクセスではキーが存在しなかった場合、親オブジェクトを再帰的に遡ってヒットするキーを検索する。

全くヒットしなかった場合、NULLが返る。

obj : {
  a : 10;
} {
  b : 20;
} {
  c : 30;
};
obj.a, obj.b, obj.c, obj.d
$ fl7 'obj : {a : 10} {b : 20} {c : 30}; obj.a, obj.b, obj.c, obj.d'
10
20
30
NULL

keyは識別子以外であってもよい

keyが識別子以外であった場合、それを評価した文字列でメンバアクセスを行う。

obj : {
  aaa : 777;
  10 : 888;
};
key : "aaa";
obj.("a" * 3),
obj.(key),
obj.10,
$ fl7 'obj : {aaa : 777; 10 : 888}; key : "aaa"; obj.("a" * 3), obj.(key), obj.10,'
777
777
888

プロパティアクセス

プロパティアクセス演算子object[key]は、objectのプロパティkeyを取得する後置演算子である。
ここで、keyは文字列の値を表す。
結合優先度はその他の後置演算子と等しい。

プロパティアクセスでは親オブジェクトを無視する。

それ以外の挙動はメンバアクセスと概ね等しい。

obj : {
  a : 10;
} {
  b : 20;
} {
  c : 30;
};
obj["a"], obj["b"], obj["c"], obj["d"]
$ fl7 'obj : {a : 10} {b : 20} {c : 30}; obj["a"], obj["b"], obj["c"], obj["d"]'
NULL
NULL
30
NULL

メソッドアクセス

メソッドアクセス演算子object::methodは、メンバアクセス演算子と左部分適用演算子の複合であるobject.method << objectと等価な動きをする。
メソッドアクセス演算子を使うとオブジェクト指向におけるMethodの動きが再現できる。

メソッド風左バインド

メソッド風左バインドを使うと、メンバでない関数をメソッドのように呼び出すことができる。

エントリーの列挙

ストリーマ展開演算子object[]をオブジェクトに対して用いると、objectが持っているすべてのプロパティを{key = key; value = value}という形の要素からなるストリーマで取得する。

{
  a : 10;
  b : 20;
  c : 30;
}[]
$ fl7 '{a : 10; b : 20; c : 30}[]'
{key:a;value:10}
{key:b;value:20}
{key:c;value:30}

改変

プロパティ代入

メンバアクセス演算子object.keyおよびプロパティアクセス演算子object[key]は、セットコンテキストで記述されるとオブジェクトのプロパティに代入を行う。

parent :        {a : 10; b: 20};
object : parent {             };

object.a = 100;
object["b"] = 200;
object.c = 300;
object["d"] = 400;

parent, object
$ fl7 'parent : {a : 10; b: 20}; object : parent {}; object.a = 100; object["b"] = 200; object.c = 300; object["d"] = 400; parent, object'
{a:10;b:20}
{a:100;b:200;c:300;d:400}

親オブジェクトのプロパティがメンバとして見えている状態でも、代入時には子オブジェクト側が改変される。

多重プロパティ代入

多重プロパティ代入演算子object.{entries}は、entriesが示すエントリー列をobjectに注入したうえでobjectを返す後置演算子である。

この演算子ではobjectが改変を受ける。

parent :        {a : 10};
object : parent {      };

result : object.{
  a : 100;
  b : 200;
};

parent,
object,
result,
result === object,
$ fl7 'parent : {a : 10}; object : parent {}; result : object.{a : 100; b : 200}; parent, object, result, result === object'
{a:10}
{a:100;b:200}
{a:100;b:200}
TRUE

Tips 多重プロパティ代入は親クラスのコンストラクタから返却されたオブジェクトに、子クラスのコンストラクタ内で続きの初期化を行う際に便利である。

Parent : {
  new : _ -> {
    a : 10;
  };
};
Child : Parent {
  new : _ -> ^.new(_).{
    b : 20;
  };
};

Child::new()
$ fl7 'Parent : { new : _ -> { a : 10; }; }; Child : Parent { new : _ -> ^.new(_).{ b : 20; }; }; Child::new()'
{a:10;b:20}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?