You can do bad stuff with any coding paradigm. That isn't a flaw of the paradigm.
I didn't say anything about any paradigm.
Maybe the wrong term to describe it: the concept and application of outlining some code into their own procs. Whatever you want to call it. Because that "concept" (and I use that word only because I need some word to name it) is my answer to what limits the amount of lines.
"Limits" not by applying a limit, but by site effect of doing the outlining, less function have greater amount of lines in them.
And, in case you say some are more likely to be gotten wrong. Well, some may require more study how to do them. Doesn't make the paradigm less good. It may even be better. (just not for someone who does their first hello world with it).
How about we don't bring paradigms into the subject of how many lines are too many in a function/procedure and since you brought the paradigm thing into the subject, I'll now add... method. That way, it's clear that the discussion is fully paradigm independent as it includes them all equally.
The first reads a bit like a "trick question"...
No. No trick question.
1. What's easier ? a) to read 1000 lines of code in a single block or b) read 20 out of line functions/procedures that implement that one "macro" function ?
The answer is definitely "b".
Reading 1000 lines in a single block is absolut hell.
Even the regex function (not mine, just did some contribution at some point) is such that I don't need to ever read 1000 lines in a go. Each case is stand alone, and code in the case section next to it has nothing to do with it, but is entirely unrelated code.
2. Isn't the fact that the programmer's attention has to jump 20 times (or at least to 20 different places) to the "sub-functions" a form of spaghetti code ?
No, it is not.
https://en.wikipedia.org/wiki/Spaghetti_codePlease answer the questions individually with specifics to provide a solid foundation for your answers.
As for the first question: I can only tell you what my experience is. And I can tell you that lots of code in the wild that I have come across at least to some noticeable degree seems to follow the described goal. But that is arbitrary, as its just the code I came across.
As for 2, since you allege the "spaghetti", why don't you do the work of finding a solid foundation.
My browsers SEARCH did not find a reference to subroutines on Wikipedia. First criteria there is "contral flow" (aka condition/loops) => they don't change by outlining into a proc. Well if anything they get less a problem, because the end of the function provides a tighter boundary for conditional/loop jumps.
2nd on wikipedia is "absence of structure" but procedures are providing structure by defining bounds for the contained functionality.
So according to wikipedia, using outlining into procs
has at least 2 points that reduce spaghettiyou didn't answer them because no matter how well named a function or procedure may be, it doesn't tell you anything about how it is implemented which is just as important to know as how the function that _uses them_ is implemented.
...
Yes, I do. Eventually I will read the code to ensure the method/function/procedure does what its name says and not only that, I'll read it to find out _how_ it does it because that can also be extremely important.
...
That means that if you have 20 such functions, now the programmer - presuming a responsible programmer that gets acquainted with the code he/she is maintaining - has to jump back and forth among 20 pieces of code to assemble all this stuff in order to figure out how the whole hangs together.
So you have read
every function in the RTL, LCL, components that you ever used?
Did you ever use any close source environment, where you could not check the RTL by yourself, but had to trust it does what it says?
But anyway, then yes, for you this will pose a problem. I can say (and again arbitrary selection) you are the first programmer that I met who does this.
Btw, what is your opinion on the implementation of "writeln"? SCNR.But back to serious, even if... E.g. if I had to judge some code for a company that wanted my to certify it for their use. I would rather read 20 small routines, than 1 large.
I could make my notes on each of them, and be done with each of them.
Of course, I am talking about a scenario were they have been properly chosen. Where they don't have unpredictable side effects. So that once I did read them, and put them an me "ok list", I do not need to read them again.
If there are all in one large block, then when I read any of those blocks (assuming that it is well marked as a block) I still have to check that it doesn't expect any side effect in any of the local vars that it uses (because the locals are all in one scope). With outlined routines, each has its own locals, that alone can reduce the work I have. And reduce it by way more than the few codetool jumps that I have to do.
Mind you that, if (what should not happen in first) I need to see other code, then I have the same problem in case of a single large function. The other code will most likely not fit into the editor window. Though in both cases I can solve that by opening several windows. But point is, a single large block of code would not help with this at all. (not for me)
And, well, if there is a bug somewhere, and I don't know in which routine? (Ignoring test cases, and test-ability improvements by having some code extracted), I can on the first run step over each function and check the result, until I find the routine that returns wrong.
You are thereby acknowledging that your attention has to jump around looking for the bug. Wouldn't it be a lot easier if the code was simply linear and your attention didn't have to jump around ?
No, there is no attention jumping. In fact there is less attention needed.
I can narrow down on the location of the bug by stepping over all the outlined code, and find the one that returns wrong. That is less work, than continuously looking for the end of the next logical block, and have the debugger run to that end....
And way less than stepping over every statement individually (unless I get lucky and the bug is right at the top).
And once I have to step in (into one single method) both debugger and codetools do the work for me. Since at this point I verified that the params passed in a correct, any code before does not matter when I debug the called function.
But in a rare case were the bug is an interaction (e.g. a dangling pointer in one place causes cross function side effects), then I need 2 editors to see both function.
Only, if all was in a single large block, the chances that the other part was scrolled out are reasonably high. So I need the same 2 editors too.
So far having the separate function has always paid out for me.
Not to mention that you wouldn't have to wonder if that piece of code is used in more than one place (which is very important to know when you're maintaining code.)
In case it was scoped for global access.... Which would mean the outlining was done badly. Not a fault of outlining, a fault of whoever did this particular case.
Otherwise, with a smaller scope, the IDE has plenty of tools to tell me in a few seconds. Yes, it will take a few seconds. Those I can take out of the thousands of seconds that I have saved by outlining.
Sorry, but I have to say, this above quote of yours looks like you a constructing cases where someone has done "not what I advertised", but a completely wrong way of outlining. So that what you describe is a problem that doesn't exist (in what I advertised).
Otherwise lets take single large block and find ways for someone to write them in the worst possible way....
Again, all I have is my experience with this.
O well, and from several decades ago, when I was a newby, the (bad) experience of not doing this.
So, having stuff in functions is much easier to handle.
That's a nice claim but where is the support for it ?
Well I haven't seen any evidence that "single large" is better. Only your word. So at this point I can only say for you (and potentially only you, and a few people you know (may be hundreds, still few)) this is the perceived case... And that even assumes that you tried otherwise.
I have (involuntary) tried otherwise (your single large way), when I was a beginner.
why should the statements be outside the context that uses it (the main/macro function) ? after all, if the function is 30 statements, the statements could simply be prefaced with a comment stating "the following sort - whatever it is that it sorts - by - whatever key it uses" instead of being "somewhere" and the programmer wouldn't have to search the source code nor wonder if that code is also used someplace else. Those are two very specific reasons for the code NOT to be in a separate function. The fact that the statements fulfill a subtask/subfunction can simply be noted with a comment.
I did several comment about commenting blocks. In this and in my previous post. Simply not the same.
Skipping several repeats on spaghetti and comments.
And in case of 1, its just a what it is, if the reader thinks its called from other places too, then there is no harm at all. None, nada, zero.
Not true at all. The maintainer bears the burden of having to determine that the code is not executed by any other code to ensure any changes to it do not affect any other part of the program. If the code was not in a separate function/procedure/method, the programmer would automatically know that code isn't executed anyplace else because it is NOT in a function/procedure/method that can be executed by another caller.
I will make a categorical statement: no code should be in a named function/procedure/method UNLESS it is executed by more than one caller. if there is only ONE caller then that code should have been inline.
So you copy/paste any code from components, if you call it from only one place?
Changing code is usually less frequent than reading it. That follows that before a change, one would usually read it.
As I wrote above, the check were it is called takes but a few seconds. Of which plenty have been saved by having it outlined. (Again, I can only tell what it does for me, and those I know)
The majority of programmers (myself included) often create a function or procedure simply to assign a name which exposes the logical task performed by a group of statements. THAT is a very unfortunate habit that is inherently incorrect.
I seem to recall that you earlier stated such a function would be a total surprise for the reader. Now you state the
majority create them themself?
For reference, point 3:
https://forum.lazarus.freepascal.org/index.php/topic,73608.msg577862.html#msg577862How does having to read copious amount of extra lines every time you need the bigger picture solve that. Keeping the code inlined just increases the likelihood to overlook parts of it.
They are not extra lines, they are the statements that implement the function and they are less "copious" if they are kept in one place than broken into a bunch of subtasks.
Parsing a text into tokens by some rule, and then sorting those tokens => that are 2 functions. I will not put them into a single function.
When I have to read one of them, I see no need to have the other presence and wonder if it has any reason to be there.
If you want to put the together suit yourself.
Again, I can only give you my opinion. There may be more info on it (I am certain there is, I am certain to have read it in the past), but
I don't want to spent time on searching it. You want to know, you can do the work (sorry)
Also again, they should be appropriately named. They should just do one thing and that is in the name and hence no way to forget it.
I agree with that. It's nice to have the jigsaw puzzle piece reasonably well named, that hopefully saves a little time and lessens the headache of putting the pieces together.
Another question...
What do you think gave someone the idea of creating inline/anonymous functions/procedures ? Why would anyone come up with those ? What problem(s) do they solve ?
Indeed other question. I don't actually like them much in Pascal. There is some point for "closures" but they could have been done without anonymous.
The same goes for: I prefer "s:= inttostr(1);" and not "s:= 1.toStr;" or similar.
There are languages that are differently designed, and in which method chainging is great. It isn't in Pascal. Languages come with a style. Keeping to that keeps the readable between different users. Copying styles from elsewhere.... But very off topic now.