Implicit Variables - Big Mistake or Bad Idea?

or perhaps it might be a scoping issue with an implicit variable eg. i# or s" etc.

best to avoid implicit variables althogether - I recall there was a lot of discussion about this when ABC came out. It is a long time ago now (late 1997) but I seem to recall the problem was that whereas in Clarion/Legacy some of the embeds were routines (and therefore saw the variables of the containing procedure), in ABC these became methods with a different scope. It was not clear to the programmer that the ā€œouterā€ variable was not seen as (being implicit variables) a new variable was instantiated. This was a trap waiting for the unwary and hence the advice to avoid implicit variables unless they have very local scope (eg. with a loop) or better still just avoid them altogether.

1 Like

Surely the scope of the implicit variable is simply where its declared, no different to normally declared variables, beit at the global, module, procedure, routine, local procedure or class or class method its declared in?

Obviously it depends on the compiler how its handled ultimately, but its got to recognise the variable and then handle it in a way that doesnt simply throw a compiler error, otherwise noone would be able to use an implicit variable would they?

The only other thing I can say about implicit variables is they match the same data types available to use in the template language when using #Declare, the default datatype being a string, 32 characters long.

The existence of the three datatypes as implicit variables and template variables are perhaps a nod to the IEEE754 which was established in 1985.

Now where a problem might be seen, which maybe linked to what I have seen in the templates but not reported, is the handling of a section of source, ie a variable declared in a global, module, procedure, routine, local procedure, class, or class method conflicting with another section when they shouldnt be any scoping issue, like a procedure var conflicting with another procedure var, in much the same way as I have declared variables in #Application, #Procedure, #Extension, #Code, #Group, and sometimes the scope of a variable declared conflicts with a template symbol declared in a totally unrelated template, which has forced me to use unique variable/symbol names throughout all my templates and the shipping templates. [and whilst I was just editing the last part of this sentence, having already written out the everything you see below, this website popped up message saying this message was being edited in another window !?!, only Iā€™m not editing it in two windows simultaneously]

Where I am most likely to see this is, is in a group in a template that happens to be in a group in another template sometimes with the same #group name sometimes not.

Typically what Iā€™ve done is copied functionality I need, defined as a #group into another #extension typically. Its why Iā€™ve been prompted into building my templates with output to debugview, to track down whats happening internally, and also why Iā€™ve written a template chain which can write templates, to help with scoping issues and management. In other words, eliminating the human error risks as much as possible.

But this scoping issue doesnt always show up which makes me think some other condition is needed first in order to trigger it, like maybe a crash or something perhaps happening at the machine level, which maybe totally unrelated to Clarion other than its interfering with it.

I dont know if its a bug in the runtime data conversion handling that goes on, when someone assigns a value from a variable of one datatype to another variable of a different datatype, or if its something else.

But something strange is going on because Iā€™m seeing the same random problems with template symbols containing the wrong values, or conflicting with #groups declared in other templates, but they happen to have the same #group name.

Edit. The fact the documentation is poor does not help matters either, at worst, its dangerous.

Edit 2. This whole website just reminds me of this The Gentlepersonā€™s Guide To Forum Spies (cryptome.org)
and as someone who has suffered a lifetime of criminality from employees of the state, nothing would surprise me from the criminals that work for the state. After all the state imposes itself onto everyone whether they like it or not because you cant kill ideas.

no, this is not the case.
Implicit variables do not ā€œcome into scopeā€ in local procedures (methods) as local variables do.
So setting the implicit in the ā€œparentā€ scope, does not cause it to be set in the ā€œchildā€ scope and vice versa.

Using implicits of any kind, anywhere, is considered very bad form. (Necessary in a very limited subset of cases, but ā€œbad codeā€)

1 Like

As noted in the help Implicit variables should NOT be used. Just Say No.

I would say the Scope and Life time of an ā€œImplicit variableā€ is exactly the same as if there were a variable declared at the Procedure level.

Implicit variables defined in one Routine are the same variable in all Routines of the Parent Procedure. This was done so existing code still worked. It can be changed so they are Local to the Routine with define(local_implicits=>1) as noted in the help.

Example:

In This.Init() you save Start Time as S#=CLOCK().

In This.Kill() you set End Time as E#=CLOCK(). If you try to calculate Elapsed=E#-S# you will find S#=0 because it will be a Local variable of This.Kill() and was a Local of This.Init() when saved.

(I think that can be made to work if S#=0 was done at the procedure level, but why try to fix a bad diea.)


I am familiar with this implicit issue because I created the Do2Class tool that takes a Legacy procedure with Embed Routines and changes them to be a DOO CLASS. All the code is changed from DO MyRoutine to a procedure call DOO.MyRoutine(). I have converted a lot of code so know the issues.

That Do2Class conversion will report problems with implicit variables and tags them for review (or better elimination). Because Routines could not pass parameters sometimes an Implicit was used to ā€œpass dataā€ e.g. Type#=3 ; DO FixType. When that DO changes to call the DOO.FixType() procedure the Type# variable will Not =3. Its easy to change it to pass (3).

So to restate it again ā€¦ itā€™s best to eliminate implicit variables. You can use Do2Class to find them all.

1 Like

Does your tool work for analyzing implicits in handcode modules too?

This isnt correct. I would put :

But this is.

Iā€™ve added the following code to the school.app
Main Procedure
Routine1
Message(s#)
s# = 1
Message(s#)
Routine2
Message(s#)
s# = 2
Message(s#)

ThisWindow.Init
s#=9
Message(s#)
Do Routine1
Message(s#)
Do Routine2
Message(s#)

The data I see in the debugger and the message box values I see that appear in this order are
D Debugger
_Not visible in the debugger
P Procedure
R1 Routine1
R2 Routine2
And I know Russ hated messages for debugging butā€¦
D9 P
_0 R1
_1 R1
D9 P
_1 R2
_2 R2
D9 P

Which suggests what you say, this might also explain why the debugger does not show implicit variables in the routine. And considering the templates #Declare use what appears to be implicit variables this might explain some of the scoping issues Iā€™ve see with symbols declared in groups, Iā€™m wondering if they are treated like implicit variables in routines like in this situation you highlight.

Well at least I know the implicit vars dont appear to work properly in a routine, but do in a procedure.

Agree!

Thanks!

Upper right select ā€œSourceā€ and paste it in:

1 Like

Just to scratch an itch, I added the following changes
Main Procedure
Routine1
Data
S1 Long
Code
Message(s1)
s1= s#
Message(s1)
Message(s#)
s# = 1
Message(s#)
Routine2
Data
S1 Long
Code
Message(s1)
s1= s#
Message(s1)
Message(s#)
s# = 2
Message(s#)

Declare s1 Long in local data
ThisWindow.Init
Message(s1)
s1= 8
Message(s1)
s#=9
Message(s#)
Do Routine1
Message(s1)
Message(s#)
Do Routine2
Message(s1)
Message(s#)

This is the data I get out, and S1 in the routines appear in the debugger.

D Debugger
_Not visible in the debugger
P Procedure
R1 Routine1
R2 Routine2
And I know Russ hated messages for debugging butā€¦
D0 P
D8P
D9 P
D0R1
D0R1
_0 R1
_1 R1
D8P
D9 P
D0P
D2P
D0R2
D1R2
_1 R2
_2 R2
D8P
D9P

So the variables declared in the routine encapsulated in data and code are being handled properly in terms of scope.
Its just the implicit variables declared at routine level are the same across all routines.

This seems to be a 101 test for all computer languages to test for scope issues, especially fuzzers and automated testing apps exist now. It might even pay to have something built into an template to just test apps with periodically in case something is going awry at the OS or Hardware level. Some sort of self testing module which runs in an app periodically whilst its being used. Other systems, like the automative industry do this, why shouldnt we? Its a cheap selling point to customers and it could potentially highlight problems which would have otherwise caused us work, to be bounced back to MS or the PC manufacturer.
Edit.
After this being moved into its own thread, with the thread title Big Mistake or Bad Idea?
I think knowing what to expect is key, there isnt any interprocess communication between routines, unless a procedure level var is declared or a file is used, so this could be a way to introduce obfuscation into code easily. Would have to check how decompilers, like Ghidra report the implicit variables. If decompilers report the implicit variables in a routine incorrectly, you have a sort of obfuscation, which can be handy, and the inter routine nature of implicit variables can be handy, provided everyone knows how they work.

On that point, there is nothing in the docs to suggest that implicit variables at routine level if using the same name are one and the same across all routines using the same implicit variable name. At the very least, perhaps the docs should state this and if the coder intends to use the same name, to be aware of this point and (re)set the value when stepping back into a routine, because the docs do say, the implicit vars are set to 0 or ā€˜ā€™ when first encountered, which isnt strictly true when stepping back into a routine where the implicit var has been used previously in the same routine or a different routine.
I cant even finish the previous sentence with ā€œin the same procedureā€, because I havent tested to see if the implicit var of the same name has a 0 or ā€˜ā€™ in a new procedure. Iā€™d like to think if using the new threading model, its scope is isolated by the new threading model, but like I say, I havent even tested that yet.

Caveat, this is what I see on C6, havent tested on C11 so dont know if changes have occurred with routines in later versions of Clarion.

When is a bug not a backdoorā€¦ or a weapon?

Edit2 The way these implicit variables work at the routine level is kind of like creating a parallel process in plain sight especially if the decompilers misreport the code or the analyst misunderstands its nature.

Variables declared explicitly in the ROUTINEā€™s DATA section are visible that ROUTINE only. The scope for implicit variables used in the ROUTINEā€™s code is dependent from value of the define(local_implicits) pragma. If it is equal to TRUE, implicit variables are local for ROUTINE and are not mixed with implicit variables with the same name used in the procedure code or in other routines. If value of pragma is FALSE, all implicit variables used in ROUTINEs have the scope of the procedure owning these routines and are sharing by all routines. Default value of pragma is FALSE

1 Like

And that can be defined application wide in the project setting or in the individual clw.

I havent tested, but can a pragma in a clw override the project setting?

When I look back at the numerous requests to do things in the newsgroups, activeinvisible being another, its like the ngs were used for phishing especially when looking at the documentation as well. :grinning:

Edit.

Do the project setting pragmaā€™s in the appgen control how the templateā€™s behave, like this local implicts pragma affecting the scope of template symbols in groups when generating code?

To answer your original question; Big Mistake or Bad Idea, implicits were necessary in DOS because of the very limited embed points in DOS. Also there there was only ā€œprocedureā€ scope, so they were effectively local variables.

For backward compatibility reasons they were included in the Clarion for Windows language. But as scoping became more complex, so their use became more dangerous. With the release of OOP additions the final nail was set.

They are neither a bad idea, nor a big mistake. they still have usefulness, but in very (very) limited contexts. For pretty much 99% of the time use of implicits should be considered a bug in the code. Certainly they would not be allowed in any code review I passed (without very specific reasons.)

So, feel free to dig into them as much as you like Richard, and theorise to your hearts content, but I recommend you simply never use them, and eradicate all use of them from your code. In the sense that you shouldnā€™t use them, digging deeper than that is for entertainment value only.

Generated code is just generated code. Templates donā€™t know about compiler settings, and they should generate code that doesnā€™t care about compiler settings. If your template-generated-code uses implicits across any code block, then (to be blunt) itā€™s crappy template code. period.

Pragmas set in the project are applying to all sources and they override compilerā€™s default values. The PRAGMA directives in the source file can override values of pragmas used as default by the compiler and/or set in the project.

I donā€™t understand this question.

I dont know if the template code generation could be affected by some of these #pragmaā€™s like local_implicts if found in the appgen project settings.

Bear in mind Iā€™m using the appgen to write the template code, so I didnt know if any pragma settings in the appgen project settings could influence the way the template code generation worked. Iā€™ve been under the impression most people write templates by hand, but I dont know that for sure, somebody else might have also written their own template to write template code using the appgen and just kept it quiet.

Iā€™m not. I dont like them personally, but now that I know what else could be done with them, I might have a play with them to see what else they can be made to do.

Pragmas are instructions for the compiler, linker or for the Project System. They do not affect the work of the AppGen in any way.

Ok thanks. I just wanted to check. :grinning: