Fluent interface


In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language. The term was coined in 2005 by Eric Evans and Martin Fowler.

Implementation

A fluent interface is normally implemented by using method chaining to implement method cascading, concretely by having each method return this. Stated more abstractly, a fluent interface relays the instruction context of a subsequent call in method chaining, where generally the context is
Note that a "fluent interface" means more than just method cascading via chaining; it entails designing an interface that reads like a DSL, using other techniques like "nested functions and object scoping".

History

The term "fluent interface" was coined in late 2005, though this overall style of interface dates to the invention of method cascading in Smalltalk in the 1970s, and numerous examples in the 1980s. A common example is the iostream library in C++, which uses the << or >> operators for the message passing, sending multiple data to the same object and allowing "manipulators" for other method calls. Other early examples include the and the which used this style for object creation and property assignment.

Examples

C#

C# uses fluent programming extensively in LINQ to build queries using "standard query operators". The implementation is based on extension methods.

var translations = new Dictionary
;
// Find translations for English words containing the letter "a",
// sorted by length and displayed in uppercase
IEnumerable query = translations
.Where
.OrderBy
.Select );
// The same query constructed progressively:
var filtered = translations.Where ;
var sorted = filtered.OrderBy ;
var finalQuery = sorted.Select );

Fluent interface can also be used to chain a set of method, which operates/shares the same object. Instead of creating a customer class, we can create a data context which can be decorated with fluent interface as follows.

// Defines the data context
class Context
class Customer
class Program

C++

A common use of the fluent interface in C++ is the standard iostream, which chains overloaded operators.
The following is an example of providing a fluent interface wrapper on top of a more traditional interface in C++:

// Basic definition
class GlutApp ;
// Basic usage
int main
// Fluent wrapper
class FluentGlutApp : private GlutApp ;
// Fluent usage
int main

Java

The jOOQ library models SQL as a fluent API in Java. An example of a fluent test expectation in the jMock testing framework is:

mock.expects).method.with,
stringContains) );


Author author = AUTHOR.as;
create.selectFrom
.where
.from
.where
.and));

The annotation processor enables the creation of a fluent API using Java annotations.
The library enables Java 8 Lambdas to be represented as objects in the form of at runtime, making it possible to create type-safe fluent interfaces, i.e., instead of:

Customer obj =...
obj.property.eq

One can write:

method

Also, the mock object testing library makes extensive use of this style of interface to provide an expressive programming interface.

Collection mockCollection = EasyMock.createMock;
EasyMock
.expect
.andThrow)
.atLeastOnce;

In the Java Swing API, the LayoutManager interface defines how Container objects can have controlled Component placement. One of the more powerful LayoutManager implementations is the GridBagLayout class which requires the use of the GridBagConstraints class to specify how layout control occurs. A typical example of the use of this class is something like the following.

GridBagLayout gl = new GridBagLayout;
JPanel p = new JPanel;
p.setLayout;
JLabel l = new JLabel;
JTextField nm = new JTextField;
GridBagConstraints gc = new GridBagConstraints;
gc.gridx = 0;
gc.gridy = 0;
gc.fill = GridBagConstraints.NONE;
p.add;
gc.gridx = 1;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 1;
p.add;

This creates a lot of code and makes it difficult to see what exactly is happening here. The Packer class provides a fluent mechanism, so you would instead write:

JPanel p = new JPanel;
Packer pk = new Packer;
JLabel l = new JLabel;
JTextField nm = new JTextField;
pk.pack.gridx.gridy;
pk.pack.gridx.gridy.fillx;

There are many places where fluent APIs can simplify how software is written and help create an API language that helps users be much more productive and comfortable with the API because the return value of a method always provides a context for further actions in that context.

JavaScript

There are many examples of JavaScript libraries that use some variant of this: jQuery probably being the most well known. Typically, fluent builders are used to implement "database queries", for example in https://github.com/Medium/dynamite :

// getting an item from a table
client.getItem
.setHashKey
.setRangeKey
.execute
.then

A simple way to do this in JavaScript is using prototype inheritance and this.

// example from https://schier.co/blog/2013/11/14/method-chaining-in-javascript.html
class Kitten
// use it
new Kitten
.setName
.setColor
.save;

Scala

supports a fluent syntax for both method calls and class mixins, using traits and the with keyword. For example:

class Color
object Black extends Color
trait GUIWindow
trait WindowBorder extends GUIWindow
class SwingWindow extends GUIWindow
val appWin = new SwingWindow with WindowBorder
appWin.render

Raku

In Raku, there are many approaches, but one of the simplest is to declare attributes as read/write and use the given keyword. The type annotations are optional, but the native gradual typing makes it much safer to write directly to public attributes.

