PureBasic Forum
http://forums.purebasic.com/english/

PureBasic Modules: A Quick Tutorial
http://forums.purebasic.com/english/viewtopic.php?f=12&t=70686
Page 1 of 2

Author:  TI-994A [ Thu May 10, 2018 6:19 pm ]
Post subject:  PureBasic Modules: A Quick Tutorial

A QUICK & SIMPLE TUTORIAL ON THE USE OF MODULES

1. THE BASICS
The PureBasic manual defines modules as follows:
Quote:
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:
Procedure myProcedure() 
EndProcedure

The module equivalent of the above procedure would be these set of closures:
Code:
DeclareModule myModule 
EndDeclareModule

Module myModule   
EndModule

At this point, they both do absolutely nothing. So, let's add a variable to the procedure:
Code:
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:
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:
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:
DeclareModule myModule
EndDeclareModule

Module myModule 
  Define myVar = 123
EndModule

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

Author:  Andre [ Thu May 10, 2018 8:07 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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... ;-))

Author:  Paul [ Thu May 10, 2018 8:16 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

Very nicely done !

Author:  Dude [ Thu May 10, 2018 10:46 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

Great tutorial! This thread needs to be made Sticky.

Author:  TI-994A [ Fri May 11, 2018 4:39 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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

Author:  davido [ Fri May 11, 2018 5:33 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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

Author:  walbus [ Fri May 11, 2018 6:52 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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

Author:  TI-994A [ Fri May 11, 2018 9:31 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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?

Author:  walbus [ Fri May 11, 2018 12:48 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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

Author:  Fred [ Fri May 11, 2018 1:01 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

Very nice tutorial :)

Author:  TI-994A [ Fri May 11, 2018 3:34 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

Fred wrote:
Very nice tutorial :)

Thank you, Fred; truly appreciate that. :D

Author:  Andre [ Mon May 14, 2018 11:32 pm ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

@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...

Author:  TI-994A [ Tue May 15, 2018 3:27 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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.

Author:  RSBasic [ Thu May 17, 2018 8:29 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

Nice tutorial.

Author:  applePi [ Sat Jun 02, 2018 9:41 am ]
Post subject:  Re: PureBasic Modules: A Quick Tutorial

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.

Page 1 of 2 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/