Talk:Fluent interface
![]() | This article is rated Stub-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||
|
Returning this In Chained Methods
editUnder "Implementation": "... by having each method return the object to which it is attached, often referred to as this or self" Where did this criterion come from? It didn't appear in, for example, Fowler's original article, which instead explicitly said "You should choose your return type based on what you need to continue fluent action.", going on to use JMock as an example of a fluent library where the chained methods often return objects with different types from that which the methods were called on: those different types being more useful than simply finishing with "return this;" would have been. — Preceding unsigned comment added by 125.237.145.229 (talk) 02:23, 4 August 2024 (UTC)
Method Chaining vs Fluent Interface
editAccording to the definition of fluent interface, this is not a fluent interface
const result = somestring.trim().padStart(10).replace('abc', 'def').padEnd(10);
A Fluent Interface chains on "this" which each method modifying the same object. The code above a new object is returned from each method, them a method of that new object is called. That is just method chaining.
To spread it out, to be a fluent interface the follow test has to pass
const a = somestring.trim();
const b = a.padStart(10);
const c = b.replace('abc', 'def');
const d = c.padEnd(10);
const isFluentInterface = (a === b && a === c && a === d); // isFluentInterface will be false here
An example that is a fluent interface
class Calc {
constructor(v) { this.v = v; }
add(v) { this.v += v; return this; }
subtract(v) { this.v -= v; return this; }
multiply(v) { this.v *= v; return this; }
divide(v) { this.v ;= v; return this; }
};
const result = (new Calc(1)).add(3).subtract(2).multiply(4).divide(3);
Applying the test above it passes
const a = new Calc(1);
const b = a.add(3);
const c = b.subtract(2);
const d = c.multiply(4);
const e = d.divide(3);
const isFluentInterface = (a === b && a === c && a === d && a === e); // isFluentInterface will be true here
Problem with the C# sample code
editHello!
1) I tried the C# sample code, but the compiler alerted 12 syntax errors. Please give a sample with runnable code.
2) The "fluent-interface-benefit" (short intuitive code) is not demonstrated very convincing. I would prefer to see something like:
IConfiguration config = ConfigurationFluent.Create().Color("blue").Height(1).Length(2).Depth(3);
or
IConfiguration config = ConfigurationFluent.CreateColored("blue").Height(1).Length(2).Depth(3);
(Create() or CreateColored() would be static methods, returning a new instance as an "entry-Point" into the fluent interface.
That is no really good Sample too, because C# 2008 provides the with-Keyword, so one could instantiate without fluent interface as well:
var config = new Configuration() with { Color = "blue", Height = 1, Length = 2, Depth = 3 };
3) A better sample would result in stuff like:
// List<SpecialItem> _SpecialItems = new List<SpecialItem>();
SpecialItem.CreateColored("blue").Height(1).Length(2).Depth(3).AddTo(_SpecialItems);
That would demonstrate, how fluent interface reduce nesting. Compare to:
// List<SpecialItem> _SpecialItems = new List<SpecialItem>();
_SpecialItems.Add(new SpecialItem() with { Color = "blue", Height = 1, Length = 2, Depth = 3 });
Unfortunately the benefit "help from Intellisense" (a fluent interface supports fluent writing code) cannot be shown in an article, or would you like to add screenshots?
ErfinderDesRades (talk) 11:11, 15 December 2008 (UTC)
IMO the published sample is garbage. Chaining in itself does not make for readability and the ALT.NET community is severely abusing mere chaining with this misunderstanding. There's nothing less readable about
myObject.SetValueX(1);
myObject.SetValueY(2);
than
myObject.SetValueX(1).SetValueY(2);
In my opinion, this actually makes it less readable because these are distinct statements that are being slurred together.
I agree that the samples from ErfinderDesRades are better. Jon (talk) 09:52, 30 September 2009 (UTC)
PHP sample
editIn the PHP sample, what is this part good for?
<?php
session_start();
error_reporting(E_ALL | E_USER_NOTICE);
require_once 'classes/Loader.php';
require_once 'config.php';
?>
Monad
editShouldn't a reference to monad be included somewhere in this article? Dave Sexton (talk) 08:43, 26 July 2010 (UTC)
Fluent Interface vs Method Chains
editThe article correctly states that a fluent interface entails more than just method chaining but then goes on to to show examples that solely use Method Chaining. This is misleading. The article and the examples could be improved to reflect a Fluent Interface' role in creating internal DSLs. This would make the distinction more clear. —Preceding unsigned comment added by 87.123.52.156 (talk) 08:46, 22 September 2010 (UTC)
- Same comment from my side. The C++ example in fact does implement a fluent interface, but not so the other examples. One correct example is much more worth than a dozen of examples whereof only one really illustrates the point. Since nothing happened since this comment from 2010 I am going to remove the other examples. --Chiccodoro (talk) 11:15, 7 September 2012 (UTC)
- The C++ example is also unnecessarily verbose. What about just deleting them all and adding a concise example in pseudo-code? As soon as you use a real language, people start getting all fanboyish and feel compelled to add their favorite one to the mix. — Preceding unsigned comment added by 82.9.176.129 (talk) 03:15, 18 December 2014 (UTC)
JQuery
editIs JQuery considered a fluent interface? If so, it should be referenced in this article.
Also, I'd like to echo the above topic's concern. This article doesn't make clear what the requirements for fluent interfaces are, beyond method chaining. —Preceding unsigned comment added by 208.91.1.14 (talk) 22:11, 27 October 2010 (UTC)
jQuery (note capitalization) definitely at least uses method chaining[1]. When you start with a selection of elements — e.g., $("li") to select all list items in the page — then most chained functions do indeed return the same collection (or perhaps a reduced/expanded collection) for further operations. Honestly, the Martin Fowler piece cited in the main article isn't terribly clear on what would be required to call something a "Fluent interface" either, though it does cite JMock as an example.
Dave Brown (talk) 01:11, 8 April 2013 (UTC)
The non-existence of C# 3.5
editRegarding "With C# 3.5 and later there are more advanced method chaining techniques".
I don't think C# 3.5 exist; there is C# 3.0 and .NET Framework 3.5. Do you agree? --Mortense (talk) 03:09, 17 November 2010 (UTC)
Single-statement nature and debugging
editIssues raised in this comment were addressed, please see the 'Problems' section.
The article should elaborate on the problematic side of fluent style, which is debugging: fluent chains constitute a single statement or expression, which can be problematic when debugging, compared to more classic styles.
Typically, for many languages you are not able set breakpoints within a chain, and stepping will often be problematic.
There is also an issue with crash stack reports, in which a fluent chain will be treated as a single statement when the debug information is limited to statements (which for many languages is the case). That can make identifying which method call triggered an issue ambiguous if the same method is present more than once in a chain. —Preceding unsigned comment added by 88.174.31.159 (talk) 20:58, 7 January 2011 (UTC)
Problems > Subclasses
editIn Java, Generics are used to enable subclassing without the subclasses having to implement all parent methods just to change the return type. JATL is a good example how it is done. — Preceding unsigned comment added by 94.143.89.37 (talk) 19:17, 25 December 2012 (UTC)
Minor Problem with the Java sample code
editWith the font being used and the use of the variable name "l", it requires some thought to see that "l" is not "1" in pack( l ).
I tried changing "l" to "label" but that made the alignment of the grid method invocations look ... a bit ... ugly.
So I thought I'd just mention my problem with the "l" here. — Preceding unsigned comment added by 219.88.170.8 (talk) 19:44, 20 January 2014 (UTC)
The sample has a WRONG reference to Packer200, which is used for handling JAR.
Its original reference was https://java.net/projects/packer but the java.net site closed. — Preceding unsigned comment added by 2001:F70:8C40:500:858F:B19C:A296:5FEE (talk) 14:02, 28 October 2021 (UTC)
Monad?
editIsn't this kind of style similar to a Monad? Should http://en.wikipedia.org/wiki/Monad_(functional_programming) be linked in the text? — Preceding unsigned comment added by Sukima (talk • contribs) 22:29, 21 May 2014 (UTC)
Re monads - this is a Javascript and purescript comparison showing this is just monads. https://github.com/pelotom/purescript-d3#example Here is the commentary: https://twitter.com/pelotom/status/483504492034269184 — Preceding unsigned comment added by 124.170.192.192 (talk) 04:36, 19 July 2014 (UTC)
Example Farm
editThis is yet another computer science article that has turned into a large body of inconsistent and completely unecessary examples. The JavaScript section is (as usual) particularly egregious. A single pseudo-code example would more than suffice. — Preceding unsigned comment added by 82.9.176.129 (talk) 03:11, 18 December 2014 (UTC)
Not a Monad
editBind is not the equivalent of a map operation, which is what is needed for method chaining. This is a misunderstanding of monads, and should be removed. — Preceding unsigned comment added by 98.189.26.19 (talk) 22:26, 12 February 2015 (UTC)
return this; vs. copy-on-write
editI think this article should mention the difference between two semantic variants of the fluent interface pattern that I've encountered: one where all mutators end with return this;
and one (copy-on-write) where the implementing classes are immutable and the mutators return a modified copy. NeonMerlin 02:22, 1 July 2018 (UTC)
Java recursive generics
editThe Java section has only usage examples from language libraries and doesn't show how you can build fluent interfaces yourself with recursive generics and other techniques. --Iamrcr (talk) 23:49, 20 February 2019 (UTC)
Java 8
editShould we list Java 8 Streams under the main fluent section as this is now builtin to the language? — Preceding unsigned comment added by Ginister (talk • contribs) 11:03, 27 March 2019 (UTC)
D programming language and UFCS
editIn D language, there is this transparent feature called UFCS (Uniform Function Call Syntax), which for any call x.f(y, z)
, if the method f is not in the object / variable x, is translated to f(x, y, z)
and the function f and its overloads are searched in all imported modules and symbols in the current scope. This allows fancy extensions, and Fluent like operations that can be extended by the user:
import std.stdio : writeln;
import std.algorithm.iteration : filter;
import std.range : iota;
void main()
10.iota // returns numbers from 0 to 9
// filter for even numbers
.filter!(a => a % 2 == 0)
.writeln(); // writes them to stdout
// Traditional style:
writeln(filter!(a => a % 2 == 0)
(iota(10)));
}
The two statements are exactly equivalent, and UFCS is basically a syntax sugar. However, it does allow extending any type, and adding fluent style operations.
class A {
public:
int a, b, c;
auto setA(int a_) { a = a_; return this; }
}
auto setB(A t, int b_) { t.b = b_; return t; }
auto obj = A().setA(5).setB(8);
will work (as long as setB has access to the field b). setB doesn't even need to be in the same module. In fact due to powerful metaprogramming (mixins and mixin templates) and compile time introspection (compile traits), it is possible to automate generation of fluent interfaces for any class. Just my two cents. One my argue that this is just a syntax sugar, but so is 'Fluent' interface. It is just to save creating temporary variables with names, and making code readable from left to right, which UFCS enables. 81.6.34.172 (talk) 21:07, 29 April 2020 (UTC)