TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Chaining, or why you should stop returning void (2012)

44 点作者 debdut超过 3 年前

17 条评论

ris超过 3 年前
You should categorically not be implementing chaining semantics unless your operations are non-mutating.<p>If they are mutating and you return the same object, it&#x27;s possible for people to go <i>years</i> without realizing that&#x27;s what&#x27;s happening (no, most people don&#x27;t read the manual), assigning the result to something else, reusing the original for another thing and introducing subtle bugs all over the place.<p>See the design of python&#x27;s list `.sort()` returning None for this exact reason.<p>(and of course there are sometimes performance penalties to implementing non-mutating methods, so there are lots of valid cases for not implementing chaining semantics)
评论 #29141060 未加载
评论 #29146708 未加载
评论 #29141739 未加载
评论 #29139973 未加载
评论 #29142866 未加载
评论 #29142166 未加载
jedimastert超过 3 年前
First, needs a (2012).<p>Second, this is the very top:<p>&gt; Edit from 2018: The tone of this post is a little cringe-worthy to me now in retrospect, and I think that many APIs are probably clearer when you return void. Leaving this here for posterity.
评论 #29140013 未加载
评论 #29144453 未加载
flohofwoe超过 3 年前
The &quot;Galaxy Brain&quot; version of this advice is using plain old designated initialization of &#x27;option bag&#x27; data structures. Here&#x27;s a non-trivial C99 example from the sokol_gfx.h API to create a pipeline-state-object for 3D rendering:<p><pre><code> state.pip = sg_make_pipeline(&amp;(sg_pipeline_desc){ .layout = { .attrs = { [ATTR_vs_position].format = SG_VERTEXFORMAT_FLOAT3, [ATTR_vs_color0].format = SG_VERTEXFORMAT_FLOAT4 } }, .shader = shd, .index_type = SG_INDEXTYPE_UINT16, .cull_mode = SG_CULLMODE_BACK, .depth = { .write_enabled = true, .compare = SG_COMPAREFUNC_LESS_EQUAL, }, .label = &quot;cube-pipeline&quot; }); </code></pre> Chaining might be useful for data processing pipelines, but not for simple data initialization tasks IMHO.
评论 #29141649 未加载
评论 #29140575 未加载
emerongi超过 3 年前
I like function chaining more. E.g. Elixir&#x27;s `Map.set(map, field, value)` function combined with the `|&gt;` operator, which feeds the value from the previous operation in to the function as the first argument:<p><pre><code> person_map |&gt; Map.set(:name, &quot;Peter&quot;) |&gt; Map.set(:age, 37) |&gt; Map.set(:married, true) </code></pre> It&#x27;s so much fun to look at a chain of generic functions working on a generic data structure, while keeping the code clear. Makes me feel all warm inside. Immutability and functional programming, ain&#x27;t it nice, huh?
评论 #29139874 未加载
BoardsOfCanada超过 3 年前
I like dart&#x27;s cascade operator (..) a lot, that way you can chain calls on an object without the functions returning this. I&#x27;m sure other languages have something similar, kotlin has apply which feels a bit more heavy handed though.
评论 #29139746 未加载
评论 #29140133 未加载
评论 #29139662 未加载
评论 #29139940 未加载
评论 #29139741 未加载
a_lost_needle超过 3 年前
My functional API&#x27;s never return void because they&#x27;re functions and immutability is the benefit there. Returning void means you&#x27;re either mutating something or interacting with something thing that does. Also, chaining can be dangerous, as if it&#x27;s not implemented correctly, can hide errors, or not have adequate failure tolerance, and cleanup can be a mess if a stream or connection disconnects in the middle of your chain.<p>But in an OO project, void is a really useful. If you&#x27;re doing game programming, mutability is required for all but the most trivial games. And throwing in more functions and more variables on the stack isn&#x27;t going to benefit anything. You click a button, the gun fires. I don&#x27;t need to check the return, it add no value, adds complexity and isn&#x27;t idiomatic to the language.<p>Use the right tool for the job.
74B5超过 3 年前
It&#x27;s the fluent interface pattern.<p><a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fluent_interface" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fluent_interface</a>
评论 #29140334 未加载
评论 #29139783 未加载
laurent123456超过 3 年前
Chaining is fine when building up an object, but definitely not something that should be systematically used. That&#x27;s making the interface more complicated for little gain.
评论 #29139868 未加载
mjgoeke超过 3 年前
I work in C# but have come to a similar conclusion to his note at the top of his article.<p>C# supports extension methods, so if you want you can augment the original 3rd party class with your own (chaining in this case) methods. Or author your own “fluent interface” on your own classes, as he’s done here.<p>I’m the end, most of the time I found I was wanting a function ‘forward composition’ operator (like F#’s |&gt; ). And the only place the chaining methods really made sense was factory classes&#x2F;methods for complex declarative configuration.<p>The only ones that stuck for us were ORM mapping declarations, and factories for setting up complex domain specific data setup in tests.
评论 #29141134 未加载
AdrianB1超过 3 年前
I love this kind of blog posts because not only they present different ways of doing things and a fairly sane discussion about it, but also showing the author learning from experience and telling about it.<p>Young people are very creative (mostly between ages of 15 and 25) and that creates new ideas. Experienced people test the new ideas and draw conclusions. We need both to progress, the first should be as creative as possible and the later as analytical thinking as possible. It is the innovation pipeline, the first throw the ideas, the others refine, filter and select.
kevinmgranger超过 3 年前
There&#x27;s competing incentives for API ergonimics and making mutations &#x2F; ownership explicit. Kotlin&#x27;s scope functions really get you the best of both worlds with this.<p>Lambdas can have a &quot;receiver&quot;, which acts as the (implicit or explicit) `this` for the lambda.<p>`apply` even returns the object itself, so the first example could be:<p><pre><code> frame.add(FormPanel().apply { setSize(300, 150) add(usernameLabel) add(usernameField) add(passwordLabel) add(passwordField) })</code></pre>
alerighi超过 3 年前
This can be inefficient depending from the language and the compiler. The compiler many not always know that the this that you return is the same of the object you are calling the method to, and that can prevent further optimizations.<p>I don&#x27;t see either any readability advantages of doing so, doing that just for not typing the name of the variable is nonsense, also the code is less clear to the reader (you have to know that the method that you call returns the same objects, it&#x27;s not obvious, it can as well return another object, or a copy of that object). It&#x27;s more explicit doing it the normal way.
MichaelBurge超过 3 年前
You could also make a single-letter alias:<p><pre><code> auto&amp; r = rectangle; r.width(100); r.height(100); </code></pre> I like to use very short variable names(single or 3 letters at most) but fully write out the type:<p><pre><code> Rectangle r; </code></pre> Which is similar in spirit to aliasing the variable.<p>&quot;Rectangle&quot; is probably not a good example, because rectangles are pure data used for many different purposes. So &quot;rectangle&quot; is often a poor variable name. But many programs use 1 type for 1 purpose, and then the type alone is enough.
avl999超过 3 年前
Chaining works well in builder objects and perhaps in some GUI programming or some other very specialized cases but most of the classes I write don&#x27;t have sufficient mutable state to make this kind of thing worth it.<p>My advice would be to almost always start with a void (unless builder objects) and then add chaining if the evolution of your API dictates that chaining together calls would be a common enough usecase.
rchaves超过 3 年前
A better reason to not return void is that it will make you think more about immutability and side-effects. Not returning void allow you to reduce the hidden state changes or at least to manage them better
thriftwy超过 3 年前
These tricks ate necessary due to lack of property assignment syntax in languages such as Java. C# does not have this problem and they may start pointing fingers.
评论 #29139974 未加载
评论 #29139735 未加载
aaaaaaaaaaab超过 3 年前
Yeah, how about no?<p>Mutating methods should return void, period.