<p>According to the <a href="https://en.wikipedia.org/wiki/Smalltalk" rel="noreferrer">Wikipedia article on Smalltalk</a>, in the <a href="https://en.wikipedia.org/wiki/Smalltalk#Expressions" rel="noreferrer">Expressions section</a>,</p>
<blockquote>
<pre><code>| window |
window := Window new.
window label: 'Hello'.
window open
</code></pre>
<p>If a series of messages are sent to the same receiver as in the example above, they can also be written as a cascade with individual messages separated by semicolons:</p>
<pre><code>Window new
  label: 'Hello';
  open
</code></pre>
</blockquote>
<p>This seems like a useful feature, but I don’t know of any newer OO language that has it — not even Objective-C, which uses Smalltalk-style OO rather than Simula-style like C++.</p>
<p>What are some reasons to exclude this feature?</p>

<syntax><object-oriented><smalltalk>
Why is Smalltalk’s cascade operator not more common?
<p>One issue of this feature is implicit shadowing.</p>
<p>JavaScript has a <code>with</code> statement that works like a cascade operator that is no longer recommended and has been dropped from the current version of the standard. Commonly used implementations only support it for backwards compatibility.</p>
<p>It looks like this:</p>
<pre><code>with (new Window) {
    label('Hello');
    open();
}

// without with:
let window = new Window;
window.label('Hello');
window.open();
</code></pre>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with" rel="nofollow noreferrer">MDN's page on the <code>with</code> statement</a> gives some examples of the downsides that come with this feature, all due to implicit shadowing:</p>
<blockquote>
<ul>
<li>Performance: The <code>with</code> statement forces the specified object to be searched first for all name lookups. Therefore, all identifiers that aren't members of the specified object will be found more slowly in a <code>with</code> block. Moreover, the optimizer cannot make any assumptions about what each unqualified identifier refers to, so it must repeat the same property lookup every time the identifier is used.</li>
<li>Readability: The <code>with</code> statement makes it hard for a human reader or JavaScript compiler to decide whether an unqualified name will be found along the scope chain, and if so, in which object. [...]</li>
<li>Forward compatibility: Code using <code>with</code> may not be forward compatible, especially when used with something other than a plain object, which may gain more properties in the future. [...]</li>
</ul>
</blockquote>
<p>The last of those is especially problematic: introducing a new method to an existing class may potentially break any <code>with</code> statement on an instance of that class.</p>

CC BY-SA 4.0
2023-05-17T14:28:11.203Z
2023-05-17T14:28:11.203Z
Jasmijn
CC BY-SA 4.0
2023-08-15T18:05:57.847Z
The performance issue you cite seems a little dubious to me.  Obviously in a static environment this cost can be pushed into the compile/type checking phase, so is irrelevant, but I believe most modern Javascript virtual machines will compile a new version of each function for each set of types it is called with, so even there the cost should only be the first time a given type is used with the function.  Also for languages where each statement in the block is *required* to be a call to a method of the given object , neither the performance nor readability issues apply.  This is true ...
occipita
CC BY-SA 4.0
2023-08-15T18:08:26.590Z
... for both the Smalltalk and Rust syntaxes given as examples.  The issue in javascript is that each statement in a `with` block may *either* be a call to the object *or* some other general statement to be interpreted as normal.  This is clearly an inferior solution.  The forward compatibility issue always applies to any code involving superclasses that can have new methods added, and is not, as far as I can see, made any worse by using a method chaining syntax.
occipita
<p>Depending on where you draw the line for &quot;newer&quot;, there are some other examples. Dart has a very similar <a href="https://flutterbyexample.com/lesson/cascade-notation" rel="noreferrer">cascade notation</a> in the form of a double dot:</p>
<pre><code>// with cascade notation:
querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) =&gt; window.alert('Confirmed!'))

// without cascade notation
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) =&gt; window.alert('Confirmed!'));
</code></pre>
<p>As to why there aren't many other languages that do this, I can think about two reasons:</p>
<ol>
<li>This way of invocation implies the call of multiple methods that have no useful return value and instead mutate the internal state of the receiver. This is widely considered bad practice, opposed to a more functional/immutable approach.</li>
<li>A similar result can be achieved with no additional syntax in any programming language that supports dot notation. This is commonly applied when building objects with optional or default configuration values, as in this Rust example:</li>
</ol>
<pre><code>let agent: Client = ClientBuilder::new()
    .user_agent(APP_USER_AGENT)
    .timeout(std::time::Duration::from_secs(8))
    .build()
    .unwrap();
</code></pre>
<p>All that is required is for each method to return the type of the original receiver. When incrementally configuring an object (as in the <code>ClientBuilder</code> example) this is a &quot;value&quot; type (returning a copy of the object), but it may as well be a reference that is returned for the sole purpose of allowing this &quot;cascading&quot; style.</p>

