Modules. What are they!?

Just starting out? Need help? Post your questions and find answers here.
User avatar
em_uk
Enthusiast
Enthusiast
Posts: 366
Joined: Sun Aug 08, 2010 3:32 pm
Location: Manchester UK

Modules. What are they!?

Post by em_uk »

Hi,

Now before I get flamed, I did do a search of the forums for Modules but found the topics too advanced for my poor brain and couldn't find anything that gave me any enlightenment!


So can someone please explain to me (like I'm an idiot) :

What is a module?

Why should I use them?

How do I use them?

and then a basic example of what they allow us to do now...

I may have a nice ripe apple to give the person who can make me understand them.

Thanks in advance!
----

R Tape loading error, 0:1
WilliamL
Addict
Addict
Posts: 1252
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Modules. What are they!?

Post by WilliamL »

MacBook Pro-M1 (2021), Sequoia 15.4, PB 6.20
User_Russian
Addict
Addict
Posts: 1520
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Modules. What are they!?

Post by User_Russian »

davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Modules. What are they!?

Post by davido »

@em_uk: Thank you for the question. I'm having problems with Modules.

@WilliamL: Thank you for the link. I must have missed that one.

:D
DE AA EB
User avatar
TI-994A
Addict
Addict
Posts: 2705
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Modules. What are they!?

Post by TI-994A »

I'm trying to figure it out myself, so let me see if I've got it right. If not, please steer me in the right direction.

In its simplest form, this is the basic structure of a module:

Code: Select all

DeclareModule myModule
  ;this is called the module declaration
EndDeclareModule

Module myModule
  ;this is called the module space
EndModule
At this point, they do absolutely nothing, so let's begin by adding a simple variable:

Code: Select all

DeclareModule myModule
EndDeclareModule

Module myModule
  Define a.i = 1
EndModule
The module now contains an integer variable, a, assigned with a value of 1. Since it is defined within the module space, it is a private variable, accessible only within the module. To add a public variable, it has to be defined in the module declaration, like this:

Code: Select all

DeclareModule myModule
  Define a.i = 1  
EndDeclareModule

Module myModule
EndModule
The integer variable a is now a public variable that is accessible inside and outside the module. Similarly, constants and procedures can also be private or public, depending on where they are declared. It should be noted that public variables can still be manipulated within the module:

Code: Select all

DeclareModule myModule
  Define a.i = 1  
EndDeclareModule

Module myModule
  a = 2
EndModule
As mentioned earlier, constants can also be defined within the module, either as private or public ones, depending on where they are defined:

Code: Select all

DeclareModule myModule
  #constant1 = 100
  Define a.i = 1  
EndDeclareModule

Module myModule
  #constant2 = 200
  a = 2
EndModule
Here, constant1 is a public constant, while constant2 is a private constant. Procedures, on the other hand, should always be created within the module, but to declare them as public, an additional declaration is required:

Code: Select all

DeclareModule myModule
  #constant1 = 100
  Define a.i = 1  
EndDeclareModule

Module myModule
  #constant2 = 200
  a = 2
  
  Procedure test(param)
    ProcedureReturn param + #constant1
  EndProcedure
EndModule
At this point, the procedure test() is a private procedure, accessible only within the module space. To make it a public procedure, accessible from outside the module, it has to also be declared in the module declaration:

Code: Select all

DeclareModule myModule
  #constant1 = 100
  Define a.i = 1  
  Declare test(param)
EndDeclareModule

Module myModule
  #constant2 = 200
  a = 2
  
  Procedure test(param)
    ProcedureReturn param + #constant1
  EndProcedure
EndModule
The procedure test()is now a public procedure, accessible from both inside and outside the module. Another procedure is added here to demonstrate this:

Code: Select all

DeclareModule myModule
  #constant1 = 100
  Define a.i = 1  
  Declare test(param)
EndDeclareModule

Module myModule
  #constant2 = 200
  a = 2
  
  Procedure test(param)
    ProcedureReturn param + #constant2
  EndProcedure
  
  Procedure test2(param)
    ProcedureReturn test(param) + #constant1
  EndProcedure
EndModule
Here, a new private procedure, test2(), calls the public procedure test(), making use of both private as public constants as well. Note that the procedure test2() is private only because it has not been declared in the module declaration, and can be made public by simply doing so.

Now, to use the module. As mentioned earlier, only public constants, variables and procedures are accessible from outside the module. This can be done in two ways. The first method is to use the full name of the module, in this case myModule, followed by two colons (::), and then the name of the public constant, variable or procedure:

Code: Select all

Debug myModule::#constant1   ;returns 100
Debug myModule::a            ;returns 2
Debug myModule::test(22)     ;returns 222
The second method is by using the keyword UseModule followed by the module name, myModule. After that, the public constants, variables and procedures can be used directly without any prefixes:

Code: Select all

UseModule myModule           
  Debug #constant1           ;returns 100
  Debug a                    ;returns 2
  Debug test(22)             ;returns 222
The keyword UseModule essentially merges the module namespace with the global namespace. It works in a similar way as the With/EndWith function, but without the need for the backslash (\) or EndWith. To stop this namespace merger, simply call UnuseModule, followed by the module name:

Code: Select all

UseModule myModule
  Debug #constant1
  Debug a
  Debug test(22)
UnuseModule myModule
This stops the namespace merger, and any further calls to the module must be done either with the full module name with double colons, or by calling the UseModule function with the module name again. One important point regarding namespaces: when using the UseModule function, the global namespace cannot contain same-named constants, variables or procedures. The following code syntax is legal:

Code: Select all

#constant1 = "Hello"
Define a.f = 1.23

Procedure.s test()
  ProcedureReturn #constant1 + " World!"
EndProcedure

Debug myModule::#constant1   ;returns 100
Debug myModule::a            ;returns 2
Debug myModule::test(22)     ;returns 222

Debug #constant1             ;returns "Hello"
Debug a                      ;returns 1.23
Debug test()                 ;returns "Hello World!"
This code syntax is not legal, and will raise an "...already declared in global scope" error:

Code: Select all

#constant1 = "Hello"
Define a.f = 1.23

Procedure test()
  Debug #constant1 + " World!"
EndProcedure

UseModule myModule           ;raises error 
  Debug #constant1
  Debug a
  Debug test(22)
UnuseModule myModule
However, if no name conflicts are expected, the UseModule function is very useful, and can save a lot of typing. Simply place it at the beginning of the program code, just after the module declaration:

Code: Select all

DeclareModule myModule
  #constant1 = 100
  Define a.i = 1  
  Declare test(param)
EndDeclareModulee

UseModule myModule

;the rest of the program code
;UnuseModule not required...
It should also be noted that, unlike procedures, the global contents in the module space are executed even if the module is not called. To illustrate:

Code: Select all

Procedure someProcedure()
  Debug "I will not be executed..."
EndProcedure
Clearly, even if the above procedure was placed at the beginning of the program code, the debug statement would not be executed unless the procedure is called.

Code: Select all

DeclareModule someModule
EndDeclareModule

Module someModule
  Procedure test(param)
    Debug "I will not be executed..."
  EndProcedure
  
  Debug "I will be executed..."
EndModule
On the other hand, if the above module was placed at the beginning of the program code, although the first debug statement would not be executed, the second one would.

So, that's PureBasic's new module function in a nutshell. Its main advantage over DLLs, procedures and include files is its unique namespace feature. Having a totally separate namespace allows modules to have constants, variables and procedures that would not run the risk of name conflicts, while still being able to share and expose selected elements, and have its code accessible from within the IDE.

Here's the complete working code for this little tutorial:

Code: Select all

DeclareModule myModule
  #constant1 = 100
  Define a.i = 1  
  Declare test(param)
EndDeclareModule

Module myModule
  #constant2 = 200
  a = 2
  
  Debug "This line will be executed..."
  
  Procedure test(param)
    ProcedureReturn param + #constant2
  EndProcedure
  
  Procedure test2(param)
    ProcedureReturn test(param) + #constant1
  EndProcedure
EndModule

;----------------------------------------
;UseModule works here before same-named
;constants, variables and procedures are
;declared in the global namespace
;----------------------------------------
UseModule myModule           
  Debug #constant1           ;returns 100
  Debug a                    ;returns 2
  Debug test(22)             ;returns 222
UnuseModule myModule
;----------------------------------------  

#constant1 = "Hello"
Define a.f = 1.23

Procedure.s test()
  ProcedureReturn #constant1 + " World!"
EndProcedure

Debug myModule::#constant1   ;returns 100
Debug myModule::a            ;returns 2
Debug myModule::test(22)     ;returns 222

Debug #constant1             ;returns "Hello"
Debug a                      ;returns 1.23
Debug test()                 ;returns "Hello World!"


;----------------------------------------
;UseModule fails here because same-named
;constants, variables and procedures have
;been declared in the global namespace
;and are conflicting with the module's
;constants, variables and procedures.
;----------------------------------------
; UseModule myModule
;   Debug #constant1
;   Debug a
;   Debug test(22)
; UnuseModule myModule
;----------------------------------------
Feedback and corrections are appreciated. :wink:
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
em_uk
Enthusiast
Enthusiast
Posts: 366
Joined: Sun Aug 08, 2010 3:32 pm
Location: Manchester UK

Re: Modules. What are they!?

Post by em_uk »

Thank you all for the links and especially TI-994A for that indepth opener. I think I am starting to get it.

So how would this work with things like sprites/screens/windows?

Could I take a sinus scrolly program and then convert it to module use and then incorporate with another program, maybe a background effect and then they both output to the same screen/window?

I will have a little go and see if I have grasped it.

:D
----

R Tape loading error, 0:1
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Re: Modules. What are they!?

Post by citystate »

just wondering about the use of UnuseModule - why does it have a parameter?

unless this is legal syntax:

Code: Select all

UseModule myFirstModule
  ;do stuff

UseModule mySecondModule
  ;do more stuff

UnuseModule myFirstModule

UnuseModule mySecondModule
it would seem to make more sense and would be neater (plus it would fit with existing PB keyword pairs) to use

Code: Select all

UseModule myFirstModule
  ;do stuff

  UseModule mySecondModule
    ;do more stuff (nested within the first module)
  UnuseModule

UnuseModule
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Modules. What are they!?

Post by c4s »

@citystate
UnuseModule is optional. In your second example must be called.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
TI-994A
Addict
Addict
Posts: 2705
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Modules. What are they!?

Post by TI-994A »

citystate wrote:just wondering about the use of UnuseModule - why does it have a parameter? unless this is legal syntax:

Code: Select all

UseModule myFirstModule
  ;do stuff

UseModule mySecondModule
  ;do more stuff

UnuseModule myFirstModule

UnuseModule mySecondModule
Hello citystate. As far as I know, the flow is perfectly legal, as long as there aren't any naming conflicts between the two modules. The UnuseModule directive is optional, unless needed.
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
TI-994A
Addict
Addict
Posts: 2705
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Modules. What are they!?

Post by TI-994A »

c4s wrote:UnuseModule is optional. In your second example must be called.
Hello c4s. You're right about UnuseModule being optional, although it is still not a requirement in citystate's second example. Referring to the code in question:

Code: Select all

UseModule myFirstModule
  ;do stuff
  UseModule mySecondModule
    ;do more stuff (nested within the first module)
  UnuseModule   ;must include module name
UnuseModule   ;must include module name
Neither one of the UnuseModule calls are required, unless there would be naming conflicts in the proceeding code.
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
Deluxe0321
User
User
Posts: 69
Joined: Tue Sep 16, 2008 6:11 am
Location: ger

Re: Modules. What are they!?

Post by Deluxe0321 »

Just a small question. How to make these examples work? Booth examples won't compile..

1)

