Coding style for chained function calls

A common thing you need to do is to take a value, do something with it by passing it to a function, and then do some more with the return value, in a chain. Whenever I run into this type of scenario, I get unsure about how best to write the code.

As an example, let’s say I have a number, num, and need to take the floored square root of it and turn it into a string. Here are a few possibilities (in JavaScript).

I might simply pass num to one function at a time, and replace num with the return value:

function floorSqrt(num) {
    num = Math.sqrt(num);
    num = Math.floor(num);
    num = String(num);
    return num;
}

This is nice since I don’t need the original num any more, but in practice it might be confusing to start with one thing (a number) and end up with something completely different (a string).

I can save each step in a new variable:

function floorSqrt(num) {
    var sqrtNum = Math.sqrt(num);
    var floorSqrt = Math.floor(sqrtNum);
    var stringNum = String(floorSqrt);
    return stringNum;
}

Although it seems wasteful to declare all those variables and come up with good names for them.

Or I can just do it all as a one-liner:

function floorSqrt(num) {
    return String(Math.floor(Math.sqrt(num)));
}

But for more than two functions that approach gets incredibly unreadable, almost like code golf.

It seems to me like the most beautiful way to do this would be with some stack-based language, which might look something like this (pseudo code):

[sqrt floor toString]

Is there a way to do something similar with JavaScript? List some functions, run one at a time, and use the return value of each one as the argument for the next? The closest is how some libraries like jQuery or Underscore.js allow you to chain methods, something like this:

function floorSqrt(num) {
    return _.chain(num).sqrt().floor().toString().value();
}

I’m sure many wise people have thought wise things about this. What are some thoughts on pros and cons of the different styles?

2

TL;DR: The Reduce/Compose Functional Programming Idiom

# define/import: compose(fn1, f2)(arg) => fn2(fn1(arg)) 
# define/import: reduce(fn, [l1, l2, l3, ...]) => fn(fn(l1, l2), l3)...

commands = [Math.sqrt, Math.floor, String]
floorSqrt = reduce(compose, commands)

# floorSqrt(2) == String(Math.floor(Math.sqrt(2)))

Notes:

  • compose from Eloquent Javascript
  • reduce requires a 2 argument definition

Using reduce and compose is a very common idiom used when you want to setup a pipeline of transformations for data to go through. It’s both readable and elegant.

<rant>
There are too many programmers who conflate readability with familiarity and vice versa. They believe an unfamiliar idiom is unreadable, like the reduce/compose idiom only because it is unfamiliar. To me this behavior is more aligned with a diletante, not someone who is serious about their craft. </rant>

4

Our goal as software engineers, should be writing code that is clear and understandable for other humans, and I’m glad you’ve already realized that writing too many nested function calls you end up with code that is hard to read.

So assuming your language doesn’t support jQuery-like syntax you mentioned at the end, seems the only good alternative you have left is to break up complex chain of function calls into simpler statements where each assigns a temporary value to an intermediary variable. So now you are left with only two choices: 1) reuse same variable name for each step and 2) define a new local variable for each step.

And assuming you’ve arrived at the same conclusion as me, I’ll help you make the final choice: Use new variable names for each step

The argument “it is wasteful to declare 5 variables when I can use one” is a bit of premature optimization. I’ve had embedded guys join my team and this was one of their habit that I would always have to break. Each variable should have a) meaningful name and b) always the same meaning. Then when one reads through the code he never has to guess what “num” means especially since code tends to not stay as simple as your example. Imagine someone else comes long, adds a few loops and if-statements and keeps reusing your “num” variable. Now to understand what’s in it, you would have to trace back and perform mental gymnastics in trying to determine just which statement was hit and how many times was “num” reassigned.

Assuming you are not doing embedded programming on a some board with 8 KB of RAM, there’s no reason to reuse the same variable multiple times for multiple purposes. Come up with good, clear names and use them. When the stack unrolls, it costs exactly same amount to remove 1 int from stack as it takes to remove 6 ints.

9

If you are not restricted to Javascript, many functional programming languages allow you to use an approach similar to that suggested by dietbuddha (function composition operator). I will illustrate this using Haskell.

