71 comments

[ 4.1 ms ] story [ 135 ms ] thread
First, needs a (2012).

Second, this is the very top:

> 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.

It's amazing how easily my brain skips a subtitle like this. Years of subconsciously parsing advertisements has won over my elementary school teachers encouragement to "read the whole passage."
Same. Bites me more than I'd like to admit.
Y'know, I've been wondering lately what's been going on with my reading comprehension. I just wrote off all these errors over the last few years as part of getting old.

I've been so busy patting myself on the back for succeeding in not giving any attention to ads - I never stopped to think there might be a cost.

Commenting about the cringe-worthiness of the tone: I noticed early on in my career that folks seem to be extremely polar in their idea of "right" and "wrong" choices when it comes to software. This crystallization is self-fulfilling, as the bombastic tone dissuades softer voices from expressing dissenting opinions or new ideas. Sometimes there are scientifically proven "right" ways to do things, i.e. comparing the computational or space efficiency of different algorithms. When it comes down to code style and API design though, what really matters is self-consistency and clarity. Much of the rest is down to preference and personal expression.
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.
Fluent builder patterns are wildly popular in C# however.

At this point it seems like a stylistic choice.

There are a bunch of different approaches that other languages that take that make this unnecessary as well.

Some functional languages simply don't tend to use mutable objects with method/property syntax so you can just chain function calls to achieve the same result. (Also some languages have syntactic sugar to do the same thing for method calls)

VB.net (unpopular as it is) has "With" statements that allow you to simply avoid repeating the name of the object you are mutating with method calls/property assignments (this looks very similar to a "fluent api" but it's just a serious of normal property assignments with the object name omitted using a with statement):

  With theCustomer
      .Name = "Coho Vineyard"
      .URL = "http://www.cohovineyard.com/"
      .City = "Redmond"
  End With
Functional programming won't save you from the fact that you don't want to have constructor with dozen unnamed parameters. That's also fragile in the face of code change.
Well, the situation is a bit better than you make out. Your parameters may be unnamed, but they should at least be typed. Cases like `Directory.Move : IDirectoryInfo -> IDirectoryInfo -> unit` are a bit of a pain to give unambiguous types, but a twelve-parameter method in which every parameter has a different type (`CustomerId`, `BankId`, whatever - tiny types) is orders of magnitude less fragile than one in which everything is a string.
It's still not good enough. Java also gives you typing but builders and chained setters are still used.
That's because Java, like C#, makes it really painful to define a new type. When it takes huge amounts of boilerplate to define a new type to hold a piece of dumb data, of course nobody does it! In F# it's one line of code, so it's idiomatic to define dozens of tiny types and use them to constrain the semantics of your program.
I'm just not sure it will solve the problem in the fact of forward compatibility.
Chaining is fine when building up an object, but definitely not something that should be systematically used. That's making the interface more complicated for little gain.
Why? Whenever you return „void“ you return „this“. That does not make anything more complicated. It is a pattern that suits itself well in front end code. When it comes to async. code, however, it’s a different story since you return promises in this case that are also chainable.
> When it comes to async. code, however, it’s a different story since you return promises in this case that are also chainable.

So that's one issue. That's what I mean by the interface being more complicated - void is void, but if you return something there might be some edge cases, some of which are difficult to predict. Personally I think it's not worth the trouble.

I like dart's cascade operator (..) a lot, that way you can chain calls on an object without the functions returning this. I'm sure other languages have something similar, kotlin has apply which feels a bit more heavy handed though.
Oooh I didn’t know this was a thing. I had that as an idea recently but it’s really interesting to hear it already exists!

I have been hearing a bunch of interesting things about Dart lately and feel like I should check it out.

(comment deleted)
Pretty sure this was taken from Smalltalk, which uses the semicolon as the cascade.

So

   a b c d.   
sends c to the result of sending b to a, and d to the the previous result etc.

   a b; c; d.
Sends b, c, and d to a. This is often indicated visually:

   a b;
     c;
     d.
Semicolon/method cascade is one of my favorite bits of Smalltalk syntax.

I'm a bit neutral on returning self (either explicitly or implicitly), although it enables left-to-right pseudo-expressions like 1 + 2 * 3.

I am also fond. And interestingly, the cascade actually separates keyword messages nicely without having to use brackets, which normal messaging does not.

So:

    a foo:2; bar:4.
This sends foo: and bar: to a. But you can't do that without the cascade:

    a foo:2 bar:4.
That's not bar: sent to the result of a foo:, that's foo:bar: sent to a.

For normal messages you have to use brackets:

    (a foo:2) bar:4.
Which is ugly and asymmetrical with respect to cascades. So in Objective-S, I introduced the pipe for message chaining:

    a foo:2 | bar: 4.
IMHO, this works both visually and semantically, because you are "piping" the result of "a foo:2" into the message expression " bar: 4", as the receiver.
What's heavy-handed about Kotlin's apply? It's just an extension function in the standard library (so not a separate language feature, if that's what you mean by "heavy"?) and solves the problem cleanly IMHO.