class Employee
my $employee = Employee.new;
given $employee
say $employee;
  1. Output:
  2. Name: Sally
  3. Surname: Ride
  4. Salary: 200

PHP

In PHP, one can return the current object by using the $this special variable which represent the instance. Hence return $this; will make the method return the instance. The example below defines a class Employee and three methods to set its name, surname and salary. Each return the instance of the Employee class allowing to chain methods.

class Employee
  1. Create a new instance of the Employee class, Tom Smith, with a salary of 100:
$employee = )
->setName
->setSurname
->setSalary;
  1. Display the value of the Employee instance:
echo $employee;
  1. Display:
  2. Name: Tom
  3. Surname: Smith
  4. Salary: 100

Python

In Python, returning self in the instance method is one way to implement the fluent pattern.
It is however , Guido van Rossum, and therefore considered unpythonic.

class Poem:
def __init__ -> None:
self.title = title
def indent:
"""Indent the poem with the specified number of spaces."""
self.title = " " * spaces + self.title
return self
def suffix:
"""Suffix the poem with the author name."""
self.title = f" - "
return self


>>> Poem.indent.suffix.title
' Road Not Travelled - Robert Frost'

Swift

In Swift 3.0+ returning self in the functions is one way to implement the fluent pattern.

class Person


let person = Person
.set
.set
.set

Immutability

It's possible to create immutable fluent interfaces that utilise copy-on-write semantics. In this variation of the pattern, instead of modifying internal properties and returning a reference to the same object, the object is instead cloned, with properties changed on the cloned object, and that object returned.
The benefit of this approach is that the interface can be used to create configurations of objects that can fork off from a particular point; Allowing two or more objects to share a certain amount of state, and be used further without interfering with each other.

JavaScript example

Using copy-on-write semantics, the JavaScript example from above becomes:

class Kitten
// use it
const kitten1 = new Kitten
.setName;
const kitten2 = kitten1
.setColor;
console.log;
// -> Kitten, Kitten

Problems

Errors can not be captured at compile time

In typed languages, using a constructor requiring all parameters will fail at compilation time while the fluent approach will only be able to generate runtime errors, missing all the type-safety checks of modern compilers. It also contradicts the "fail-fast" approach for error protection.

Debugging and error reporting

Single-line chained statements may be more difficult to debug as debuggers may not be able to set breakpoints within the chain. Stepping through a single-line statement in a debugger may also be less convenient.

java.nio.ByteBuffer.allocate.rewind.limit;

Another issue is that it may not be clear which of the method calls caused an exception, in particular if there are multiple calls to the same method. These issues can be overcome by breaking the statement into multiple lines which preserves readability while allowing the user to set breakpoints within the chain and to easily step through the code line by line:

java.nio.ByteBuffer
.allocate
.rewind
.limit;

However, some debuggers always show the first line in the exception backtrace, although the exception has been thrown on any line.

Logging

One more issue is with adding log statements.

ByteBuffer buffer = ByteBuffer.allocate.rewind.limit;

E.g. to log the state of buffer after rewind method call, it is necessary to break the fluent calls:

ByteBuffer buffer = ByteBuffer.allocate.rewind;
log.debug;
buffer.limit;

This can be worked around in languages that support extension methods by defining a new extension to wrap the desired logging functionality, for example in C#

static class ByteBufferExtensions
// Usage:
ByteBuffer
.Allocate
.Rewind
.Log
.Limit;

Subclasses

Subclasses in strongly typed languages often have to override all methods from their superclass that participate in a fluent interface in order to change their return type. For example:

class A
class B extends A
...
A a = new B.doThat.doThis; // This would work even without overriding A.doThis.
B b = new B.doThis.doThat; // This would fail if A.doThis wasn't overridden.

Languages that are capable of expressing F-bound polymorphism can use it to avoid this difficulty. For example:

abstract class AbstractA>
class A extends AbstractA
class B extends AbstractA
...
B b = new B.doThis.doThat; // Works!
A a = new A.doThis; // Also works.

Note that in order to be able to create instances of the parent class, we had to split it into two classes — AbstractA and A, the latter with no content. The approach can easily be extended if we
want to have sub-subclasses too:

abstract class AbstractB> extends AbstractA
class B extends AbstractB
abstract class AbstractC> extends AbstractB
class C extends AbstractC
...
C c = new C.doThis.doThat.foo; // Works!
B b = new B.doThis.doThat; // Still works.
In a dependently typed language, e.g. Scala, methods can also be explicitly defined as always returning this and thus can be defined only once for subclasses to take advantage of the fluent interface:
class A
class B extends A
...
val a: A = new B.doThat.doThis; // Chaining works in both directions.
val b: B = new B.doThis.doThat; // And, both method chains result in a B!

OWIKI.org. Text is available under the Creative Commons Attribution-ShareAlike License.