PureBasic Modules: A Quick Tutorial

Share your advanced PureBasic knowledge/code with the community.
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

PureBasic Modules: A Quick Tutorial

Post by TI-994A »

A QUICK & SIMPLE TUTORIAL ON THE USE OF MODULES

1. THE BASICS
The PureBasic manual defines modules as follows:
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'.
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.

Let's demonstrate this with some simple examples. Consider this empty procedure:

Code: Select all

Procedure myProcedure()  
EndProcedure
The module equivalent of the above procedure would be these set of closures:

Code: Select all

DeclareModule myModule  
EndDeclareModule

Module myModule    
EndModule
At this point, they both do absolutely nothing. So, let's add a variable to the procedure:

Code: Select all

Procedure myProcedure()
  Protected myVar = 123
EndProcedure
We know that the variable myVar is not accessible from the parent program, and trying to access it would only generate a new variable of the same name in the parent program, resulting with a zero value:

Code: Select all

Procedure myProcedure()
  Protected myVar = 123
EndProcedure

Debug myVar   ; == 0
The correct way of accessing the variable in the procedure would be to instruct the procedure to deliver the value to the parent program, like so:

Code: Select all

Procedure myProcedure()
  Protected myVar = 123
  ProcedureReturn myVar
EndProcedure

Debug myProcedure()   ; == 123
Quite simple and basic stuff.

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
And this would be the second way:

Code: Select all

DeclareModule myModule
  Define myVar = 123
EndDeclareModule

Module myModule  
EndModule
What's the difference? Before we answer that, let's take another look at the basic structure of the module:

Code: Select all

DeclareModule myModule  
EndDeclareModule

Module myModule    
EndModule
As the function name implies, the upper DeclareModule section handles the module declarations, while the lower Module section houses all of its functions. However, all the code in the module section would remain locked and inaccessible to the parent program unless they are selectively and expressly declared in the upper declaration section. To illustrate this further, let's return to the earlier example about the variable.

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
Like the procedure earlier, variables in modules are also not accessible from the parent program, and trying to access them would only generate a new variable of the same name in the parent program, resulting with a zero value:

Code: Select all

DeclareModule myModule
EndDeclareModule

Module myModule  
  Define myVar = 123
EndModule

Debug myVar   ; == 0
Unlike procedures, which would have to return the value of the variable to the parent program, variables in modules can be referenced and accessed directly. The syntax for referencing variables in modules from the parent program would be to prefix them with the module name, as follows:

Code: Select all

DeclareModule myModule
EndDeclareModule

Module myModule  
  Define myVar = 123
EndModule

Debug myModule::myVar   ; == 0 ?
However, you'd notice that the resulting output is still zero. Why is this?

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
Furthermore, the values for these public variables need not be assigned in the declarations section, and could also be assigned in the module body, like so:

Code: Select all

DeclareModule myModule
  Define myVar
EndDeclareModule

Module myModule  
  myVar = 123
EndModule

Debug myModule::myVar   ; == 123
So, what else could we do with modules?

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
The module-equivalent of the above procedure would look like this:

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
Notice how the same procedure has been added into the module, and notice how it has also been declared in the upper declaration section. It is then called in the same method, by prefixing the module name to the procedure name.

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
The variable myPrivateVariable and the function myPrivateFunction() are both inaccessible to the parent program, but they are still able to work within the module itself, called and operated upon by its own functions. A slightly oversimplified example, but it's pretty straightforward.


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()
However, there's another way to reference them, provided there are no naming conflicts with the parent program. There is a special closure function that can be used to omit the module prefix when used in the parent program. It's called UseModule/UnuseModule, and the implantation syntax is as follows:

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
That's really convenient, with one caveat; this convention would fail if the parent program utilises even one identical identifier for any of its variables or functions. In such a case, the UseModule/UnuseModule syntax would not be permitted, so use the module prefix instead.

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
4. INTEROPERABILITY
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 ?
The simple answer is, this is not possible. Not directly, anyway.

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()
And that's it! That about covers the basic aspects of modules in PureBasic. I hope that it has been clear and understandable, and at the very least, clarifying some of the common confusions.

Your feedback and comments are always welcome. :D
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by Andre »

Thank you! I like this very much :D

(something which would be good to be integrated into the 'beginners chapter' in the PB manual, but of course only if you agree... ;-))
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by Paul »

Very nicely done !
Image Image
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: PureBasic Modules: A Quick Tutorial

Post by Dude »

Great tutorial! This thread needs to be made Sticky.
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by TI-994A »

Thank you very much, guys! Always glad to hear it's helpful. :D
Andre wrote:...good to be integrated into the 'beginners chapter' in the PB manual...
Hi Andre. I'm so honoured that you'd think so. It's all for the PureBasic community, so please use it in any way you'd see fit.

Thanks again. :D
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: PureBasic Modules: A Quick Tutorial

Post by davido »

Very instructive. Thank you. :D
Andre wrote:(something which would be good to be integrated into the 'beginners chapter' in the PB manual, but of course only if you agree... ;-))
+1
DE AA EB
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: PureBasic Modules: A Quick Tutorial

Post by walbus »

Hi TI-994A

Still missing is the range definition and handling of global variables in a module and a reference to EnableExplicit, I think...

Regards Werner
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by TI-994A »

walbus wrote:Still missing is the range definition and handling of global variables in a module and a reference to EnableExplicit...
Globals are touched on in the INTEROPERABILITY section, but beyond that, they work pretty much the same way regardless of scope. And EnableExplicit is a compiler directive, but it too works the same way, according to scope.

What range definition are you referring to?
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: PureBasic Modules: A Quick Tutorial

Post by walbus »

Hi
Yes, I know it myself
By the section I meant to explain that global variables declared in a module are available to all procedures in the module, but not outside the module.

Modules should be ever created with EnableExplicit, that's what I meant here
An EnableExplicit in a module is only valid for the module, not outside the module
Fred
Administrator
Administrator
Posts: 16616
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by Fred »

Very nice tutorial :)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by TI-994A »

Fred wrote:Very nice tutorial :)
Thank you, Fred; truly appreciate that. :D
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by Andre »

@TI-994A: As you agreed (thank you! :d) I will try to add the tutorial to the PB manual (beginner chapter) for the next PB version. Thank you! :D

If you plan any changes/additions just give us a note, and please include them in the first post...
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by TI-994A »

Andre wrote:@TI-994A: As you agreed (thank you! :d) I will try to add the tutorial to the PB manual (beginner chapter) for the next PB version. Thank you! :D

If you plan any changes/additions just give us a note, and please include them in the first post...
Thank you, Andre. I'm truly glad. :D

I'll go over it and do the needful.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
RSBasic
Moderator
Moderator
Posts: 1218
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: PureBasic Modules: A Quick Tutorial

Post by RSBasic »

Nice tutorial.
Image
Image
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: PureBasic Modules: A Quick Tutorial

Post by applePi »

Thank you TI-994A for this lesson about Modules.
apparently you have the spirit of a teacher . so i am sure the users eager for more lessons about tricky things such as pointers and so on over the years.
i suggest to change the title of this tutorial to "Lessons in PureBasic" and then add this as lesson 1. so in the future and over the years you can add lesson 2 and so on in the same thread, while updating the contents in the first page, just a suggestion.
the lessons, tutorials, Documentations are usually very hard to write and needs tremendous efforts.
Post Reply