Talk:Fluent interface: Difference between revisions
m Task 70: Update syntaxhighlight tags - remove use of deprecated <source> tags |
|||
Line 5: | Line 5: | ||
According to the definition of fluent interface, this is not a fluent interface |
According to the definition of fluent interface, this is not a fluent interface |
||
< |
<syntaxhighlight lang="javascript"> |
||
const result = somestring.trim().padStart(10).replace('abc', 'def').padEnd(10); |
const result = somestring.trim().padStart(10).replace('abc', 'def').padEnd(10); |
||
</syntaxhighlight> |
|||
</source> |
|||
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. |
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. |
||
Line 13: | Line 13: | ||
To spread it out, to be a fluent interface the follow test has to pass |
To spread it out, to be a fluent interface the follow test has to pass |
||
< |
<syntaxhighlight lang="javascript"> |
||
const a = somestring.trim(); |
const a = somestring.trim(); |
||
const b = a.padStart(10); |
const b = a.padStart(10); |
||
Line 19: | Line 19: | ||
const d = c.padEnd(10); |
const d = c.padEnd(10); |
||
const isFluentInferace = (a === b && a === c && a === d); // isFluentInterface will be false here |
const isFluentInferace = (a === b && a === c && a === d); // isFluentInterface will be false here |
||
</syntaxhighlight> |
|||
</source> |
|||
An example that is a fluent interface |
An example that is a fluent interface |
||
< |
<syntaxhighlight lang="javascript"> |
||
class Calc { |
class Calc { |
||
constructor(v) { this.v = v; } |
constructor(v) { this.v = v; } |
||
Line 33: | Line 33: | ||
const result = (new Calc(1)).add(3).subtract(2).multiply(4).divide(3); |
const result = (new Calc(1)).add(3).subtract(2).multiply(4).divide(3); |
||
</syntaxhighlight> |
|||
</source> |
|||
Applying the test above it passes |
Applying the test above it passes |
||
< |
<syntaxhighlight lang="javascript"> |
||
const a = new Calc(1); |
const a = new Calc(1); |
||
const b = a.add(3); |
const b = a.add(3); |
||
Line 44: | Line 44: | ||
const e = d.divide(3); |
const e = d.divide(3); |
||
const isFluentInferace = (a === b && a === c && a === d && a === e); // isFluentInterface will be true here |
const isFluentInferace = (a === b && a === c && a === d && a === e); // isFluentInterface will be true here |
||
</syntaxhighlight> |
|||
</source> |
|||
== Problem with the C# sample code == |
== Problem with the C# sample code == |
||
Line 53: | Line 53: | ||
2) The "fluent-interface-benefit" (short intuitive code) is not demonstrated very convincing. I would prefer to see something like: |
2) The "fluent-interface-benefit" (short intuitive code) is not demonstrated very convincing. I would prefer to see something like: |
||
< |
<syntaxhighlight lang="csharp"> |
||
IConfiguration config = ConfigurationFluent.Create().Color("blue").Height(1).Length(2).Depth(3); |
IConfiguration config = ConfigurationFluent.Create().Color("blue").Height(1).Length(2).Depth(3); |
||
</syntaxhighlight> |
|||
</source> |
|||
or |
or |
||
< |
<syntaxhighlight lang="csharp"> |
||
IConfiguration config = ConfigurationFluent.CreateColored("blue").Height(1).Length(2).Depth(3); |
IConfiguration config = ConfigurationFluent.CreateColored("blue").Height(1).Length(2).Depth(3); |
||
</syntaxhighlight> |
|||
</source> |
|||
(Create() or CreateColored() would be static methods, returning a new instance as an "entry-Point" into the fluent interface. |
(Create() or CreateColored() would be static methods, returning a new instance as an "entry-Point" into the fluent interface. |
||
Line 65: | Line 65: | ||
That is no really good Sample too, because C# 2008 provides the with-Keyword, so one could instantiate without fluent interface as well: |
That is no really good Sample too, because C# 2008 provides the with-Keyword, so one could instantiate without fluent interface as well: |
||
< |
<syntaxhighlight lang="csharp"> |
||
var config = new Configuration() with { Color = "blue", Height = 1, Length = 2, Depth = 3 }; |
var config = new Configuration() with { Color = "blue", Height = 1, Length = 2, Depth = 3 }; |
||
</syntaxhighlight> |
|||
</source> |
|||
3) A better sample would result in stuff like: |
3) A better sample would result in stuff like: |
||
< |
<syntaxhighlight lang="csharp"> |
||
// List<SpecialItem> _SpecialItems = new List<SpecialItem>(); |
// List<SpecialItem> _SpecialItems = new List<SpecialItem>(); |
||
SpecialItem.CreateColored("blue").Height(1).Length(2).Depth(3).AddTo(_SpecialItems); |
SpecialItem.CreateColored("blue").Height(1).Length(2).Depth(3).AddTo(_SpecialItems); |
||
</syntaxhighlight> |
|||
</source> |
|||
That would demonstrate, how fluent interface reduce nesting. Compare to: |
That would demonstrate, how fluent interface reduce nesting. Compare to: |
||
< |
<syntaxhighlight lang="csharp"> |
||
// List<SpecialItem> _SpecialItems = new List<SpecialItem>(); |
// List<SpecialItem> _SpecialItems = new List<SpecialItem>(); |
||
_SpecialItems.Add(new SpecialItem() with { Color = "blue", Height = 1, Length = 2, Depth = 3 }); |
_SpecialItems.Add(new SpecialItem() with { Color = "blue", Height = 1, Length = 2, Depth = 3 }); |
||
</syntaxhighlight> |
|||
</source> |
|||
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? |
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? |
||
Line 88: | Line 88: | ||
---- |
---- |
||
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 < |
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 <syntaxhighlight lang="csharp">myObject.SetValueX(1); |
||
myObject.SetValueY(2);</ |
myObject.SetValueY(2);</syntaxhighlight> than <syntaxhighlight lang="csharp">myObject.SetValueX(1).SetValueY(2);</syntaxhighlight> 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 [[User:ErfinderDesRades|ErfinderDesRades]] are better. |
I agree that the samples from [[User:ErfinderDesRades|ErfinderDesRades]] are better. |
||
Line 98: | Line 98: | ||
In the PHP sample, what is this part good for? |
In the PHP sample, what is this part good for? |
||
< |
<syntaxhighlight lang="php"> |
||
<?php |
<?php |
||
session_start(); |
session_start(); |
||
Line 105: | Line 105: | ||
require_once 'config.php'; |
require_once 'config.php'; |
||
?> |
?> |
||
</syntaxhighlight> |
|||
</source> |
|||
== Monad == |
== Monad == |
||
Line 190: | Line 190: | ||
In [[D language]], there is this transparent feature called UFCS (Uniform Function Call Syntax), which for any call <code>x.f(y, z)</code>, if the method f is not in the object / variable x, is translated to <code>f(x, y, z)</code> 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: |
In [[D language]], there is this transparent feature called UFCS (Uniform Function Call Syntax), which for any call <code>x.f(y, z)</code>, if the method f is not in the object / variable x, is translated to <code>f(x, y, z)</code> 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: |
||
< |
<syntaxhighlight lang="D"> |
||
import std.stdio : writeln; |
import std.stdio : writeln; |
||
import std.algorithm.iteration : filter; |
import std.algorithm.iteration : filter; |
||
Line 205: | Line 205: | ||
(iota(10))); |
(iota(10))); |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
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. |
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. |
||
< |
<syntaxhighlight lang="D"> |
||
class A { |
class A { |
||
public: |
public: |
||
Line 219: | Line 219: | ||
auto obj = A().setA(5).setB(8); |
auto obj = A().setA(5).setB(8); |
||
</syntaxhighlight> |
|||
</source> |
|||
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. [[Special:Contributions/81.6.34.172|81.6.34.172]] ([[User talk:81.6.34.172|talk]]) 21:07, 29 April 2020 (UTC) |
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. [[Special:Contributions/81.6.34.172|81.6.34.172]] ([[User talk:81.6.34.172|talk]]) 21:07, 29 April 2020 (UTC) |
Revision as of 18:43, 11 May 2020
Computer science Stub‑class | |||||||||||||||||
|
Method Chaining vs Fluent Interface
According 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 isFluentInferace = (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 isFluentInferace = (a === b && a === c && a === d && a === e); // isFluentInterface will be true here
Problem with the C# sample code
Hello!
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
In 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
Shouldn'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
The 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
Is 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
Regarding "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
Issues 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
In 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
With 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)
Monad?
Isn'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
This 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
Bind 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
I 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
The 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
Should 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
In 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)