Code: Select all

#XPATH = "C:\Test\Test\Test\"

DeclareModule foo
  #EXT_PATH = #XPATH + "foo.bar"
  Declare.s foo()
EndDeclareModule

Module foo
  Procedure.s foo()
    ProcedureReturn #EXT_PATH  
  EndProcedure
EndModule
2)

Code: Select all

Procedure DummyT(a.i,b.i)
  ProcedureReturn a.i + b.i * 2  
EndProcedure

DeclareModule bar
  Declare.i bar(a.i,b.i,c.i)
EndDeclareModule

Module bar
  Procedure.i bar()
    ProcedureReturn DummyT(a.i,b.i) * c.i
  EndProcedure
EndModule
I understand this has something to do with the namespace, so - how to access the "main" namespace?

Thank you!
User_Russian
Addict
Addict
Posts: 1520
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Modules. What are they!?

Post by User_Russian »

BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: Modules. What are they!?

Post by BorisTheOld »

TI-994A wrote: To add a public variable, it has to be defined in the module declaration, like this:

Code: Select all

DeclareModule myModule
  Define a.i = 1  
EndDeclareModule

Module myModule
EndModule
The integer variable a is now a public variable that is accessible inside and outside the module.
I would highly recommend that all data be private to the module.

The whole point of using modules is to isolate the code from the rest of the application. If data is made freely available then the resulting spaghetti code is guaranteed to cause problems. Module data, if needed, should only be accessed via public procedures. This is particularly important if one hopes to use a module in many applications. An application should not need to know how the module data is structured.

