Fluent interface for object methods

G’day:
I was just messing around with the .addColumn() Query method, and came acropper when it didn’t return the actual query… which meant I could not chain multiple .addColumn() calls toegther.

.addColumn(), like it’s procedural equivalent, [queryAddColumn()][1], returns the number of columns in the query after the column is added. This might (?) be useful from the perspective of the procedural function, but I’m not sure mirroring this behaviour with the method version is the best approach?

CFML has a bunch of functions - generally query, array and struct ones - which don’t really return anything useful: a boolean flagging success (where failure is an exception), or stuff like the above: a mostly pointless number. For the object methods, I can’t help but think adopting a “fluid interface” might be a better way to go with these types of methods?

In short, a fluid interface is one in which a method will return the object it acted upon, if otherwise it’d not return anything useful. This allows for better method chaining.

I dunno if it’s too late for the CFML implementation to shift to this approach, or whether there’s a backwards compat concern in suddenly not returning a boolean or numeric? However perhaps for .lucee, taking the “fluid” approach might be better?

Thoughts?


Adam

that is already the case, but only for functions returning useless information, like for example querySetCell that only returns true in every case.
but the function addColumn does return valid information (column number added).

i have a lot of code that looks like this:

row=qry.addRow();
qry.setCell(...,row);

and I would miss a lot if this function no longer returns the row number added and if addRow returns the row number addColumn must return the column number.

To find out what function are supporting this way, look for <member-chaining> in this file
https://bitbucket.org/lucee/lucee/src/bbabcce83615456f9940c3998e8408e55aab3b4c/lucee-java/lucee-core/src/resource/fld/web-cfmfunctionlibrary_1_0?at=master#cl-136

All good re everything else, but…

That’s begging the question.

There is a good useful reason - as you explained - to return the rows number when adding a row. And we’ve all used that value in precisely the scenario you mention.

However the return value from adding a column isn’t a value I personally have ever needed or used. Have you? Whilst we do reference rows by row number, we do not reference columns by row number; we reference them by name. And we intrinsically already have the name in the situation we’re discussing.

I think you’re saying it “must” return the same sort of value because you’re deciding there’s a similarity between the two functions that just isn’t there.

But anyway, you’ve obviously considered it when you did the implementation and arrived and your conclusion in an informed (if, IMO, less than ideal) fashion. Fair enough.

Cheers for the explanation.


Adam

My opinion on this is not very strong, I see that my argument on this is weak, I simply want to bring it up. Maybe we should start an excel sheet wit all possible candidates and vote

+1 for maximising method chaining

1 Like

Yes, +1 for method chaining.

I was just playing with Rust last night and was very frustrated that Vec<T>::sort() does a sort in place and does not return a value. That means that to reorder a string into alphabetical order you need three lines of code: convert String to Vec<char>, sort the vector, convert the vector back to a String.