Universal Function Call Syntax (UFCS) - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Discord (community-run)
  - Forums
  - IRC
  - Wiki
  - Issues
  - Contributing
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

# Universal Function Call Syntax (UFCS)

UFCS is a feature that is applied by the compiler automatically. It enables the member function syntax even for regular functions. It can be explained simply by comparing two expressions:

        variable.foo(arguments)

When the compiler encounters an expression such as the one above, if there is no member function named `foo` that can be called on `variable` with the provided arguments, then the compiler also tries to compile the following expression:

        foo(variable, arguments)

If this new expression can indeed be compiled, then the compiler simply accepts that one. As a result, although `foo()` evidently has been a regular function, it gets accepted to be used by the member function syntax.

Note: UFCS considers only functions that are defined at module scope; for example, nested functions cannot be called with the UFCS syntax.

We know that functions that are closely related to a type are defined as member functions of that type. This is especially important for encapsulation as only the member functions of a type (and that type's module) can access its `private` members.

Let's consider a `Car` class which maintains the amount of fuel:

    class Car {
        enum economy = 12.5;          // kilometers per liter (average)
        private double fuelAmount;    // liters

        this(double fuelAmount) {
            this.fuelAmount = fuelAmount;
        }

        double fuel() const {
            return fuelAmount;
        }

        // ...
    }

Although member functions are very useful and sometimes necessary, not every function that operates on a type should be a member function. Some operations on a type are too specific to a certain application to be member functions. For example, a function that determines whether a car can travel a specific distance may more appropriately be defined as a regular function:

    bool canTravel(Car car, double distance) {
        return (car.fuel() * car.economy) >= distance;
    }

This naturally brings a discrepancy in calling functions that are related to a type: objects appear at different places in these two syntaxes:

    void main() {
        auto car = new Car(5);

        auto remainingFuel = car.fuel();  // Member function syntax

        if (canTravel(car, 100)) {        // Regular function syntax
            // ...
        }
    }

UFCS removes this discrepancy by allowing regular functions to be called by the member function syntax:

        if (car.canTravel(100)) {  // Regular function, called by the
                                   // member function syntax
            // ...
        }

This feature is available for fundamental types as well, including literals:

    int half(int value) {
        return value / 2;
    }

    void main() {
        assert(42.half() == 21);
    }

As we will see in the next chapter, when there are no arguments to pass to a function, that function can be called without parentheses. When that feature is used as well, the expression above gets even shorter. All three of the following statements are equivalent:

        result = half(value);
        result = value.half();
        result = value.half;

UFCS is especially useful when function calls are chained. Let's see this on a group of functions that operate on `int` slices:

    // Returns the result of dividing all of the elements by
    // 'divisor'
    int[] divide(int[] slice, int divisor) {
        int[] result;
        result.reserve(slice.length);

        foreach (value; slice) {
            result ~= value / divisor;
        }

        return result;
    }

    // Returns the result of multiplying all of the elements by
    // 'multiplier'
    int[] multiply(int[] slice, int multiplier) {
        int[] result;
        result.reserve(slice.length);

        foreach (value; slice) {
            result ~= value * multiplier;
        }

        return result;
    }

    // Filters out elements that have odd values
    int[] evens(int[] slice) {
        int[] result;
        result.reserve(slice.length);

        foreach (value; slice) {
            if (!(value % 2)) {
                result ~= value;
            }
        }

        return result;
    }

When written by the regular syntax, without taking advantage of UFCS, an expression that chains three calls to these functions can be written as in the following program:

    import std.stdio;

    // ...

    void main() {
        auto values = [ 1, 2, 3, 4, 5 ];
        writeln(evens(divide(multiply(values, 10), 3)));
    }

The values are first multiplied by 10, then divided by 3, and finally only the even numbers are used:

    [6, 10, 16]

A problem with the expression above is that although the pair of `multiply` and `10` are related and the pair of `divide` and `3` are related, parts of each pair end up written away from each other. UFCS eliminates this issue and enables a more natural syntax that reflects the actual order of operations:

        writeln(values.multiply(10).divide(3).evens);

Some programmers take advantage of UFCS even for calls like `writeln()`:

        values.multiply(10).divide(3).evens.writeln;

As an aside, the entire program above could have been written in a much simpler way by `map()` and `filter()`:

    import std.stdio;
    import std.algorithm;

    void main() {
        auto values = [ 1, 2, 3, 4, 5 ];

        writeln(values
                .map!(a => a * 10)
                .map!(a => a / 3)
                .filter!(a => !(a % 2)));
    }

The program above takes advantage of templates, ranges, and lambda functions, all of which will be explained in later chapters.

Copyright © 1999-2026 by the D Language Foundation | Page generated by Ddoc on Mon Aug 17 18:57:11 2026