I would also recommend that the UseModule/UnuseModule feature not be used. It removes clarity from the code and is a good way to introduce bugs. A well structured application doesn't need to use this feature.

Modules should be treated as "black boxes", and are best used for large blocks of related code. Lots of "public" data, and heavy use of the UseModule feature, means that the modules are fragmented and need to be combined in a way that will simplify the overall structure of the application.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
Deluxe0321
User
User
Posts: 69
Joined: Tue Sep 16, 2008 6:11 am
Location: ger

Re: Modules. What are they!?

Post by Deluxe0321 »

@User_Russian: Thank you for the link!

Black Box or not, this behavior is rather strange im my opinion.
So now I have to do a workarround like this in order to get it working correctly - more typing than necessary:

Code: Select all

DeclareModule GlobalConst
  #XPATH = "C:\Test\Test\Test\"
EndDeclareModule

DeclareModule foo
  
  #EXT_PATH = GlobalConst::#XPATH + "foo.bar"
  
  Declare.s foo()
  
EndDeclareModule

Module foo
  
  Procedure.s foo()
    ProcedureReturn #EXT_PATH  
  EndProcedure
  
EndModule

Debug foo::foo()
Why can't we have a global namespace to access?
User avatar
TI-994A
Addict
Addict
Posts: 2705
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Modules. What are they!?