You can easily implement a similar extension function in C#, although the syntax is slightly uglier and you don't get the implicit receiver in the lambda.

I just mean it looks a bit more obtrusive to me than just ..

I agree that it speaks volumes about the power of the language itself.

Pascal (https://www.freepascal.org/docs-html/ref/refsu62.html) and Visual Basic (https://docs.microsoft.com/en-us/dotnet/visual-basic/languag...) have with.

That serves a similar purpose, (in VB only for accessing multiple fields in an object, I think)

Visual Basic’s syntax is a bit safer. Requiring that seemingly superfluous dot means there can’t be confusion between referencing fields and referencing local or global variables.

In Pascal adding a field to a record whose name shadows that of a local can change the meaning of the statements in a with statement, and removing it may silently ‘fix’ a broken reference to a no longer existing field.

with A, B, C, D do is asking for trouble even more.

It's the fluent interface pattern.

https://en.wikipedia.org/wiki/Fluent_interface

Yeah some of the issues with error handling are pretty serious. I would say in C++ it could be useful only for simple “nothrow” routines for basic object configuration; this would apply for cases when the configurations should happen after construction.

Aside from that I wouldn’t use it for complex algorithms.

It’s almost like a weird intersection between functional and object oriented paradigms.

But there’s not much benefit from these two approaches:

rect.setHeight(125).setWidth(250);

rect.setHeight(125); rect.setWidth(250);

That being said, for algorithms similar in spirit to the chaining I think the C# Linq language is a good example of something that works well in a “chained” fashion.

God, I hate that pattern.

Give me an API that takes a key/value pair where key is the name of the field to be set, and value is the value to be set.

Easy to read. Great way to get people to pay attention to tge datamodel, Low overall maintenance burden.

As opposed to: lets add another bloody withMethod() to the API,

so people can write

MethodsLikeThis .withThis(Thing) .andThat(Stuff) .atTheEndofWhich(aThingwithAnEnd) .someone(you) .hopes(new Hope("There is a point to it all)).but().alas("There is not.");

So now my stack traces look daft when things break in a contrived attempt to make things prettier to read when otherwise it could have been:

Unable to set value for key:"Kye" value:"if you spell it right, it will set it. Unless it isn't even the right datatype". Unknown field:"Kye"

Build your state packet. Prime your logical machine. Push the button. Verify output. Do not try to turn my test suite into a work of effing Shakespeare.

Maybe that's just me being crotchety though.

> Give me an API that takes a key/value pair where key is the name of the field to be set, and value is the value to be set.

Not in a statically typed language, please! It should be a compile-time error to try and set the key `Kye`.

I agree with the compile-time error checking part, but it's possible to have groups of key/value pairs (i.e. anonymous records) in a statically typed language where only specific keys are allowed, with specific value types for each key.
(comment deleted)
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
You should categorically not be implementing chaining semantics unless your operations are non-mutating.

If they are mutating and you return the same object, it's possible for people to go years without realizing that's what's happening (no, most people don't read the manual), assigning the result to something else, reusing the original for another thing and introducing subtle bugs all over the place.

See the design of python's list `.sort()` returning None for this exact reason.

(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)

Or at least adopt a semantic preference that informs the user as to what is happening, e.g. Python has .sorted() for for non-mutating method vs .sort() for mutating method.
`sorted()` is a builtin function, not a method. It can still be confusing, but it's more clear IMO that `sorted(array)` will not mutate vs a hypothetical `array.sorted()`.
This is why I hate JS Array#sort. Its return type being an array gives the impression it’s not sorting the original array, leading to a lot of hard to track down bugs.

It’s also one of the biggest reasons I discourage use of lodash. Sure, most of its methods are pure and return new values. But some do mutate the input, and they’re interchainable (sorry, couldn’t resist). The only way to know which you’re using is to memorize or constantly consult their enormous API.

In c++ you can make your mutating chaining operations rvalue qualified, have them return by value and move this into the result. So you have purely functional operations that still don't create copies in practice.
Builder pattern for complex initialization like db connections
Return a new builder that has the changes applied.
> You should categorically not be implementing chaining semantics unless your operations are non-mutating.

What if it's a method of the data object?

data should not have methods, but that's a whole other religeous war :)
> What if it's a method of the data object?

Then it should either mutate the object in-place without chaining, or return a new data object with the updated value and leave the original unmodified.

This is something Rust is well-suited for (and it's a popular pattern in the Rust community as a result)

Rust can a) enforce that a method is non-mutating on its object, and b) use move-semantics to return a "new" value without doing an actual clone, while preventing the "old" value from being reused elsewhere. So the immutable "builder" pattern works very smoothly and safely

I like function chaining more. E.g. Elixir's `Map.set(map, field, value)` function combined with the `|>` operator, which feeds the value from the previous operation in to the function as the first argument:

    person_map
    |> Map.set(:name, "Peter")
    |> Map.set(:age, 37)
    |> Map.set(:married, true)
It'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't it nice, huh?
>It'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.

Yeah, that’s usually a bad sign. Programmers who think some language features are “fun” usually end up overapplying them and making life harder for everyone who just want to do their job and ship stuff.

Programming languages should be simple, boring and self-evident.

Keep “fun” in your hobby projects.

You do you. Software development is a large enough field, our paths don't have to cross.
In his case, I'm glad they probably never will.
Elixir (really, Erlang) has tightly-constrained semantics around immutability and exception handling that make this feature a natural application of the core concepts.
i'm confused, are you responding to their example or to their vibe?
I wouldn't touch software development with a ten foot pole if it wasn't fun. It's fine to enforce a code style in your own projects, but proselytizing them truth from on high is a bit presumptuous.
Yeah, how about no?

Mutating methods should return void, period.

The "Galaxy Brain" version of this advice is using plain old designated initialization of 'option bag' data structures. Here's a non-trivial C99 example from the sokol_gfx.h API to create a pipeline-state-object for 3D rendering:

    state.pip = sg_make_pipeline(&(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 = "cube-pipeline"
    });
Chaining might be useful for data processing pipelines, but not for simple data initialization tasks IMHO.
I know C is an extremely deep language but that doesn’t look like C99 to me. Since when can you set struct member variables piecewise in a…function definition?

Is this maybe a custom compiler? Or is this actually C++?

What you're seeing is a compound literal with designated initializers. Both features were introduced in C99.
I encountered code like this in a C99 project recently. I still don't understand it, but I believe it's supposed to be possible.
It's a C99 compound literal with designated initializer. C++ doesn't support it.
As other commenters have pointed out, those are designated initializers[1], one of my favorite C99 feature.

I's also been picked up recently for inclusion into C++20[2].

However, it seems that C++ adds a specific limitation:

> all designators used in the expression must appear in the same order as the data members of T

> out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++

Which limits the usefulness, as I've used this syntax to let myself reorder struct fields (and add some) without breaking the API (while obviously breaking the ABI). It's a great tool to use while your API is still in flux.

At least an error will be produced, which is much better than just providing values and hoping that the API/ABI remains stable.

[1]: https://en.cppreference.com/w/c/language/struct_initializati...

[2]: https://en.cppreference.com/w/cpp/language/aggregate_initial...

Designated initializers is the most amazing feature of the C language. I don't understand why no other language ever copied it...
Groovy has this ability I think if I can parse that code. My C code experience predates C99
Didn't Swift adopt something similar? (I'm no Swift dev so I'm not sure)
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.

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.

There's competing incentives for API ergonimics and making mutations / ownership explicit. Kotlin's scope functions really get you the best of both worlds with this.

Lambdas can have a "receiver", which acts as the (implicit or explicit) `this` for the lambda.

`apply` even returns the object itself, so the first example could be:

    frame.add(FormPanel().apply {
        setSize(300, 150)
        add(usernameLabel)
        add(usernameField)
        add(passwordLabel)
        add(passwordField)
    })
I work in C# but have come to a similar conclusion to his note at the top of his article.

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.

I’m the end, most of the time I found I was wanting a function ‘forward composition’ operator (like F#’s |> ). And the only place the chaining methods really made sense was factory classes/methods for complex declarative configuration.

The only ones that stuck for us were ORM mapping declarations, and factories for setting up complex domain specific data setup in tests.

For C#, the only method chaining we really do today would be for LINQ (very heavy usage) and AspNetCore startup logic.

If you are super addicted to certain language sugar like object initializers, then wrapping some of your business logic (e.g. mappers) with extension methods is not a terrible path. E.g.:

  public Thing MyFavoriteThing => new Thing
  {
    Id = Guid.NewGuid(),
    TheThing = _someLocalProperty.SomeTransform().Trim(),
    MyOtherInitalizedFact = true
  };
The alternative would look something like:

  public Thing MyFavoriteThing()
  {
    var result = new Thing
    {
      Id = Guid.NewGuid(),
      TheThing = SomeTransform(_someLocalProperty),
      MyOtherInitializedFact = true
    };
    
    result.TheThing = Trim(theThing);
    return result;
  }
You could also make a single-letter alias:

    auto& r = rectangle;
    r.width(100);
    r.height(100);
I like to use very short variable names(single or 3 letters at most) but fully write out the type:

    Rectangle r;
Which is similar in spirit to aliasing the variable.

"Rectangle" is probably not a good example, because rectangles are pure data used for many different purposes. So "rectangle" is often a poor variable name. But many programs use 1 type for 1 purpose, and then the type alone is enough.

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.

I don'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's not obvious, it can as well return another object, or a copy of that object). It's more explicit doing it the normal way.

My functional API's never return void because they're functions and immutability is the benefit there. Returning void means you're either mutating something or interacting with something thing that does. Also, chaining can be dangerous, as if it'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.

But in an OO project, void is a really useful. If you'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't going to benefit anything. You click a button, the gun fires. I don't need to check the return, it add no value, adds complexity and isn't idiomatic to the language.

Use the right tool for the job.

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't have sufficient mutable state to make this kind of thing worth it.

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.

(comment deleted)