What are the scopes of the variables in the ADVPL and when to use each one?

Asked

Viewed 1,116 times

5

I am taking a code from a colleague to give maintenance. I find myself with this code here:

Static Function Conv2Json(cCpo)
    Local cRet := ""
    Local cSeparador := ""

    aCpo := StrtoKArr(cCpo, ';')

    cSeparador := " + ' - ' +"

    For i := 1 to len(aCpo)
        cRet += _cTabela + "->" + aCpo[i] + cSeparador
    Next i

    cRet := SUBS(cRet, 1, len(cRet) - len(cSeparador))
return cRet

But I don’t see _cTabela being used as a parameter and not being declared as a function variable.

I have seen, however, that she is declared in calling function:

User Function makeUniJson(cTabela, cOp, cTabgeo) 
    Local cJson := ""

    Local cCodTab       := ""
    Local cTabProtheus  := ""
    Local cTabGeosales  := ""
    Local cStatus       := ""

    Local xResult       := ""

    Private _cTabela    := cTabela

    Default cTabGeo     := ""

    ...

Apparently, it has something to do with the scope of the variable, but I didn’t quite understand how this scope issue works.

What is the difference between variables declared with Local or Private? What would be the Default? There is something like Global or Public?

2 answers

5


ADVPL in essence is the Clipper (worsened). Language has a thing called dynamic scope, one of the worst computer inventions. But it’s not a big problem, because this mechanism is totally optional, you can use local variables like any language and have the lexical scope normally, without harm. Every good programmer knows not to use dynamic scope, except in languages made only to create scripts, even in these languages is not encouraged by the authors themselves.

The scope of the variable is determined by the time of execution it was created and survives and is visible until the scope is still active, even if the lexical scope is another. That is, the variable is created in a function and all the functions that it calls and those that were called in the whole stack, it exists and is visible normally, it only ceases to exist when the function that created it is finished. It is created by default if you do not put any scope modifier attribute or if you are explicit and declare the variable as private.

It’s a kind of global public variable, where it has the lifetime for the entire application from the moment it’s created and it’s always visible, even outside (after it’s finished) where it was created, only the private variable has a slightly reduced scope, since it only exists up the pile and not down.

You might think, public is worse than private, since it has a much broader scope, right? In theory yes, in practice no. In practice every programmer knows that public is too dangerous and avoids its use (no Clipper/Harbour code needs public or private to have its full potential, is completely unnecessary resource, in thesis ADVPL could also, but in practice not), while the variable private (dynamic scope) the programmer feels safe and uses as if the variable were so private, and is not quite as already shown above.

But guess what? Protheus is all developed with private in mind. You have to guess which variables are in the scope at that time. And there could be hundreds. And you have to be careful not to create a new one in the scope of this function because it may conflict with the existing "private". It’s crazy, it’s insane, even for a small app, imagine for one with millions of phone lines with dozens of call stacks.

So in your codes just use local (or static in some rare cases), do not use public or private under no circumstances. But consume the existing variables declared so by the system. They end up being part of the contract, the API. Always consider them as if they had been received as a parameter.

So you think: there should be documentation showing all the variables in each function. But it does not, first because the documentation is weak, second because it hardly makes sense. Depending on the order of call will be other variables. Your user role has no documentation, and it is in your role that they will be available. Depends on who you call can change the available variables. It’s in trial and error, and look at debugging which variables are there now (which may be different depending on the version (it’s bad anyway, I have recent experience, even had open call to resolve certain situations that made it impossible to resolve a certain issue I was working on).

I’m sorry you have to go through this. I did too. I had to ask for new entry points to be created to resolve without depending on these variables. When they create new things they do it right and pass arguments to my user role, today they know it’s not to use it. But guess what again? Not all programmers there know what they are doing or are committed to doing right and a lot of stuff is still created this way. When it passes in the only department that is ISO 9000 there (yes, only a tiny department has the certification) do it right. And obviously everything that is legacy has no way to solve because most variables have become part of the "contract".

Look at the available variables in debugging, do this in several places and see if it is something punctual as the other answer says. Some people have access to current sources of Protheus, if you have see if it is punctual. I saw, and it is not yet, today. The list only does not increase anymore because now they understand that they should not create new ones like this, which confirms everything I said above.

In his example makeUniJson() "exports" the variable _cTabela for all the functions that it calls or the others that are being called by them, it must be the case of Conv2Json(). There’s nothing you can do to stop it, except in your code, you don’t create new variables like that. Prefer only to export what you need by parameters, as in any healthy language.

  • Any reader of this answer, I suggest this complementary reading to deepen the concept and absurdity that is dynamic scope: https://answall.com/a/13471/64969

  • I also recommend reading the TDN documentation, which talks about the scopes of variables in Advpl -- http://tdn.totvs.com/pages/viewpage.action?pageId=6063097

-1

As explained in another answer, variables private have dynamic scope.
This type of scope is more common in "shell" languages, such as bash (Linux) and cmd (DOS/Windows).

In general use languages it is not common to have a dynamic scope, which however exists in at least 2 current languages: in perl (5/6), where it is explicitly declared, and in Lua, where global variables implicitly have a dynamic scope.

In the ADVPL/Protheus eco-system, the generic use of variables is not common private, however in ERP Protheus there is a specific use case where these variables are used: in customizing routines by the client.

Each "module" (Materials, Stock, etc) of Protheus publishes a list of "entry points" (functions) that business routines make available, so that they can be customized by customers.

These customizations are usually performed by consulting analysts who have knowledge of the module in question. Usually (always?) the parameters are passed to the input points in a variable private array type and PARAMIXB name.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.