Page 1 of 3

Modules. What are they!?

Posted: Thu Jul 18, 2013 3:27 pm
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!

Re: Modules. What are they!?

Posted: Thu Jul 18, 2013 3:28 pm
by WilliamL

Re: Modules. What are they!?

Posted: Thu Jul 18, 2013 3:32 pm
by User_Russian

Re: Modules. What are they!?

Posted: Thu Jul 18, 2013 3:41 pm
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

Re: Modules. What are they!?

Posted: Thu Jul 18, 2013 8:39 pm
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:

Re: Modules. What are they!?

Posted: Thu Jul 18, 2013 9:37 pm
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

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 2:51 am
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

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 7:46 am
by c4s
@citystate
UnuseModule is optional. In your second example must be called.

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 10:05 am
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.

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 10:17 am
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.

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 1:44 pm
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!

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 1:53 pm
by User_Russian

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 2:31 pm
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.

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 2:59 pm
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?

Re: Modules. What are they!?

Posted: Fri Jul 19, 2013 3:08 pm
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