Uniform function call syntax

This is an old revision of this page, as edited by 109.146.20.129 (talk) at 20:00, 18 January 2017 (Added another example language that uses UFCS). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

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 various dedicated operators available in functional languages for passing values through an expression. 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, dependant on the context. When the programmer starts with an argument, the set of potentially applicable functions is greatly narrowed down, aiding discoverability.

C++ proposal

It has been proposed (as of 2016) for addition to C++ by Bjarne Stroustrup[4] and Herb Sutter, 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, however this leads to excessive coupling between classes.

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);
}

See also

References

  1. ^ https://doc.rust-lang.org/book/ufcs.html
  2. ^ http://dlang.org/function.html#pseudo-member
  3. ^ http://ddili.org/ders/d.en/ufcs.html
  4. ^ ""UFCS proposal"" (PDF).