Recent

Author Topic: Private Global Variables  (Read 714 times)

bobby6478

  • New member
  • *
  • Posts: 8
Private Global Variables
« on: October 17, 2019, 03:26:59 am »
This works EXACTLY as I want it to work, I'm not having any difficulties. However, whenever I've tried to find this on the forums and on google, I've found no discussions about it. In Free Pascal, it seems like if you declare a variable between interface and implementation of unit A, then that variable is accessible to all units that import A. However, if you declare it after implementation but outside of procedures and functions, the variable is accessible within all procedures and functions, but is not accessible to units which import it. There are a huge amount of applications for this (at least in my opinion), but it doesn't even get a mention on

https://wiki.freepascal.org/Scope

which surprises me. The reason for my post is, am I mistaken in some way, or is this an intended function of Free Pascal that is neglected in the documentation for the language? That is, is this concept of a global variable being private to a unit an actual feature of free pascal, or are there nasty behind the scenes consequences to me using it? Thanks!

440bx

  • Hero Member
  • *****
  • Posts: 1199
Re: Private Global Variables
« Reply #1 on: October 17, 2019, 03:50:08 am »
<snip>
is this an intended function of Free Pascal that is neglected in the documentation for the language? That is, is this concept of a global variable being private to a unit an actual feature of free pascal, or are there nasty behind the scenes consequences to me using it? Thanks!
It is intended.  It is not specific to Free Pascal, it is implemented in Delphi as well and it is a consequence of having an interface section separate from an implementation section.  That is well documented, though not stated the way you did.

Also, it doesn't apply only to variables.  It applies to anything that is declared in the implementation section.  For instance, it is quite common to have "implementation only" variables, types, functions and procedures.  Their _scope_ is confined to the implementation section.  Functions and procedures can be made _visible_ to other parts of the program by declaring them in the interface section of the unit.  Variables and types to be visible in other parts of the program, they must be declared in the interface section of the unit (instead of the implementation.)

HTH.
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

dbannon

  • Hero Member
  • *****
  • Posts: 755
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Private Global Variables
« Reply #2 on: October 17, 2019, 06:54:52 am »
Its also worth mentioning that while you CAN do it, you should not over do it.  It is, sort of a global variable with all the problems a global variable brings.

In particular, consider very carefully before you have units all over the place modifying the value of one of those variables. Have seen posts where very skilled people suggest you only do this via properties, maybe read only properties so you can keep things tidy.

Davo
Lazarus 2, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng

Thaddy

  • Hero Member
  • *****
  • Posts: 9183
Re: Private Global Variables
« Reply #3 on: October 17, 2019, 07:17:10 am »
Indeed. A simple example would look like this:
Code: Pascal  [Select]
  1. {$mode objfpc}
  2. unit readonly;
  3.  
  4. interface
  5. function GetTest:Integer;inline;
  6. property Test:integer read GetTest;
  7.  
  8. implementation
  9. var
  10.   FTest:Integer = 100;
  11. function GetTest:Integer;
  12. begin
  13.   Result := FTest;
  14. end;
  15.  
  16. end.
The property scope is global and read-only , but the variable itself has only local scope and can only be modified in local scope.
See https://www.freepascal.org/docs-html/current/ref/refse27.html (note the section on how to hide a getter/setter)

You can do tricks like this too:
Code: Pascal  [Select]
  1. {$mode objfpc}
  2. interface
  3. uses sysutils;
  4. { getter hidden in sysutils }
  5. property Time:TDateTime read Now; { any existing TFunction can be a getter for a property }
  6.  
  7. implementation
  8. end.

« Last Edit: October 17, 2019, 07:56:25 am by Thaddy »
also related to equus asinus.

PascalDragon

  • Hero Member
  • *****
  • Posts: 673
  • Compiler Developer
Re: Private Global Variables
« Reply #4 on: October 17, 2019, 09:04:01 am »
This works EXACTLY as I want it to work, I'm not having any difficulties. However, whenever I've tried to find this on the forums and on google, I've found no discussions about it. In Free Pascal, it seems like if you declare a variable between interface and implementation of unit A, then that variable is accessible to all units that import A. However, if you declare it after implementation but outside of procedures and functions, the variable is accessible within all procedures and functions, but is not accessible to units which import it. There are a huge amount of applications for this (at least in my opinion), but it doesn't even get a mention on

https://wiki.freepascal.org/Scope

which surprises me. The reason for my post is, am I mistaken in some way, or is this an intended function of Free Pascal that is neglected in the documentation for the language? That is, is this concept of a global variable being private to a unit an actual feature of free pascal, or are there nasty behind the scenes consequences to me using it? Thanks!
This rule is for all identifiers, not only variables and one of the core concepts of Object Pascal. It's also documented, namely in the language reference.

bobby6478

  • New member
  • *
  • Posts: 8
Re: Private Global Variables
« Reply #5 on: October 18, 2019, 05:17:51 pm »
Its also worth mentioning that while you CAN do it, you should not over do it.  It is, sort of a global variable with all the problems a global variable brings.

In particular, consider very carefully before you have units all over the place modifying the value of one of those variables. Have seen posts where very skilled people suggest you only do this via properties, maybe read only properties so you can keep things tidy.

Davo

I have created a class with properties, but I have an array which holds objects of that class, and that is what I write this "global variable" as. In fact, I'd rather keep this array buried as one of the class's class properties, but I'm unsure how that would work memory wise, so I've decided to just make it more of a global variable in the class file.

dbannon

  • Hero Member
  • *****
  • Posts: 755
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Private Global Variables
« Reply #6 on: October 19, 2019, 01:57:27 am »
I have created a class with properties, but I have an array which holds objects of that class, and that is what I write this "global variable" as. In fact, I'd rather keep this array buried as one of the class's class properties, but I'm unsure how that would work memory wise, so I've decided to just make it more of a global variable in the class file.

Look, its going to work either way. But we do have a morbid fear of global variables for a good reason.  If you are writing something thats going to turn out to be reasonably big, reasonably complicated and hitting that array from a number of places, you might like to consider making it an object in its own right, making some nice functions to access it. It will add a small overhead but FP is pretty good at optimizing things like that at compile time. This "API" approach may, later on make it heaps easier to do things like validating the data going into the array, having a single set of functions to find data in there, managing the data in there without affecting any other units. And even making debugging easier. 

But if its a small app that only you will ever work on, the global approach will certainly work. Thats the beauty of (eg) FP, you get to choose.

Davo
Lazarus 2, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng

Thaddy

  • Hero Member
  • *****
  • Posts: 9183
Re: Private Global Variables
« Reply #7 on: October 19, 2019, 07:37:04 am »
Quote
In fact, I'd rather keep this array buried as one of the class's class properties,
If the array is all of the same class type then to make it hidden you can do this in the defining unit:
Code: Pascal  [Select]
  1. type
  2.   TBaseclass = class
  3.   strict private { or strict protected, depending on application }
  4.   class var
  5.     FHidden:Array of TBaseClass;
  6.   end;

The array is the same(global to the class) for all instances of the class and completely hidden in units that use the class.
Such an array is truly global to the class only, wherever it is used. Only its instances can access it.
« Last Edit: October 19, 2019, 11:41:59 am by Thaddy »
also related to equus asinus.