Your solution with intermediate variables would go like this:

floorSqrt :: Float -> String
floorSqrt num = let
                  sqrtNum   = sqrt num
                  floorSqrt = floor sqrtNum
                  stringNum = show floorSqrt
                in
                  stringNum

The one-liner would be

floorSqrt num = show (floor (sqrt num))

or also

floorSqrt num = (show . floor . sqrt) num

or

floorSqrt = show . floor . sqrt

i.e. you can compose the three functions using the . operator and apply the resulting function to the argument num. By using a composite function you can leave out the argument num from the definition, as illustrated in the last example above.

In general, if you have a sequence of functions

f1, ..., fn

where, for i ∈ {1, …, n} : fi : ai -> bi, and for i ∈ {1, …, n – 1} : bi = ai + 1, you can define the composite function

compositeFunction = fn .   . f1

If all the functions you want to compose have the same type a -> a, you can apply the foldr function to the list of functions you want to compose. For example, imagine you have the function

floorSqrt :: Float -> Float
floorSqrt = (fromIntegral . floor) . sqrt

(note that we have to insert fromIntegral because floor does not return a Float). This can be written as

floorSqrt = foldr (.) id [fromIntegral . floor, sqrt]

where foldr corresponds to reduce in dietbuddha’s answer, and . to compose. The id function (identity) is needed as a starting point for the folding / reduction (I suppose this is implicit in the JavaScript example).

You can use the above pattern for any sequence of functions f1, ..., fn where, for i ∈ {1, …, n}, fi : a -> a:

compositeFunction = foldr (.) id [fn, ..., f1]

In Haskell, you cannot use this last pattern for your original example because foldr requires all functions in the list to have the same type. You can use it in JavaScript because it does not have this restriction (see dietbuddha’s answer).

I would not nest too many methods when using the standard math and string methods, for example, in Javascript. But there are libraries which have a so-called fluent interface, these kind of API’s are especially made for making readable code by method chaining. You will find tons of articles when you google for those keywords.

Languages such as you describe exist, the most popular (popular being a relative term) is FORTH

Your example would look something like this in FORTH:

: floorSQRT  ( NUM -- NUM )
    Sqrt
    Floor
    ToString ;

(Though FORTH is extremely low level, and so doesn’t really have a string type the way we think of it now.)

If you really wanted to do something like this in JavaScript, you could, by creating your own versions of these methods that took an array as the first parameter, something like:

function Sqrt(stack) { stack.push(Math.sqrt(stack.pop())) };
function Floor(stack) { stack.push(Math.floor(stack.pop())) };
function MakeString(stack) { stack.push(String(stack.pop())) };

function floorSqrt(stack) {
    Sqrt(stack);
    Math.floor(stack);
    MakeString(stack);
}

stack.push(num);
floorSqrt(stack);
num = stack.pop();

This would work, but it would be massively confusing to most JavaScript programmers, so don’t ever do it.

Having worked with FORTH back in the day, the idea of a stack based language is very appealing, but in practice, for any reasonable sized piece of code, it quickly becomes confusing. Because everything is implicit, it’s hard to remember what each method is going to actually operate on. Much more confusing than your original code, actually. Honestly, if I were writing this code, and wanted it to be clear, it’d look like this:

function floorSqrt(num) {
    num = Math.sqrt(num);
    num = Math.floor(num);

    return String(num);
}

I don’t really find that confusing at all. It’s very clear.

If you really want to do chaining, you could try to make it clearer like this:

function floorSqrt(num) {
    return String(
               Math.floor(
                   Math.sqrt(num)
           ));
}

But again, I don’t think that’s really necessary. I think the original is perfectly fine and straightforward.

As Doc Brown says, this is a fluent interface, and is easily achievable in javascript, to use your example:

Number.prototype.sqrt=function(){return Math.sqrt(this);};
Number.prototype.floor=function(){return Math.floor(this);};
String.prototype.alert=function(){alert(this);return this;}

(5).sqrt().floor().toString().alert();  //alerts "2"

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật