Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

LOCAL vars and Naming Conventions 2

Status
Not open for further replies.

academica

Technical User
Feb 21, 2010
28
CN
This is not an actual problem, it’s about scope and naming conventions of variables and is related to good coding style and programming principles. (I’m posting this after having read thread184-1527177. I’m also familiar with Hungarian Notation and Naming Conventions).
Suppose you have the following case:
Code:
FUNCTION One
*********************
LOCAL lcChar_1
Var1 = MyFunction2()
…
ENDFUNC

FUNCTION Two
********************
LOCAL lcChar_2
lcChar_2 = lcChar_1 + CHR(32)
…
ENDFUNC
In this case I am confused by the notation lcChar_1, which means it’s a LOCAL char variable in FUNCTION Two, while it’s actually LOCAL in FUNCTION One.

My question is: When should the scope letter be used with a variable name? How does it improve programme readability?
 
Hmmm...

If I remember my scoping rules correctly, lcChar_1 is indeed a local variable in function one, and as such will not be visible in function two - unless declared locally there or passed as a parameter (thus declared implicitly anyway).

So I would have thought your code would crash, unless rewritten something like this:

Code:
FUNCTION One
*********************
LOCAL lcChar_1
LOCAL Var1
lcChar_1 = "a"
Var1 = Two(lcChar_1)
return(Var1)
ENDFUNC

FUNCTION Two(lcChar_1)
  ********************
  LOCAL lcChar_2

  lcChar_2 = lcChar_1 + CHR(32)
  return(lcChar_2)
ENDFUNC

Note that lcChar_1 was not explicity assigned any value, which would give it an initial value of .f. which would then throw an error when you tried to append a space (chr(32)) character to it.

Also, you were calling MyFunction2() - which isn't defined - I assumed you meant your function Two().

Lastly, Var1 (the return value from Two() or MyFunction2()) was not declared either and neither of the functions had any return value - so how would the value assigned to lcChar_2 get back to the calling program?

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.
 
Academica,

lcChar_1, which means it's a LOCAL char variable in FUNCTION Two, while it's actually LOCAL in FUNCTION One.

But it's not LOCAL in Function Two. In fact, it doesn't exist in Function Two, and an error will occur if you run it.

lcChar_1 is local to Function One (becuase you have declared it as such). That means that it won't be visible in lower-level functions. The fact that it is prefixed with "l" does not itself make it local. The prefix is merely a convention, and is not acted on by the compiler.

If you want Function Two to access the variable, you should pass it as a parameter.

By the way, you're also confused with the function names. For the purposes of your question, do we assume that MyFunction2 is the same as Two?

To answer your specific question, the scope letter should always be used with a variable name. In most cases, the variable will be local, and therefore the first letter should be "l". But it might be private ("p") or public ("g"). If the variable is being received as a parameter, the conventional prefix is "t".

As for improving readability, it's really a matter of taste. I can only say that I have been using this convention for about ten years, and it would seem odd to me not to use it. But that's just my opinion.

Hope this helps.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro tips, advice, training, consultancy
Custom software for your business
 
Thank you, Griff and Mike for your replies.
Yes, you are right: LOCAL hides the variable from the called subroutine. I've had the misconception that initializing a variable by STORE or an '=' operator gives it a LOCAL scope.

Here are my next questions:
1. What type are variables initialized by STORE or '='? PRIVATE?
2. What is the advantage of declaring a variable as LOCAL and hiding it from the lower level?
3. If I have, say, a counter (nCntr), which will be changed in a lower level function, what is the proper way to declare it in the calling routine:
- by an assignment operator,
- as a PRIVATE variable or
- to pass it as a parameter (this raises the problem how to return two variables from a function)
 

1) Generally, a STORE or an assignment to a previously nonexistant variable will either create a private variable (if you are in a function or subroutine) or an effectively public one (if you are in the top level code), although it is really a private one - which happens to be visible to everything else below it (which is everything).

2) If you make something explicitly LOCAL, the subroutines (functions, or any other call for that matter) CANNOT POSSIBLY alter its value - because for them it does not exist. This is good for things like flags and counters, where they tend to have similar names. A PRIVATE variable is different, because the subroutines can not only see it - they can change it. This is not so good for flags and counters - but very handy if you are simply trying to improve the readability of a very large code block by chopping it up into procedures and functions and a) don't want to pass enormous lists of parameters or b) want your functions to be able to change the values.

Purists would probably condemn me for using PRIVATE variables this way B-)

3) I would tend to use the PRIVATE declaration, but the 'proper' way to do it is probably to pass the variable by reference as a parameter to the function.

Code:
LOCAL A
a=1
MyFunction(a)  && passed by value (by default)
? a  && a is still 1
MyFunction(@a) && passed by reference (due to the @)
? a  && a is now 2

function MyFunction(x)
  x = x +1
return(.t.)


I think ALL arrays are passed by reference anyway




Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.
 
I'll take a shot at these ...

1. What type are variables initialized by STORE or '='? PRIVATE?

If you don't explicitly declare the scope, any variables you create are private, which means they're visible in the routine that creates them, and any lower level routines (unless the lower level routines themselves declare the variables as private, in which case it becomes a different variable).

Actually, it's slightly more complicated than that: PRIVATE doesn't actually create a variable; it simply says that any undeclared variables with the specified names that are created in the routine will be private. But don't worry too much about that.

2. What is the advantage of declaring a variable as LOCAL and hiding it from the lower level?

A big advantage: it helps to keep your procedures and functions self-contained. You can call whatever functions you like without having to worry about what variables they use, or whether there's likely to be a name clash. That in turn makes coding and testing easier, and it helps to avoid hard-to-find bugs.

3. If I have, say, a counter (nCntr), which will be changed in a lower level function, what is the proper way to declare it in the calling routine:

You can do that by making it private in the caller (and not making it private in the lower level). But it's generally advisable to keep away from privates.

A better way is to pass the variable to the lower level as a parameter - and to pass the parameter by reference. That means that both routines will see the same value, and any changes that the lower level make will be passed back to the caller.

But I'd question why you want to do this. If you want a function to transform a value in some way, it's better for the function to receive the value as a parameter (passed in the normal way, that is, by value, not by reference). The function would then return a new value to the caller.

A quick example:

Code:
* main procedure

LOCAL lcSSN

USE SomeTable
GO TOP
lcSSN = SomeTable.SSN

* Convert SSN to printable format
lcSSN = FormatSSN(lcSSN)

* etc etc.

FUNCTION FormatSSN
* Receives a string representing a social security number.
* Adds dashes between the elements; pads with leading
* zeroes.
LPARAMETER tcStr

LOCAL lcWork

lcWork = PADL(tcStr, 9, "0")

RETURN LEFT(lcWork, 3) + "-" + SUBSTR(lcWork, 5, 2) + ;
  "-" + RIGHT(lcWork, 4)
ENDFUNC

The best advice it to always to declare your variables as local, unless you've got some overriding reason not to (for example, passing variables to reports, or using them in the ON SELECTION clause of a menu - but those are unusual cases).

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro tips, advice, training, consultancy
Custom software for your business
 
Thank you, Griff and Mike. Your info has been invaluable, as it helped me put in place two more pieces of the puzzle: the scope of variables and passing parameters.

I like doing things properly, i.e. I'll rewrite the code. Good I'm still at the beginning. Thanks again.

VFP 9.0 SP2 on XP SP3
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top