Jump to content

Uniform function call syntax

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Derek R Bullamore (talk | contribs) at 13:30, 1 October 2017 (Filled in 3 bare reference(s) with reFill ()). 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 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[4], 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);[6] however, this leads to excessive coupling between classes.[7]

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 a(&self);
    fn b(&self);
}

trait Bar {
    fn b(&self);
}

struct Qux;

impl Foo for Qux {
    fn a(&self) { println!("Qux’s implementation of Foo::a"); }
    fn b(&self) { println!("Qux’s implementation of Foo::b"); }
}

impl Bar for Qux {
    fn b(&self) { println!("Qux’s implementation of Bar::b"); }
}

fn main() {
    let c = Qux;

    // These two are equivalent:
    c.a();
    Foo::a(&c);

    // This would not work because .b() is ambiguous:
    // c.b();
    // But it's possible to disambiguate using UFCS
    Foo::b(&c);
    Bar::b(&c);
}

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

References

  1. ^ "Universal Function Call Syntax - The Rust Programming Language". Doc.rust-lang.org. Retrieved 1 October 2017.
  2. ^ "Functions - D Programming Language". Dlang.org. Retrieved 1 October 2017.
  3. ^ "Programming in D - Universal Function Call Syntax (UFCS)". Ddili.org. Retrieved 1 October 2017.
  4. ^ a b ""Unified Call Syntax"" (PDF). Isocpp.org. Retrieved 1 October 2017.
  5. ^ ""UFCS proposal"" (PDF). Open-std.org. Retrieved 1 October 2017.
  6. ^ "using intellisense". Msdn.microsoft.com. Retrieved 1 October 2017.
  7. ^ ""How Non-Member Functions improve encapsulation". Drdobbs.com. Retrieved 1 October 2017.