Tommi Prami 131 Posted May 16 (edited) Yellow, Could not think what else to call then as "Local Global variables" So let me show. function Foo(...) var LListOfVariables: TSomeType; procedure Bar1; begin // Complex proc that might or might not use variables defined above, and/or change them end; procedure Bar2; begin // Complex proc that might or might not use variables defined above, and/or change them end; ... begin // Func main body that might or might not call local procs end; For me this is very hard to wrap my brains around. For me this pattern requires lot of thinking and overloads my limited memory, to keep in mind that call to local procedure might touch the local variable, even it is not directly passed into them. I don't have anything against local methods, they wrap nicely some local need, that is specific for that parent method, and only for that. But fight are they good idea at first place, is another matter. -Tee- Edited May 16 by Tommi Prami Share this post Link to post
Der schöne Günther 316 Posted May 16 I think that is the whole point of these nested methods, that they can access all the local variables that were defined before them? I never use them. I have only seen them in some legacy code of ours, and in all cases it made a tangled mess of spaghetti even worse 🍝 I'm sure someone can find a valid use case, though. Share this post Link to post
dummzeuch 1517 Posted May 16 (edited) I use them sometimes as a convenient way not to pass too many parameters. As far as I remember this comes with a performance penalty though. I declare those shared variables at the top of the main procedure, above the nested procedures, and those that are not shared below the nested procedures. Edited May 16 by dummzeuch 5 Share this post Link to post
Lars Fosdal 1793 Posted May 16 I sometimes use these where a method has been broken into sub-routines to create more readable code, but more often than not, I tend to pass arguments to these sub-routines as parameters. 1 Share this post Link to post
Tommi Prami 131 Posted May 16 (edited) 1 hour ago, Der schöne Günther said: I think that is the whole point of these nested methods, that they can access all the local variables that were defined before them? I think that is not the point of nested methods. To me that that Nested methods see those variables is not the point of the nested methods, that is just as how they work. Like hammer is nice tool but don't hit random people in the head with it... 🙂 -tee- Edited May 16 by Tommi Prami Share this post Link to post
David Heffernan 2353 Posted May 16 26 minutes ago, dummzeuch said: I use them sometimes as a convenient way not to pass too many parameters. I always prefer to pass parameters because it makes it much clearer what the input/output of the function is. Usually the so called convenience you refer to just leads to obfuscation. Share this post Link to post
Vincent Parrett 763 Posted May 16 Not a fan of nested procedures/functions - but if I do use them I prefer to pass parameters - I prefer the narrowest scope possible on all variables/fields etc. 1 Share this post Link to post
Tommi Prami 131 Posted May 16 10 minutes ago, David Heffernan said: I always prefer to pass parameters because it makes it much clearer what the input/output of the function is. Usually the so called convenience you refer to just leads to obfuscation. I think this way too. My main reason is not that much of the how "clean/good" the code is in this case, but is mentally frustrating. Very difficult to keep track what happens and when... If code is cleaner and better, that is definitely a big bonus. -Tee- Share this post Link to post
Tommi Prami 131 Posted May 16 5 minutes ago, Vincent Parrett said: but if I do use them I prefer to pass parameters - I prefer the narrowest scope possible on all variables/fields etc. Nicely summed up... Share this post Link to post
Die Holländer 49 Posted May 16 Some times I use nested methods if I discover that in the main procedure a small function is needed and need to be called serveral times in that main procedure. When the function gets larger then I move the function to the main object in the private section and pass the parameters. The only sad thing that happens in the Delphi editor when using nested methods is that the auto complete, like automatic adding "end;" after typing Begin<enter> is not working anymore.. Share this post Link to post
DelphiUdIT 187 Posted May 16 I use nested methods when I have activities to carry out exclusively in that specific "section" of the program This also allows me to remind myself in the future that that type of operation only happens there. And the variables used are mostly just passed as parameters. Then it will be so simple and painless to eventually convert the nested method into a public/private method if needed. Share this post Link to post
Uwe Raabe 2064 Posted May 16 IMHO, having local procedures/functions using outer-scope local variables is often a hint for having a separate class for this functionality. I wish we were able to declare something like a local class type inside a method, just as we can declare a simple record type. In the moment I work around that limitation by nested classes unless I want it hidden from the interface, which forces me to make it a regular private class. 1 Share this post Link to post
dummzeuch 1517 Posted May 16 3 hours ago, David Heffernan said: I always prefer to pass parameters because it makes it much clearer what the input/output of the function is. Usually the so called convenience you refer to just leads to obfuscation. In my opinion using this kind of variables falls into the same class as using break and continue in a loop. A little bit better than goto, a little bit worse than using exit. I use it sparingly, but as I said: Sometimes it is just convenient. Share this post Link to post
PeterBelow 239 Posted May 16 5 hours ago, Tommi Prami said: For me this is very hard to wrap my brains around. -Tee- Nested procedures/functions are basically legacy from the times of Turbo Pascal, before we could write properly object-oriented code. They are still useful for procedural code, but if you organize your program's tasks into classes then you can replace nested procedures with private methods of the class and either pass needed values as parameters or move the local variables used as private fields to the class declaration. IMO that gives a much cleaner and easier to understand design, and it keeps down the size of the methods. 1 Share this post Link to post
dummzeuch 1517 Posted May 16 1 hour ago, PeterBelow said: if you organize your program's tasks into classes then you can replace nested procedures with private methods of the class and either pass needed values as parameters or move the local variables used as private fields to the class declaration. IMO that gives a much cleaner and easier to understand design, and it keeps down the size of the methods. Unless, of course you need a local type declaration that you don't want to be visible outside the unit. Such a type can be declared inside a procedure / method and used within that method and any nested procedure. To convert these nested procedures into methods, you will have to move the type declaration outside the main procedure/method. The same applies to constants. Share this post Link to post
David Heffernan 2353 Posted May 16 1 hour ago, dummzeuch said: In my opinion using this kind of variables falls into the same class as using break and continue in a loop. A little bit better than goto, a little bit worse than using exit. Exit, Break and Continue are all good. No problem with them being used properly. These local variables that are shared between local functions are very different because they tend to have larger scope that is harder to manage. Share this post Link to post
David Heffernan 2353 Posted May 16 20 minutes ago, dummzeuch said: Unless, of course you need a local type declaration that you don't want to be visible outside the unit. Types can be declared inside structured types. Share this post Link to post
Uwe Raabe 2064 Posted May 16 1 hour ago, David Heffernan said: Types can be declared inside structured types. Indeed, but they still reside in the interface section and thus may need some units being used in the interface section instead of the implementation section. 1 Share this post Link to post
David Heffernan 2353 Posted May 16 45 minutes ago, Uwe Raabe said: Indeed, but they still reside in the interface section and thus may need some units being used in the interface section instead of the implementation section. Not is the containing structured type is declared in the implementation section Share this post Link to post
microtronx 38 Posted May 16 (edited) I use them sometimes but I ensure that all variables and constants in local procedures have a _ as prefix procedure Main(); var vmyString:string; procedure _one(); begin vmyString:=vmyString+'_def'; end; procedure _two(const _var:string); begin vmyString:=vmyString+' : '+_var; end; begin vmyString:='abc'; _one(); _two( copy(vmyString,1,3) ); end; Edited May 16 by microtronx Share this post Link to post
dummzeuch 1517 Posted May 16 2 hours ago, David Heffernan said: 4 hours ago, dummzeuch said: In my opinion ... Exit, Break and Continue are all good. No problem with them being used properly. These local variables that are shared between local functions are very different because they tend to have larger scope that is harder to manage. Somehow I expected your opinion to be different from mine... Share this post Link to post
Stefan Glienke 2019 Posted May 16 While I at times use local routines I avoid accessing outer scope local variables like the plaque because it usually generates quite a huge and often unnecessary stack frame. 2 Share this post Link to post
David Heffernan 2353 Posted May 16 14 minutes ago, dummzeuch said: Somehow I expected your opinion to be different from mine... My opinions are independently formed though Share this post Link to post
MichaelT 6 Posted May 17 On 5/16/2024 at 6:22 AM, Tommi Prami said: ...For me this is very hard to wrap my brains around. For me this pattern requires lot of thinking and overloads my limited memory, to keep in mind that call to local procedure might touch the local variable, even it is not directly passed into them. I don't have anything against local methods, they wrap nicely some local need, that is specific for that parent method, and only for that. But fight are they good idea at first place, is another matter. -Tee- That language 'feature' is a useful relic. A file in the context of the 'C' or 'Pascal' world is a compilation unit and a module is defined at a different level of abstraction. The keyword unit is about compilation units. Modula introduced modules. That's more or less the 'Host world' & Friends, no compilers or what we call a compiler today. These systems loaded a module for example into an execution context/process and the code run and/or were interpreted under the control of the executing system. A PC application or an program on home computers is controlled by a minimalistic runtime and utilizes the OS way more actively. Modules can have parameters. Have a look at PL/SQL. If you think of MTS or COM and apartments, said sloppy, it's about putting those old machines to the Windows PC. There is good reason for having interfaces and functions/procedures there and not classes in general. This COM and COM+ world is a mixture of IBM-host and DEC computers I think (appartments and friends). In remote scenarios a parameterized module does it's job pretty well (Oberon - Modula successor). On way to mimic modules are those kind of procedures. Object orientation also means modularization and a class is usually responsible fot this. In the context of above an object is a loaded module ready to execute and the application is already a 'host' computer and with a GUI involved in a certain kind of 'single user' mode (kinda MS-DOS). With the help of threads or co-routines this single user application turns into a multi-user application but without a GUI on the server side. Another example would be package vs. package library. The library is simply a concatenation of complied compilation units and the package library goes beyond. In Delphi you still have compilation units in fashion of a module, for example initialization and finalization, module variables and so on, classes, and procedures acting as a module pretty similar to Pascal on 'host' computers. On the other hand people tried out different kind of ways to experiment with the visibility and accessibility of variables and recursion on the other hand. Some problems in theoretical computer science can be solved easier or more readable when stack a function call is read a different way from left to right, right to left or from the middle. In practice those cases are rare, but at the days of upcoming multi purpose languages there have been approaches to mimic the capabilities of domain languages focused on math problems and expressed in the U.S. style of function definitions (Haskel and other functional languages from the syntax perspective). In Europe we use another standard way of describing mathematical functions, different notations. Agreed, without ever having seen these old, in the 1990s most of this was already pretty old stuff just mentioned in our scripts at the university by the guys who invented PL/I at IBM, Mr. Rechenberg (Left Linear programming languages LL(1 aka Pascal for example), just on e symbol needed to decide what comes next) and his buddy at the university in Berlin who focused on LR aka. C, a guy from the Netherlands. The difference was that the LL compiler were hand crafted and the LR languages were those built with Lex and Yacc. The difference is not the grammar solely but the way the compilers are built. Later also C and especially C++ syntax and compilers were harmonized into a more left linear appearances (2 pass no longer required or as substantial as before - from necessity to feature). I hope I crumbled this very past knowledge together correctly. I never built a compiler, we built Pascal interpreters or better said Modula Interprets aka. Mini-Modula later replaced by Mini-Java interpreters with the focus on recursive decent parsers. Share this post Link to post
msohn 28 Posted May 17 16 hours ago, Stefan Glienke said: While I at times use local routines I avoid accessing outer scope local variables like the plaque because it usually generates quite a huge and often unnecessary stack frame. I'd love to learn more about this. Does that mean that passing the variables as arguments to local routines would generate more efficient code? Share this post Link to post