4 ms·
no more than 3 arguments for your functions It is hard for me to believe that this is a piece of style advice that anyone writing serious software would follow
by jblow 10y ago
no more than 3 arguments for your functions
It is hard for me to believe that this is a piece of style advice that anyone writing serious software would follow.
If you need to do something wherein the basic task requires 8 arguments' worth of information (which happens A LOT) then trying to factor that into 3-argument pieces is going to give you something Byzantine that is probably also buggy (and it could get extremely heinous, in a way determined by the data dependencies internal to the procedure you are factoring). And if you somehow succeed at all this, congratulations, you just did a bunch of engineering that did not improve the functionality of your software in any way. (In fact it probably made the software take longer to compile).
If doing a certain job needs 8 pieces of information, it needs 8 pieces of information. It doesn't help anyone to try to break that up.
Similarly with this:
keep the complexity of the functions as low as possible
Not really. If you are just factoring some block of complexity in to 4 blocks of less-complexity, well, now you have the same amount of complexity as the original code, plus the complexity of the call graph, and the fact that the person who comes along to read the code will not be able to clearly see the control flow.
There definitely are many cases when factoring a procedure into simpler things is beneficial. But to claim that it's a good idea all the time, or even half the time, is I think mistaken.
- fazzone 10y agoA guideline like "three arguments to a function" says nothing about the type of those three arguments. You are right that there are many jobs that require 8 or more pieces of information, but often those parameters can be grouped into structures which each hold multiple pieces of information. The point is not to create types for every function just to hold their arguments, but that well-thought-out data abstraction can simplify things by factoring data into named structures that are used in multiple functions. For example you could have a drawRectangle function which takes four parameters (x1, y1, x2, y2) of some primitive numeric type, or you could create a Point type and use just two of those. This improves clarity because it is obvious just from the signature of drawRectangle(Point a, Point b) that you are specifying the endpoints of the rectangle, whereas four numeric arguments could mean (x1, y1, x2, y2) or (x, y, width, height).
- jblow 10y ago(a) This kind of thing in many cases is just tedious busywork that you are now making someone do every time they call the routine. What if they have a MyPoint and your procedure takes a YourPoint? And what if your point is 8-dimensional, anyway, what does that constructor look like? (b) This has performance implications, not least because of the ABI. And depending on what language you are using, they can be quite severe (good luck if you are using one of those languages that always puts classes on the heap).
- lmm 10y ago> What if they have a MyPoint and your procedure takes a YourPoint? Then you get early warning that you need to be paying attention, rather than silently corrupting your data by swapping some coordinates around. > And what if your point is 8-dimensional, anyway, what does that constructor look like? You don't want an 8-dimensional point literal that takes 8 arguments directly, that's never going to be readable. You might want to use a builder. More likely you want to load it from a data file or something on those lines rather than constructing it directly. Where are you even getting these 8-dimensional points from? > This has performance implications, not least because of the ABI. And depending on what language you are using, they can be quite severe (good luck if you are using one of those languages that always puts classes on the heap). In Haskell (or indeed in C) it doesn't necessarily have performance implications; an 8-element structure may have exactly the same runtime representation as those 8 elements being passed distinctly. (In my experience performance concerns are always overblown in any case. If you have actual performance constraints then profile; if you don't, don't worry about it. Too often performance is used as an excuse)
- jblow 10y agoThen you get early warning that you need to be paying attention, rather than silently corrupting your data by swapping some coordinates around. No, a real-world case is that I have a giant program that uses my own geometric primitives, and now I want to start heavily using a library. I know they are just fricking 3D points or quaternions or whatever. Yet because of some weird ideology you want to increase the amount of gruntwork I have to do, and make my life much less pleasant. You don't want an 8-dimensional point literal that takes 8 arguments directly, that's never going to be readable. You might want to use a builder. More likely you want to load it from a data file or something on those lines rather than constructing it directly. Where are you even getting these 8-dimensional points from? WHAT ARE YOU TALKING ABOUT In Haskell (or indeed in C) it doesn't necessarily have performance implications; an 8-element structure may have exactly the same runtime representation as those 8 elements being passed distinctly. Wow, okay, this conversation is over.