Post by TI-994A »

Deluxe0321 wrote:Just a small question. How to make these examples work? Booth examples won't compile..
Hello Deluxe0321. Both the examples fail because the modules were trying to access constants and procedures that are outside their scope. In the second example, the procedure declaration did not match the procedure itself. Here's the working code:

Code: Select all

;the constant #XPATH is in the global
;namespace and is not accessible to modules

#XPATH = "C:\Test\Test\Test\"

DeclareModule foo
  ;removing the reference works
  ;#EXT_PATH = #XPATH + "foo.bar"
  #EXT_PATH = "foo.bar"
  Declare.s foo()
EndDeclareModule

Module foo
  Procedure.s foo()
    ProcedureReturn #EXT_PATH  
  EndProcedure
EndModule

Debug foo::foo()   ;returns foo.bar

Code: Select all

;the procedure DummyT() is in the global
;namespace and is not accessible to modules

Procedure DummyT(a.i,b.i)
  ProcedureReturn a.i + b.i * 2  
EndProcedure

DeclareModule bar
  ;here bar() is declared with parameters
  Declare.i bar(a.i,b.i,c.i)
EndDeclareModule

Module bar
  ;here bar() does not have any parameters
  ;Procedure.i bar()
  Procedure.i bar(a.i,b.i,c.i)
    ProcedureReturn a + b + c
    ;DummyT() is not accessible from here
    ;ProcedureReturn DummyT(a.i,b.i) * c.i
  EndProcedure
EndModule

Debug bar::bar(1, 2 ,3)   ;returns 6
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
Post Reply