1. THE BASICS
The PureBasic manual defines modules as follows:
Technically, modules are mini-programs within larger programs, which could be called like procedures. But unlike procedures, they execute their immediate code without the parent program calling them. And also unlike procedures, modules could also contain their own procedures.Modules are an easy way to isolate code part from the main code, allowing code reuse and sharing without risk of name conflict. In some other programming languages, modules are known as 'namespaces'.
Let's demonstrate this with some simple examples. Consider this empty procedure:
Code: Select all
Procedure myProcedure()
EndProcedure
Code: Select all
DeclareModule myModule
EndDeclareModule
Module myModule
EndModule
Code: Select all
Procedure myProcedure()
Protected myVar = 123
EndProcedure
Code: Select all
Procedure myProcedure()
Protected myVar = 123
EndProcedure
Debug myVar ; == 0
Code: Select all
Procedure myProcedure()
Protected myVar = 123
ProcedureReturn myVar
EndProcedure
Debug myProcedure() ; == 123
In the case of modules, there would be two ways to add variables. This is the first way:
Code: Select all
DeclareModule myModule
EndDeclareModule
Module myModule
Define myVar = 123
EndModule
Code: Select all
DeclareModule myModule
Define myVar = 123
EndDeclareModule
Module myModule
EndModule
Code: Select all
DeclareModule myModule
EndDeclareModule
Module myModule
EndModule
In the first of the two module examples, the variable myVar was declared in the lower module section, like so:
Code: Select all
DeclareModule myModule
EndDeclareModule
Module myModule
Define myVar = 123
EndModule
Code: Select all
DeclareModule myModule
EndDeclareModule
Module myModule
Define myVar = 123
EndModule
Debug myVar ; == 0
Code: Select all
DeclareModule myModule
EndDeclareModule
Module myModule
Define myVar = 123
EndModule
Debug myModule::myVar ; == 0 ?
As stated earlier, variables and functions enclosed within modules are not accessible by the parent program unless they are expressly made available. And this is done by declaring them in the upper declaration section of the module structure.
In order to remedy this, and make the variable accessible, we would have to use the second method, which declares the variable myVar, like so:
Code: Select all
DeclareModule myModule
Define myVar = 123
EndDeclareModule
Module myModule
EndModule
Debug myModule::myVar ; == 123
Code: Select all
DeclareModule myModule
Define myVar
EndDeclareModule
Module myModule
myVar = 123
EndModule
Debug myModule::myVar ; == 123
Procedures are great at modulating reusable functions, saving the need for tediously repetitive code. However, at best, each procedure is capable of performing only a handful of processes. Consider this:
Code: Select all
Procedure myProcedure(a, b)
c = a + b
ProcedureReturn c
EndProcedure
Debug myProcedure(1, 2) ; == 3
Code: Select all
DeclareModule myModule
Declare myProcedure(a, b)
EndDeclareModule
Module myModule
Procedure myProcedure(a, b)
c = a + b
ProcedureReturn c
EndProcedure
EndModule
Debug myModule::myProcedure(1, 2) ; == 3
At its very core, that's all there is to modules. A glorified procedure with its own namespace. Although that's where the similarities between procedures and modules end.
2. INNER FUNCTIONS
As mentioned earlier, modules are like mini-programs. In addition to their exposed variables and functions, they could also house private ones that are never accessed or referenced by the parent program. For example:
Code: Select all
DeclareModule myModule
Define myVariable
Declare myProcedure(a, b)
EndDeclareModule
Module myModule
myVariable = 123
myPrivateVariable = 789
Procedure myPrivateProcedure()
Shared myPrivateVariable
Debug Str(myPrivateVariable)
EndProcedure
Procedure myProcedure(a, b)
myPrivateProcedure()
c = a + b
ProcedureReturn c
EndProcedure
EndModule
3. NAMESPACES
To delve further, let's explore the concept of namespaces. We've seen that modules have a unique prefixing syntax with which to reference its elements.
Code: Select all
myModule::moduleVariable
myModule::moduleFunction()
Code: Select all
DeclareModule myModule
Define myVariable
Declare myProcedure(a, b)
EndDeclareModule
Module myModule
myVariable = 123
Procedure myProcedure(a, b)
c = a + b
ProcedureReturn c
EndProcedure
EndModule
UseModule myModule
Debug myVariable
Debug myProcedure(1, 2)
UnuseModule myModule
Code: Select all
myVariable = 456
DeclareModule myModule
Define myVariable
EndDeclareModule
Module myModule
myVariable = 123
EndModule
;UseModule myModule ; this entire block would
; Debug myVariable ; throw a namespace error
;UnuseModule myModule
Debug myVariable ; == 456
Debug myModule::myVariable ; == 123
Now that we've seen how the module makes its variables and functions available to the parent program, how do we get elements from the parent program into the module?
Code: Select all
Global myVersionNumber = 1.23
DeclareModule myModule
Declare displayVersionNumber()
EndDeclareModule
Module myModule
Procedure displayVersionNumber()
Debug myVersionNumber
EndProcedure
EndModule
myModule::displayVersionNumber() ; == 0 ?
To do this, a bridging interface would be required. And for that, we would simply use another module. The manual refers to this as a common module, but it's really just a dummy module whose sole purpose is to relay data between the parent program and the modules in use. It's pretty simple actually.
Code: Select all
DeclareModule globalVars
myVersionNumber.f = 1.23
EndDeclareModule
Module globalVars
;dummy module used purely as a container
;to relay data between parent & modules
EndModule
DeclareModule myModule
Declare displayVersionNumber()
EndDeclareModule
Module myModule
Procedure displayVersionNumber()
Debug StrF(globalVars::myVersionNumber, 2)
EndProcedure
EndModule
myModule::displayVersionNumber()
Your feedback and comments are always welcome.