In object-oriented programming, '''method cascading''' is syntax which allows multiple methods to be called on the same object. This is particularly applied in fluent interfaces.
For example, in Dart, the cascade: <syntaxhighlight lang=cpp> a..b() ..c(); </syntaxhighlight> is equivalent to the individual calls: <syntaxhighlight lang=cpp> a.b(); a.c(); </syntaxhighlight>
Method cascading is much less common than method chaining – it is found only in a handful of object-oriented languages, while chaining is very common. A form of cascading can be implemented using chaining, but this restricts the interface; see comparison with method chaining, below.
==Application== Cascading is syntactic sugar that eliminates the need to list the object repeatedly. This is particularly used in fluent interfaces, which feature many method calls on a single object.
This is particularly useful if the object is the value of a lengthy expression, as it eliminates the need to either list the expression repeatedly or use a temporary variable. For example, instead of either listing an expression repeatedly: <syntaxhighlight lang=dart> a.b().c(); a.b().d(); </syntaxhighlight> or using a temporary variable: <syntaxhighlight lang=dart> n = a.b(); n.c(); n.d(); </syntaxhighlight> cascading allows the expression to be written once and used repeatedly: <syntaxhighlight lang=dart> a.b()..c() ..d(); </syntaxhighlight>
==Comparison with method chaining== {{further|Method chaining}} Given a method call <code>a.b()</code>, after executing the call, method cascading evaluates this expression to the ''left'' object <code>a</code> (with its new value, if mutated), while method chaining evaluates this expression to the ''right'' object.
;Chaining The following chain (in C++): <syntaxhighlight lang=cpp> a.b().c(); </syntaxhighlight> is equivalent to the simple form: <syntaxhighlight lang=cpp> b = a.b(); b.c(); </syntaxhighlight>
;Cascading The following cascade (in Dart): <syntaxhighlight lang=dart> a..b() ..c(); </syntaxhighlight> is equivalent to the simple form: <syntaxhighlight lang=dart> a.b(); a.c(); </syntaxhighlight>
Cascading can be implemented in terms of chaining by having the methods return the target object (receiver, <code>this</code>, <code>self</code>). However, this requires that the method be implemented this way already – or the original object be wrapped in another object that does this – and that the method not return some other, potentially useful value (or nothing if that would be more appropriate, as in setters). In fluent interfaces this often means that setters return ''this'' instead of nothing.
==Languages==
=== Pascal === Within the component statement of the with statement, the components (fields) of the record variable specified by the '''with''' clause can be denoted by their field identifier only, i.e. without preceding them with the denotation of the entire record variable. The with clause effectively opens the scope containing the field identifiers of the specified record variable, so that the field identifiers may occur as variable identifiers. <syntaxhighlight lang="pascal"> with date do if month = 12 then begin month := 1; year := year + 1 end else month := month + 1
{ is equivalent to }
if date.month = 12 then begin date.month := 1; date.year := date.year + 1 end else date.month := date.month + 1
</syntaxhighlight>
===Smalltalk=== Method chains and cascades were both introduced in Smalltalk; most subsequent object-oriented languages have implemented chains, but few have implemented cascades. In Smalltalk the semicolon operator can be used to send different messages to the same object:{{sfn|Beck|1997|loc="Cascade", pp. 183–185}} <syntaxhighlight lang=smalltalk> self listPane parent color: Color black; height: 17; width: 11 </syntaxhighlight> Compare with separate statements, terminated with a period, also using a variable for abbreviation: <syntaxhighlight lang=smalltalk> |parent| parent := self listPane parent. parent color: Color black. parent height: 17. parent width: 11. </syntaxhighlight>
One subtlety is that the value of a method call ("message") in a cascade is still the ordinary value of the message, ''not'' the receiver. This is a problem when you do want the value of the receiver, for example when building up a complex value. This can be worked around by using sending a <code>yourself</code> message that just returns the receiver.{{sfn|Beck|1997|loc="Yourself", pp. 186–188}} For example, the "add an object to a collection" method (<code>Collection>>add: anObject</code>) returns the object that was added, not the collection. Thus to use this in a cascade in an assignment statement, the cascade must end with <code>yourself</code>, otherwise the value will just be the last element added, not the collection itself: <syntaxhighlight lang=smalltalk> all := OrderedCollection new add: 5; add: 7; yourself. </syntaxhighlight>
Note that <code>yourself</code> is not special in Smalltalk: rather <code>yourself</code> is just defined in the standard library, e.g. on class <code>Object</code> or somewhere similar:
<syntaxhighlight lang=smalltalk> Object>>yourself ^self </syntaxhighlight>
This is in contrast to Smalltalk's <code>self</code> and <code>super</code> (and <code>thisContext</code>) which are defined within the language itself, and so can only be replaced or altered via a change to the compiler.
===Visual Basic=== Visual Basic uses the [https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/with-end-with-statement <code>With</code> statement] to enable an arbitrary number of method calls or property accesses on the same object:
<syntaxhighlight lang=vbscript> With ExpressionThatReturnsAnObject .SomeFunction(42) .Property = value End With </syntaxhighlight>
<code>With..End With</code> blocks in Visual Basic can be nested:
<syntaxhighlight lang=vbscript> With ExpressionThatReturnsAnObject .SomeFunction(42) .Property = value With .SubObject .SubProperty = otherValue .AnotherMethod(42) End With End With </syntaxhighlight>
===Dart=== Among newer languages, Dart implements cascades, using a double-dot <code>..</code> "cascaded method invocation operation". Unlike Smalltalk, in Dart the value of a cascaded method invocation is the receiver (base object), not the value of the (uncascaded) method invocation, and thus there is no need for <code>yourself</code>. Dart uses properties, and thus rather than using method syntax for getters and setters (<code>foo.getBar(); foo.setBar(b);</code>), it uses field value/assignment syntax (<code>foo.bar; foo.bar = b;</code>), and cascades work with assignments: <syntaxhighlight lang=dart> a..string = 'Hello world!' ..done = true; </syntaxhighlight> is equivalent to: <syntaxhighlight lang=dart> a.string = 'Hello world!'; a.done = true; </syntaxhighlight>
===Lisp and dialects=== The builtin <code>doto</code> macro can be used in Clojure to call multiple methods on the same object without binding it to a variable, which is mostly useful to operate on mutable objects from the host language.
<syntaxhighlight lang=clojure> (doto (java.util.ArrayList.) (.add 1) (.add 3) (println)) ;not limited to methods ;;; expands to code equivalent to (let [l (java.util.ArrayList.)] (.add l 1) (.add l 3) (println l) l) ; the form evaluates to the first input </syntaxhighlight>
Similar macros are available or can be easily defined in various other lisps like Common Lisp.
==References== {{reflist}} {{refbegin}} * {{cite book | first = Kent | last = Beck | authorlink = Kent Beck | year = 1997 | title = Smalltalk Best Practice Patterns | publisher = Prentice Hall | isbn = 978-0134769042 }} {{refend}}
==External links== ;Dart * "[http://news.dartlang.org/2012/02/method-cascades-in-dart-posted-by-gilad.html Method Cascades in Dart]", Gilad Bracha, February 17, 2012 * ''[https://www.dartlang.org/articles/m1-language-changes/ Milestone 1 Language Changes],'' "[https://www.dartlang.org/articles/m1-language-changes/#cascades Cascades]", Bob Nystrom, July 2012 (updated March 2013)
Cascading