Shadowing Rules
In CODESYS, you are generally allowed to use the same identifier for different elements. For example, a POU and a variable can be named the same. However, you should avoid this practice in order to prevent confusion.
Negative example: In the following code snippet, a local function block instance has the same name as a function:
In such a case as this, it is unclear whether the instance or the function is called in the program.
FUNCTION YYY : INT ; END_FUNCTION FUNCTION_BLOCK XXX ; END_FUNCTION_BLOCK PROGRAM PLC_PRG VAR YYY : XXX; END_VAR YYY(); END_PROGRAM
Compiler behavior when shadowing
The compiler does not report any errors or warnings if the same identifier is used for different elements. Instead, the compiler searches the code in a specific order for the declaration of the identifier. If a declaration is found, then the compiler does not search for any other declarations elsewhere. If other declarations do exist, then they are "shadowed" for the compiler. The following section describes the shadowing rules (that is, the search order that the compiler uses when searching for the declaration for identifiers). The section "Ambiguous access and qualified access" provides ways to prevent ambiguous access and bypass shadowing rules.
How to prevent shadowing
To make sure that names are always unique, you should follow naming conventions, such as certain prefixes for variables.
For more information, see: Identifier Designation
Naming conventions can be checked automatically using the static code analysis of CODESYS. Static code analysis could also detect the duplicate use of the name YYY
and report it as an error.
Also through the consistent use of the attribute qualified_only
for enums and global variable lists and by using qualified libraries non-unique situations can be avoided.
To make sure that a POU of the same name in the Devices view is not called when a POU in the POUs view is called, the operator __POOL
should be prepended when the name of the POU is called.
Example: svar_pou := __POOL.POU();
Search order in the application
When the compiler encounters a single identifier in the code of an application, it searches for the corresponding declaration in the following order:
Local variables
Local variables of a method
Local variables in the function block, program, or function, and in any base function blocks
Local methods of the POU
Global variables in the application, if the
qualified_only
attribute is not set in the variable list where the global variables are declaredGlobal variables in the application, if the
qualified_only
attribute is not set in the variable list where the global variables are declaredGlobal variables in a parent application, if the
qualified_only
attribute is not set in the variable list where the global variables are declaredGlobal variables in referred libraries when neither the library nor the variable list requires qualified access
POU or type names
POU or type names from the application (that is, names of global variable lists, function blocks, and so on)
POU or type names from a parent application
POU or type names from a library
Libraries
Namespaces of locally referred libraries and libraries that are published by libraries
Global variables in the POUs view, unless the
qualified_only
attribute is set in the variable list where they are declaredGlobal variables in the POUs view, unless the
qualified_only
attribute is set in the variable list where they are declaredPOU or type names from the POUs view (that is, names of global variable lists, function blocks, and so on)
Libraries from POUs
Tip
Libraries that are inserted in the Library Manager of the POUs view are mirrored in the Library Manager in all applications in the project with the appropriate placeholder resolution. These libraries then form a common namespace with the libraries in the application. Therefore, there is no shadowing of libraries in the pool by libraries in the application.
Search order in the library
When the compiler encounters a single identifier in the code of a library, it searches for the corresponding declaration in the following order:
Local variables
Local variables of a method
Local variables in the function block, program, or function, and in any base function blocks
Local methods of the POU
Global variables
Global variables in the local library, if the
qualified_only
attribute is not set in the variable list where the global variables are declaredGlobal variables in referred libraries when neither the library nor the variable list requires qualified access
Libraries
POU or type names from the local library (that is, names of global variable lists, function blocks, and so on)
POU or type names from a referred library
Namespaces of locally referred libraries and libraries that are published by locally refereed libraries
Ambiguous access and qualified access
Despite these search orders, ambiguous access can still occur. For example, this is the case when a variable with the same name exists in two global variable lists that do not require qualified access. Such a case is reported by the compiler as an error (for example: Ambiguous use of the name XXX
).
This kind of ambiguous usage can be made unique by means of qualified access, for example by accessing via the name of the global variable list (example: GVL.XXX
).
Qualified access can also always be used to avoid shadowing rules.
The name of the global variable list can be used to uniquely access a variable in the list.
The name of a library can be used to uniquely access elements in the library.
The
THIS
pointer be used to uniquely access variables in a function block, even if a local variable with the same name exists in a method of the function block.
To find the declaration location of an identifier at any time, use the
command. This can be especially helpful if the compiler produces an apparently obscure error message.Searching in instance paths
The search orders described above do not apply to identifiers that exist as components in an instance path or to identifiers that are used as inputs in calls.
For access of the following type yy.component
, it depends on the entity described by yy
where the declaration of component
is searched for.
If yy
denotes a variable with a structured data type (that is, type STRUCT
or UNION
), then component
is searched for in the following order:
Local variables of the function block
Local variables of the base function block
Methods of the function block
Methods of the base function block
If yy
denotes a global variable list or a program, then component
is searched for in this list only.
If yy
denotes a namespace of a library, then component
is searched for in this library exactly as described in the section above "Search order in the library".
Only in the second instance does the compiler decide whether access to the found element is granted (that is, whether the variable is only locally accessible, or whether a method is private). If access is not allowed, an error is issued.