14

I recently suggested a method of chaining be implemented for a certain class in a certain project so readability of the code could be improved. I got a "fluent interfaces should not be implemented just for convenience, but for semantics" answer and had my suggestion shot down. I answered that I was not suggesting a fluent interface but method chaining itself (both can be confused with each other, read at bottom) to improve readability and coding comfort, suggestion was shot down again.

Anyhow, this got me thinking that maybe I could be incurring in a bad practice by always returning "this" in methods that are not supposed to return anything (e.g. setters).

My question is: can applying the previous convention be regarded as bad practice or abuse?, why?. I don't think there are any performance drawbacks, or are there?.

gnat
  • 20,543
  • 29
  • 115
  • 306
dukeofgaming
  • 14,023
  • 6
  • 52
  • 77

4 Answers4

10

No

As Kent Beck points out, code is read far more often than it is written.

If method chaining makes your code more readable, then use method chaining.

9

Yes, there are drawbacks

Code that is easy to read is good, but also beware of what the code communicates as well. When an object's methods always return the object, it communicates a couple of things:

  1. I require advanced configuration that isn't necessarily obvious in which order things should be set or configured
  2. Each subsequent method call builds on the last

Valid Use Case: Ad Hoc Database Queries

Class libraries exist in most every language that allow you to query a database without resorting to hard coded SQL. Take the Entity Framework for .NET as an example:

DBContext db = new DBContext();
List<Post> posts = db.Posts
    .Where(post => post.Title.Contains("Test"))
    .OrderBy(post => post.DateCreated)
    .ToList();

This is a fluent interface where each subsequent method call builds on the previous one. Reading these calls logically makes sense in the context of querying a database.

Invalid Use Case: Syntactical Sugar For Setting Properties

Now let's use the same pattern with the Post class:

public class Post
{
    public string Title { get; set; }
    public DateTime DateCreated { get; set; }
    public string Body { get; set; }

    public Post SetTitle(string title)
    {
        Title = title;

        return this;
    }

    public Post SetDateCreated(DateTime created)
    {
        DateCreated = created;

        return this;
    }

    public Post SetBody(string body)
    {
        Body = body;

        return this;
    }
}

Now let's look at how you would use this class:

Post post = new Post()
    .SetTitle("Test")
    .SetDateCreated(DateTime.Now)
    .SetBody("Just a test");

When I see this code, I immediately ask this question: "After calling SetBody, does it query the database? Do I need to call another method to say 'I'm done?'"

What do the chained method calls communicate to the code using the Post class?

  1. I have a complicated setup
  2. Each method call builds on the previous one

Is this actually true? No. The Post class does not have a complicated setup. Setting the title, date created and body do not build on each other towards a more complicated end goal. You've mashed a square peg into a round hole.

The drawback to self-referential method chaining is that you communicate that multiple method calls are required to do something, and that each call builds off the last. If this is not true, then method chaining could be communicating the wrong thing to other programmers.

When your coworkers said:

Fluent interfaces should not be implemented just for convenience, but for semantics

They were absolutely correct. A fluent interface, or method chaining, communicates something in and of itself which might not be true.

1

The main drawback is a loss of clarity. For instance:

x.foo();
x.bar();
x.baz();

Since none of those statements return a value (or if they do, it's been ignored), they can only be useful if they produce side effects. Contrast that to:

x.foo()
 .bar()
 .baz();

First, it's not clear that bar and baz operate on objects of the same type as x, unless you know for a fact that x's class is the only class with those methods. Even if that's the case, it's not clear the methods operate on x, or new objects.

Highlighting the parts of the code that have side effects is useful, since you need to track those side effects to reason about the program. You have to weigh the potential loss of clarity against the potential gain in ease of writing code, but also consider that code is read more than it's written.

Doval
  • 15,487
0

Consider all the stylistic elements of programming languages (as opposed to hand-coding machine language), and it weakens the "semantics not convenience" argument.

A whole lot of what we do as engineers is providing convenience around semantics.

sea-rob
  • 6,911