15

Say I have a class with some properties and some methods for manipulating those properties:

public class PersonModel
{
    public string Name { get; set; }
    public string PrimaryPhoneNumber { get; set; }

    public void LoadAccountInfo(AccountInfo accountInfo)
    {
        this.Name = accountInfo.Name;
    }

    public void LoadPhoneInfo(PhoneInfo phoneInfo)
    {
        this.PrimaryPhoneNumber = phoneInfo.PhoneNumber;
    }
}

Typical usage would be:

var model = new PersonModel();
model.LoadAccountInfo(accountInfo);
model.LoadPhoneInfo(phoneInfo);

I think it would be cool to make the methods chainable:

    public PersonModel LoadAccountInfo(AccountInfo accountInfo)
    {
        this.Name = accountInfo.Name;
        return this;
    }

    public PersonModel LoadPhoneInfo(PhoneInfo phoneInfo)
    {
        this.PrimaryPhoneNumber = phoneInfo.PhoneNumber;
        return this;
    }

Then usage would be:

var model = new PersonModel()
    .LoadAccountInfo(accountInfo)
    .LoadPhoneInfo(phoneInfo);

But I am not returning a modified "clone" of the passed-in PersonModel object in each of these chainable methods. They are just modifying the original object and returning it (for convenience). To me, this creates an ambiguity because someone calling these methods may assume that they are immutable (i.e. they leave the original object intact but return a modified object).

Does that violate any sort of best practice regarding fluent/chainable interfaces?

dreftymac
  • 31,404
  • 26
  • 119
  • 182

5 Answers5

4

Personally I think that immutability and fluent interfaces are separate concerns. It may be that you find immutability in general to be a good thing, a best practice. But this would be whether or not you used a fluent interface.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
4

No, it's perfectly reasonable to mutate the passed object. Fluent NHibernate methods all work that way, (when they modify the FluentConfiguration object, for example).

But it's not a rule either. String is the best example of an immutable object where you can chain a bunch of methods, each of them returning a new instance.

vgru
  • 49,838
  • 16
  • 120
  • 201
  • 1
    +1 for showing an example of doing it both ways. Immutable objects produce less side effects. Mutable objects are more commonplace so might be better understood. – Brian Genisio Jul 15 '11 at 10:01
  • 1
    Right. Another good example where immutable objects are featured in a fluent interface is Java's Joda Time. Both ways work. – Ray Toal Jul 15 '11 at 13:51
1

This article suggests that the objects should be immutable. It comes from a functional language perspective.

http://blogs.msdn.com/b/laurionb/archive/2009/02/16/immutable-objects-in-fluent-interfaces-a-lesson-from-functional-programming.aspx

However, looking at Moq as an example, the objects are not immutable.

I don't think that there is a "best practice" here. As @Ray Toal said, they are separate concerns.

Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
  • +1 for the article. I think Ray summed up the answer though, thanks! –  Jul 16 '11 at 06:28
0

Objects are reference type and when you're specifically asking it to "return this" why would you expect it to return something different.

Doesn't violate any best practice. In fact unless you have a reason there is no need to clone an object.

saj
  • 4,626
  • 2
  • 26
  • 25
  • 1
    I don't understand what you are suggesting. Immutable types is ver common. For instance, String is immutable. Calling `" foo ".Trim().Substring(1)` is implemente as immutable. Choosing to do it this way has more to do with the way you want to build your data objects. From a functional perspective, there is a lot of value in doing something like this. – Brian Genisio Jul 15 '11 at 10:00
  • I'm not denying the benifts of immutability, my point is merely that there is no need to implement it without need. The reason that someone may assume an object as "immutable" doesn't seem to be reason enough. – saj Jul 15 '11 at 10:07
0

All the charm of the fluent method consists in returning the same modified object.

Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
  • 1
    I'm not sure why "all the charm" relies on it being the same object. Although I don't think object need to be immutable, I don't see how the charm of a fluent interface has anything to do with the mutability of the object being chained. All the charm, in my opinion, is that the interface is extremely readable. – Brian Genisio Jul 15 '11 at 09:56
  • @Brian, I mean that it is obvious/natural for user of fluent class to obtain the same object, not copy, IMHO. – Kirill Polishchuk Jul 15 '11 at 10:08
  • 1
    LINQ which is probably the most commonly use fluent interface returns out a new object. I think the charm is in returning the same type of object. – JamesF May 30 '14 at 22:49
  • 1
    I agree with @JamesF. All LINQ extension methods create a new instance with the change applied, thus the state is always immutable. Yet, LINQ is a great example of a beautiful fluent interface. – Matias Cicero Oct 16 '16 at 06:14