There are a number of recent examples in the tips and tricks section
to get an idea, but what your asking has little to do with modules as such.
You can pretty much turn any code into a module but it's not necessarily going to make it any more modular
and could even make it harder to use.
The goal of modular code is to make your code easier to maintain and easier for someone else to use
so you generally follow an object model and present some interface to the code where the functionality
is more or less independent of how you use it and it often comes at a cost
requiring more code and a slight hit in performance. (wrap the crap)
For instance lets say you want to create a collection of cars
you have a choice of implimentation to either use heap memory, a list, array or map to store the instances
of a car structure. Each method has it's pros and cons but importantly the implementation
doesn't effect how you present the code to the user.
All you do is combine the data and functions together by eliminating the globals adding them to a structure
and pass instances of the structure to your procedures, that's it in a nutshell.
You can use a flat object model like the PB does or Interfaces it's a personal choice
but from a maintenance, extensibility and modification point of view using Interfaces
is a clear winner since it not only clearly presents a user friendly interface it
also allows you to turn your code into a dll with no effort plus facilitates name space resolution
via the public interface if it's bunged into a module.
Even though Modules in PB more or less allows you to turn any code into a black box
without effort and avoid name conflicts plus isolate your code it doesn't make it any easier to use
that code. So modules should be seen as an aid not a magic solution.
5% of a modules behaviour just prefixes the modules members in the final assembly code
and the other 95% is compiler abstractions to appear as if the codes in a black box
which is all good but its just a compiler trick.
So given that rant.
Step 1)
Eliminate global's by adding them into a logical structure
Code: Select all
;global Make.s,Model.s,ChassisType.i ...
Structure car
Make.s
Model.s
ChassisType.i
...
EndStructure
Global NewList glcar.Car() ;use a list to hold instances
Step 2)
provide a means to create an instance of the structure and return the instance
Code: Select all
Procedure New_Car()
AddElement(glcar())
ProcedureReturn glcar()
EndProcedure
Step 3)
write your procedures where the first parameter is as an instance to the structure
Code: Select all
Procedure SetModel(Car,Model.s) ;Notice it looks like a regular PB object function
Protected *car.car ;where the ID will be cast to a pointer to access a car
If car
*car = car ;cast the car parameter to a pointer
*car\Model = model ;set the model
EndIf
EndProcedure
Procedure.s GetModel(*car.car) ;Though it's better to use a pointer directly as a parameter
If *car ;which also will make it compatible with an interface should you choose to add one
ProcedureReturn *car\Model
EndIf
EndProcedure
step 4)
wrap it in a module
Code: Select all
DeclareModule mCar
;A collection of cars
Declare New_Car() ;create a new instance of a car
Declare SetModel(car,model.s) ;set a cars model
Declare SetMake(car,Make.s) ;set a cars make
Declare.s GetModel(car) ;get a cars model
Declare.s GetMake(car) ;get a cars make
Declare Find(make.s,model.s) ;find a car from a make and model returns a car instance
EndDeclareModule
Module mCar
;impliment the module
;all members here are private unless they're delcared in the declaremodule block
Enumeration 1
#gear_manual
#gear_auto
EndEnumeration
Enumeration 1
#metric
#Imperial
EndEnumeration
Structure car ;a car
Model.s
Make.s
ChassisType.i
Bhp.i
TopSpeed.i
NumberOfGears.i
GearBoxType.i
units.i
EndStructure
Global NewList glcar.Car()
Procedure New_Car() ;adds an element to the collection returns the element in the list
AddElement(glcar())
ProcedureReturn glcar()
EndProcedure
Procedure SetModel(Car,Model.s) ;Notice it looks like a regular PB object function
Protected *car.car ;where the ID will be cast to a pointer to access a car
If car
*car = car ;cast the car parameter to a pointer
*car\Model = model ;set the model
EndIf
EndProcedure
Procedure.s GetModel(*car.car) ;Better to use a pointer directly as a parameter
If *car ;which will then make it compatible with an interface
ProcedureReturn *car\Model
EndIf
EndProcedure
Procedure SetMake(*car.car,make.s)
If *car
*car\Make = make
EndIf
EndProcedure
Procedure.s GetMake(*car.car)
If *car
ProcedureReturn *car\Make
EndIf
EndProcedure
Procedure Find(make.s,model.s)
ForEach glCar() ;search for a car by make and model
If glcar()\make = make And glcar()\Model = model
ProcedureReturn glcar() ;returns the element
EndIf
Next
EndProcedure
EndModule
use it
Code: Select all
Global car1,car2,car3,car4
UseModule mCar
car1 = New_Car()
SetModel(car1,"308")
SetMake(car1,"Ferrari")
car2 = New_Car()
SetModel(car2,"911")
SetMake(car2,"Porche")
car3 = New_Car()
SetModel(car3,"500")
SetMake(car3,"fiat")
Debug GetMake(car1) + " " + GetModel(car1)
Debug GetMake(car2) + " " + GetModel(car2)
Debug GetMake(car3) + " " + GetModel(car3)
car4 = find("Porche","911")
If car4
Debug GetMake(car4) + " " + GetModel(car4)
EndIf