Uniform Function Call Syntax
Uniform Function Call Syntax (UFCS) or sometimes Universal Function Call Syntax is a programming language feature in D, Rust[1] and Nim that allows any function to be called using the syntax for method calls (as in object-oriented programming), by using the receiver as the first parameter, and the given arguments as the remaining parameters.[2] UFCS is particularly useful when function calls are chained,[3] (behaving similar to pipes, or the various dedicated operators available in functional languages for passing values through a series of expressions). It allows free-functions to fill a role similar to extension methods in some other languages. Another benefit of the method call syntax is use with "dot-autocomplete" in IDEs, which use type information to show a list of available functions, dependent on the context. When the programmer starts with an argument, the set of potentially applicable functions is greatly narrowed down[4], aiding discoverability.
C++ proposal
It has been proposed (as of 2016) for addition to C++ by Bjarne Stroustrup[5] and Herb Sutter[6], to reduce the ambiguous decision between writing free functions and member functions, to simplify the writing of templated code. Many programmers are tempted to write member-functions to get the benefits of the member-function syntax - e.g. "dot-autocomplete" to list member functions[7], however this leads to excessive coupling between classes[8].
Examples
D programming language
import std.stdio;
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];
// All the followings are correct and equivalent
int b = first(a);
int c = a.first();
int d = a.first;
// Chaining
int[] e = a.addone().addone();
}
Rust programming language
trait Foo {
fn f(&self);
fn g(&self);
}
trait Bar {
fn g(&self);
}
struct Qux;
impl Foo for Qux {
fn f(&self) { println!("Qux’s implementation of Foo::f"); }
fn g(&self) { println!("Qux’s implementation of Foo::g"); }
}
impl Bar for Qux {
fn g(&self) { println!("Qux’s implementation of Bar::g"); }
}
fn main() {
let q = Qux;
// These two are equivalent:
q.f();
Foo::f(&q);
// This would not work because .g() is ambiguous:
// q.g();
// But it's possible to disambiguate using UFCS
Foo::g(&q);
Bar::g(&q);
}
Nim programming language
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(v1)
See also
- trait (computer programming)
- interface (computer programming)
- Go (programming language), another language with a more open philosophy to methods
- Loose coupling
- Duck typing
References
- ↑ https://doc.rust-lang.org/book/first-edition/ufcs.html
- ↑ http://dlang.org/function.html#pseudo-member
- ↑ http://ddili.org/ders/d.en/ufcs.html
- ↑ ""Unified Call Syntax"" (PDF).
- ↑ ""UFCS proposal"" (PDF).
- ↑ ""Unified Call Syntax"" (PDF).
- ↑ "using intellisense".
- ↑ ""How Non-Member Functions improve encapsulation".