Jump to content
Tommi Prami

What do you think of "Local Global variables"

Recommended Posts

Posted (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 by Tommi Prami

Share this post


Link to post

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
Posted (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 by dummzeuch
  • Like 5

Share this post


Link to post

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.

 

  • Like 1

Share this post


Link to post
Posted (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 by Tommi Prami

Share this post


Link to post
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

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. 

  • Like 1

Share this post


Link to post
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
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

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

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

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.

  • Like 1

Share this post


Link to post
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
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.

  • Like 1

Share this post


Link to post
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
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
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
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. 

  • Like 1

Share this post


Link to post
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
Posted (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 by microtronx

Share this post


Link to post
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

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.

  • Like 2

Share this post


Link to post
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
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
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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×