Uniform Function Call Syntax(UFCS)またはUniform Calling Syntax(UCS)、Universal Function Call Syntaxは、オブジェクト指向プログラミング言語にみられるメソッド呼び出し構文を利用して、任意の関数を呼び出すことができる機能である。関数の第一引数をレシーバーとして使用し、残りの引数をメソッドの引数として使用する[1]。D言語[2]、Nim[3]、Koka[4]、Effekt[5]などのプログラミング言語でUFCSが採用されている。同様の手法が、AviSynthスクリプト言語において「OOP notation(OOP記述法)」という名前で用いられている[6]。
UFCSは、関数呼び出しがチェインされている場合に特に有用である[2](パイプ、または一連の式を介して値を渡すために関数型言語で使用できるさまざまな専用演算子に類似している)。これにより、フリー関数(非メンバ関数)が他言語における拡張メソッドと同様の役割を果たすことができる。メソッド呼び出し構文のもう一つの利点としては、 IDEの補完機能が使えることが挙げられる。補完機能は、型情報を使用して、コンテキストに応じて使用可能な関数の一覧を表示する。プログラマーが引数を入力すると、使用できる可能性のある関数が大幅に絞り込まれ[7]、関数の発見可能性(英語版)が向上する。
int first(int[] arr) { return arr[0]; } int[] addone(int[] arr) { int[] result; foreach (value; arr) { result ~= value + 1; } return result; } void main() { auto a = [0, 1, 2, 3]; // 以下のコードはいずれも等価であり、正しい int b = first(a); int c = a.first; // メソッドチェーン int[] e = a.addone().addone(); }
type Vector = tuple[x, y: int] proc add(a, b: Vector): Vector = (a.x + b.x, a.y + b.y) let v1 = (x: -1, y: 4) v2 = (x: 5, y: -2) # 以下のコードは全て正しい v3 = add(v1, v2) v4 = v1.add(v2) v5 = v1.add(v2).add(v4)
メンバ関数とフリー関数の呼び出し構文を統合する提案は、C++標準化の初期から議論されてきた。 Glassborow(2004)は、特別に注釈が付けられたフリー関数をメンバ関数表記で呼び出すことができるUniform Calling Syntax(UCS)を提案した[8]。2016年には、 Bjarne Stroustrup[9]とHerb Sutter[7]によって、フリー関数とメンバ関数の記述間の曖昧な決定を減らし、テンプレートコードの記述を簡素化するために、C++への追加が再び提案された。多くのプログラマーは、メンバ関数構文の利点(メンバ関数をリスト化するための「ドットオートコンプリート」など)を得るためにメンバ関数を作成しようとする[10]。しかし、これはクラス間の過度の結合につながる[11]。2023年には再びHerb Sutterによって提案され[12]、新しい情報と洞察、そしてcppfrontコンパイラでの実験的な実装が主張されている。
2018年頃までは、UFCSという用語は修飾/明示的パス構文、特に完全修飾パス構文を指すことが一般的だった[13]。同じ構造体に同じメソッドを定義する複数のトレイトが存在する可能性があるため、どのトレイトを利用するかを曖昧にしない仕組みが必要であったことが理由である。メンバ関数は、修飾パス(名前空間付きのパス)を通してフリー関数として利用できる。この機能はメソッドを(名前空間付きの)フリー関数として使えるようにしているが、フリー関数をメソッドとして使えるようにはしない。そのため、UFCSという用語はこの用途に対しては不適切である。
a.function(b)
function(a, b)