5 ms·
I share your sentiment. Some of the programmers I’ve worked with would build functions for every thing within a larger function. Need to chunk the data? Functi
by bransonf 7y ago
I share your sentiment. Some of the programmers I’ve worked with would build functions for every thing within a larger function.
Need to chunk the data? Function.
API Call? Function.
Parse the response? Function.
So I asked: “Are you ever going to use these internal functions for anything outside of this function?” And their response was: “No, but it makes debugging easier.”
It does not. It makes it exponentially more difficult. Maybe I just work with too many terrible programmers...
- enriquto 7y agoI have the opposite philosophy. The ideal function is only called once. If it is called more than once, I have a "call diamond" instead of a "tree" and this is a code smell.
- raxxorrax 7y agoHarsh constraint. Probably difficult to come up with new sorting algorithms or substitutes for basic arithmetic functions after a while.
- enriquto 7y agoI mean for functions that are called in the same context. Obviously external and well-abstracted functions can be called several times.
- Nition 7y agoOne middleground option if you have a long function but also want to break it into chucks for easy readability: In C# and some other languages you can put braces around a block of code without actually having any condition on it. Or just throw some big comment headers in.
- skohan 7y agoIn Swift I use locally-scoped functions for this. It has the advantage of ensuring that this single-use function can't be called from outside the intended scope, but I can still chunk the work into easy-to-reason-about pieces.
- Nition 7y agoC# has those now also: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/local-functions https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...
- aptwebapps 7y agoVS Code has regions, which look like preprocessor instructions but I don't think they actually have any affect on the code. They do, however collapse while providing a nice label.
- scns 7y agoJetbrains IDEs have those too
- aptwebapps 7y agoThanks, I've been using PyCharm for years and didn't know that.
- pubby 7y agoWoah, bransonf? I met you at OpenSTL a few weeks ago! What a funny coincidence. And yeah, I agree. Even Carmack had something to say on this: http://number-none.com/blow/john_carmack_on_inlined_code.html http://number-none.com/blow/john_carmack_on_inlined_code.htm...
- rustybolt 7y agoDepends. In complicated code with lots of dependencies, I've always found it easier to understand functions that are written as: function do_task(a, b, c) { d = subtask1(a, b); e = subtask2(b, c, d); f = subtask3(a, d); } instead of one long function. Of course, this only makes sense if the subtasks are indeed different conceptual steps in the computation. As an example, I remember writing finite elements code that was structured something like this: function solve_fem_problem(problem_description) { basis_functions = generate_basisfunctions(basisfunctions_type.b_spline); quadrature_rule = generate_quadrature(quadrature_type.gaussian_quadrature); A = assemble_matrix(problem_description.differential_equation, basis_functions, quadrature_rule); b = assemble_righthandside(problem_description.differential_equation, basis_functions, quadrature_rule); apply_boundary_conditions(problem_description.boundary_conditions, A, b); solution = linsolve(A, b); } which I think is very pleasing to read, and preferable to a single huge function. This also makes it easy to use another linear solver, for example. On the other hand, the functions that are called inside solve_fem_problem are probably larger. Note: During work, I haven't actually encountered a lot of code that is structured in this way.
- Symbiote 7y agoI'm hijacking this since your function shows the kind of case where I like to make an exception to the line length rule. It looks much better, and is more understandable due to the repeating pattern, as you have it, but some people I've collaborated on open source code with would insist upon this: function solve_fem_problem(problem_description) { basis_functions = generate_basisfunctions(basisfunctions_type.b_spline); quadrature_rule = generate_quadrature(quadrature_type.gaussian_quadrature); A = assemble_matrix(problem_description.differential_equation, basis_functions, quadrature_rule); b = assemble_righthandside(problem_description.differential_equation, basis_functions, quadrature_rule); apply_boundary_conditions(problem_description.boundary_conditions, A, b); solution = linsolve(A, b); } (For this example, I'm assuming an arbitrary maximum line length of between the A = and b = lines.)
- Jestar342 7y ago> It does not. It makes it exponentially more difficult. You should realise you are falling victim of your own assertions here. You're cargo-culting the idea that abstracting functions makes debugging exponentially more difficult, without having provided any substance to qualify.
- bransonf 7y agoThe assertion, which I believed was implied, is that the habit of creating many sub functions will make it more difficult to trace a bug. Imagine having a function with 5 sub functions, and since this is your style, those functions have 5 internal functions. If I want to trace an error, first I have to find it in the main function, then the sub function, and maybe even within its sub functions. Then I have to deal with several different scopes as well. I don’t mind this if a function is a useful abstraction, that is it does something well and is used repeatedly. My gripe is with functions that are written just for the sake of writing functions.
- Jestar342 7y ago> It does not. It makes it exponentially more difficult. is not implicit. That is very much an explicit assertion. I'm simply pointing out that in your pointing out of cargo-cult, you've done the exact same thing of drawing a conclusion with no basis. > Imagine having a function with 5 sub functions, and since this is your style, those functions have 5 internal functions. is unrealistic. There's plenty of room in between "no private functions at all" and "5^n functions for every layer". It's hyperbole and bordering rhetorical. As for tracing bugs in the way you mention - nobody in my sphere of influence has needed to do that in years, at least not on a regular basis. Tests demonstrating IPO are far more valuable and also far more quickly than tracing, narrow the scope of the problem to the point that you'll now be within one small function to read than a potentially much larger one.
- z3t4 7y agoWith risk of offending both sides of the argument, both long functions, and split functions are fine. Functions within functions are great for async code as you can make use of the closure/lexical scope. eg. When the network request come back you still have acces to variables declared in parent function. And you can also freeze state/value of variables in time - by making them into function parameters copied by value.