Get the highlights in your inbox every week.
The feature that makes D my favorite programming language | Opensource.com
The feature that makes D my favorite programming language
UFCS gives you the power to compose reusable code that has a natural flow without sacrificing convenience.

Back in 2017, I wrote about why the D programming language is a great choice for development. But there is one outstanding feature in D I didn't expand enough on: the Universal Function Call Syntax (UFCS). UFCS is a syntactic sugar in D that enables chaining any regular function on a type (string, number, boolean, etc.) like its member function of that type.
If you don't already have D installed, install a D compiler so you can run the D code in this article yourself.
Consider this example code:
// file: ufcs_demo.d
module ufcs_demo;
import std.stdio : writeln;
int[] evenNumbers(int[] numbers)
{
import std.array : array;
import std.algorithm : filter;
return numbers.filter!(n => n % 2 == 0).array;
}
void main()
{
writeln(evenNumbers([1, 2, 3, 4]));
}
Compile this with your favorite D compiler to see what this simple example application does:
$ dmd ufcs_demo.d
$ ./ufcs_demo
[2, 4]
But with UFCS as a built-in feature of D, you can also write your code in a natural way:
...
writeln([1, 2, 3, 4].evenNumbers());
...
or completely remove the now-redundant parenthesis to make it feel like evenNumbers
is a property:
...
writeln([1, 2, 3, 4].evenNumbers); // prints 2, 4
...
So the complete code now becomes:
// file: ufcs_demo.d
module ufcs_demo;
import std.stdio : writeln;
int[] evenNumbers(int[] numbers)
{
import std.array : array;
import std.algorithm : filter;
return numbers.filter!(n => n % 2 == 0).array;
}
void main()
{
writeln([1, 2, 3, 4].evenNumbers);
}
Compile it with your favorite D compiler and try it out. As expected, it produces the same output:
$ dmd ufcs_demo.d
$ ./ufcs_demo
[2, 4]
During compilation, the compiler automatically places the array as the first argument to the function. This is a regular pattern that makes using D such a joy, so it very much feels the same as you naturally think about your code. The result is functional-style programming.
You can probably guess what this prints:
//file: cool.d
import std.stdio : writeln;
import std.uni : asLowerCase, asCapitalized;
void main()
{
string mySentence = "D IS COOL";
writeln(mySentence.asLowerCase.asCapitalized);
}
But just to confirm:
Combined with other D features, UFCS gives you the power to compose reusable code that has a natural flow to it without sacrificing convenience.$ dmd cool.d
$ ./cool
D is cool
Time to try D
As I've written before, D is a great language for development. It's easy to install from the D download page, so download the compiler, take a look at the examples, and experience D for yourself.
29 Comments, Register or Log in to post a comment.
Even before you started explaining UFCS, you were using it.
`numbers.filter!(n => n % 2 == 0).array`
Both filter and array take an argument
`array(filter!(n => n % 2 == 0)(numbers))`
You're right Jesse. What I did instead was to mention my previous post which did talk about the filter function...which uses both UFCS and templates. So I didn't have to explain that filter!... template function and the different calling conventions too.
Im web developer i have acceoted the terms and conditions of the site
Nim has this as well if you're interested in new languages
Good to know. It's something I think every modern language should consider. Especially when it can be resolved at compile time with no runtime cost. D seems to have inspired Nim in some way.
You don't get many 'D Advantages' in Nim. It is attractive by it's syntax.
And? What new problem does this solve?
Hi. I'm the author of Next Generation Shell. Without knowing D or what UFCS was (at the time), I have added support for UFCS to NGS just because it made sense, especially when combined with multiple-dispatch. It's nice to hear that the UFCS feature is praised.
Just to give some feeling of NGS:
--- D ---
module ufcs_demo;
import std.stdio : writeln;
int[] evenNumbers(int[] numbers)
{
import std.array : array;
import std.algorithm : filter;
return numbers.filter!(n => n % 2 == 0).array;
}
void main()
{
writeln([1, 2, 3, 4].evenNumbers);
}
--- NGS ---
F even_numbers(numbers:Arr) {
numbers.filter(F(n) n % 2 == 0)
}
F main() {
[1,2,3,4].even_numbers().echo()
}
---
Next Generation Shell project is at https://github.com/ngs-lang/ngs
Hey Ilya, it's nice to see you also like the UFCS idea. Its feels natural to me.
UFCS seems very similar to .Net extensions. What are the differences between them?
Does the compiler optimize the output of UFCS instructions?
The compiler rewrites it so how you would normally write it. So its a convenience for the developer.
I'm not familiar with .Net extensions. However with D, the compiler rewrites it like how you'd normal call it. So it's a convenient syntax for the programmer.
So 1.add(2): gets rewritten to add(2,2) during compilation.
Looks like the pipe operator in Elixir, Elm, Haskell, etc, or the arrow macro in Clojure.
- I don't see how this is any better than writing a method
- what happens if you need to add arguments later on ?
- disguising methods as properties makes it hard to understand the performance implications of calling them (reading a property is a no-op, calling a function is not)
- adding properties & methods to a standard type is at best weird, at worst really confusing
:/
Hey Arthur, UFCS helps avoid writing code like: finish(make(bake(1,4)));
In D you can write it as: bake(1,2).make(). finish () OR more idiomatically, 1.bake(3).make.finish. So it reads in the order you'd process it in your mind when reading the code.
Any other extra argument gets written like 1.call(2,3,4,5,...). of course if using UFCS makes sense only in that particular context.
UFCS is actually just a syntax trick. It comes at no extra performance cost. The D compiler rewrites it to normal styling during compilation. But for the programmer, UFCS just beautifies your code. So its more lightweight compared to using a class. Sometimes people write classes to get a similar feel but with D UFCS gives you that experience. UFCS is not built into the types, its just a syntactic sugar.
Nice guys.. This is very interesting to learn about D programming. My first programming language was Pascal then VBA. I used to disregard D to be boring as I shifted to formatting and scripting languages such as Rubby n Rays and Python. I now know that D has few similarity with pascal and .NET. I like the integration. I can use the VBA API piping with ease. Will try D finally.
You should definitely try it. You can start at https://tour.dlang.org
As a Pascal programmer, you may like to know that D offers nested functions. They were inspired by Pascal! https://youtu.be/NoAJziYZ4qs?t=9m20s
—Bastiaan
Yeah, I'm actually written more about that next.
The even numbers function may as well be an alias for filter! (...).
You even don't need to download a compiler just to play around. There's a https://run.dlang.io/ to try it out without installing.
You're right! It didn't come to mind. I'll include that in my next article.
You're right! It didn't come to mind. I'll include that in my next article.
As you mentioned it is syntactic sugar. Impeoves code readability - making it closer to real English. So why not
writeln.mySentence.asLowerCase.asCapitalized;
Or bring even closer:
print mySentence asLowerCase asCapitalized
Would love to see a language like this.
Yes, you can totally do something like that:
mport std.stdio : writeln;
import std.uni : asLowerCase, asCapitalized;
void main()
{
string mySentence = "D IS COOL";
mySentence
.asLowerCase
.asCapitalized
.writeln;
}
Try running this example at https://run.dlang.io/is/cdLnpD
Or make it a one-liner:
import std.stdio : writeln;
import std.uni : asLowerCase, asCapitalized;
void main()
{
"D IS COOL"
.asLowerCase
.asCapitalized
.writeln;
}
I will tray UFCS, appears be cool!😀👍
I absolutely love D, and the feel of its progression from C/C++, hard to believe it's already 20 years since its release. These days it's looking like a mix of C/C++ with a dash of ruby. I wish I could use it in a professional capacity. Last year i had to clean up an absolute mess written in C++ that was leaking GB/s of ram (no lie), this would have been a great project to rewrite in D. for an old C/C++ programmer like me, the syntax is very easy on the eyes, compared to the likes of the flavour du jour Rust :)
Hi Steeve, I see similar comments quite often. Most of the D programmers are/were also C++ guys also. Part of why D has one of the strongest C/C++ code interoperability.