CC BY-SA 4.0
2023-05-17T14:37:46.230Z
2023-05-17T14:37:46.230Z
Maldus
CC BY-SA 4.0
2023-08-15T18:00:22.393Z
It's worth noting that the convention of making methods that mutate an object return `this` (like the ones in your `ClientBuilder` example) apparently originated with Smalltalk programmers migrating to other environments and finding this feature missing in them.
occipita
CC BY-SA 4.0
2023-05-17T14:48:43.197Z
Oh, I didn’t know that Dart had this! That’s interesting to see, and yes I absolutely would count this as an example of what I meant.
Bbrk24
# Why is Smalltalk’s cascade operator not more common?
Posted by: username_0 on 2023-05-17
According to the Wikipedia article on Smalltalk, in the Expressions section,

| window |
window := Window new.
window label: 'Hello'.
window open

If a series of messages are sent to the same receiver as in the example above, they can also be written as a cascade with individual messages separated by semicolons:
Window new
  label: 'Hello';
  open


This seems like a useful feature, but I don’t know of any newer OO language that has it — not even Objective-C, which uses Smalltalk-style OO rather than Simula-style like C++.
What are some reasons to exclude this feature?
**Tags:** syntax object-oriented smalltalk
---
## 2 answers
### Answer by username_3 on 2023-05-17. Score: 10 | Accepted answer
Depending on where you draw the line for "newer", there are some other examples. Dart has a very similar cascade notation in the form of a double dot:
// with cascade notation:
querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))

// without cascade notation
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

As to why there aren't many other languages that do this, I can think about two reasons:

This way of invocation implies the call of multiple methods that have no useful return value and instead mutate the internal state of the receiver. This is widely considered bad practice, opposed to a more functional/immutable approach.
A similar result can be achieved with no additional syntax in any programming language that supports dot notation. This is commonly applied when building objects with optional or default configuration values, as in this Rust example:

let agent: Client = ClientBuilder::new()
    .user_agent(APP_USER_AGENT)
    .timeout(std::time::Duration::from_secs(8))
    .build()
    .unwrap();

All that is required is for each method to return the type of the original receiver. When incrementally configuring an object (as in the ClientBuilder example) this is a "value" type (returning a copy of the object), but it may as well be a reference that is returned for the sole purpose of allowing this "cascading" style.
> **Comments:**
> **username_0** (2023-05-17): Oh, I didn’t know that Dart had this! That’s interesting to see, and yes I absolutely would count this as an example of what I meant.  
> **username_2** (2023-08-15): It's worth noting that the convention of making methods that mutate an object return `this` (like the ones in your `ClientBuilder` example) apparently originated with Smalltalk programmers migrating to other environments and finding this feature missing in them.  
---
### Answer by username_1 on 2023-05-17. Score: 4
One issue of this feature is implicit shadowing.
JavaScript has a with statement that works like a cascade operator that is no longer recommended and has been dropped from the current version of the standard. Commonly used implementations only support it for backwards compatibility.
It looks like this:
with (new Window) {
    label('Hello');
    open();
}

// without with:
let window = new Window;
window.label('Hello');
window.open();

MDN's page on the with statement gives some examples of the downsides that come with this feature, all due to implicit shadowing:


Performance: The with statement forces the specified object to be searched first for all name lookups. Therefore, all identifiers that aren't members of the specified object will be found more slowly in a with block. Moreover, the optimizer cannot make any assumptions about what each unqualified identifier refers to, so it must repeat the same property lookup every time the identifier is used.
Readability: The with statement makes it hard for a human reader or JavaScript compiler to decide whether an unqualified name will be found along the scope chain, and if so, in which object. [...]
Forward compatibility: Code using with may not be forward compatible, especially when used with something other than a plain object, which may gain more properties in the future. [...]


The last of those is especially problematic: introducing a new method to an existing class may potentially break any with statement on an instance of that class.
> **Comments:**
> **username_2** (2023-08-15): The performance issue you cite seems a little dubious to me.  Obviously in a static environment this cost can be pushed into the compile/type checking phase, so is irrelevant, but I believe most modern Javascript virtual machines will compile a new version of each function for each set of types it is called with, so even there the cost should only be the first time a given type is used with the function.  Also for languages where each statement in the block is *required* to be a call to a method of the given object , neither the performance nor readability issues apply.  This is true ...  
> **username_2** (2023-08-15): ... for both the Smalltalk and Rust syntaxes given as examples.  The issue in javascript is that each statement in a `with` block may *either* be a call to the object *or* some other general statement to be interpreted as normal.  This is clearly an inferior solution.  The forward compatibility issue always applies to any code involving superclasses that can have new methods added, and is not, as far as I can see, made any worse by using a method chaining syntax.  
---
