Is there a guide for developing modules?

Everything else that doesn't fall into one of the other PB categories.
Zach
Addict
Addict
Posts: 1675
Joined: Sun Dec 12, 2010 12:36 am
Location: Somewhere in the midwest
Contact:

Is there a guide for developing modules?

Post by Zach »

Hi,

I was wondering if anyone has written a guide about good practices for developing modular code. I've kind of been interested in modules since the feature was introduced, but I know very little about them and how they are intended to be used. I am assuming it is for developing self-contained "libraries" that you can use from within your program that would be re-usable across many projects and are meant to be entirely self contained?

I suppose I am most curious about developing modular code that can access / modify / share data with other parts of the programs, perhaps other modules, and what that might look like / require... Is there a way to do this without using a lot of globals, or some kind of array or other structured storage medium to read info in / out as a means of passing it around?

If anyone could give me a brief education about modules and developing modular code; good practices when doing so, etc.. That would be cool. But a guide/tutorial of some sort would be super if one exists. The help CHM is kind of terse in its description; and I learn easiest from examples of real word stuff, focused on a specific task or end-goal :oops: . It doesn't need to be anything fancy using pointers and stuff though.
User avatar
idle
Always Here
Always Here
Posts: 5839
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Is there a guide for developing modules?

Post by idle »

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 
 
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Is there a guide for developing modules?

Post by Demivec »

Nice outline idle. :)
idle wrote:Step 3)
write your procedures where the first parameter is as an instance to the structure

Code: Select all

  Procedure  SetModel(Car,Model.s) 
    Protected *car.car   ;use a pointer to access a car    
    If car 
      *car = car    ;cast the car parameter to a pointer 
      *car\Model = model     
    EndIf    
  EndProcedure
A slight simplification on this idea:

Code: Select all

Procedure  SetModel(*car.car,Model.s) 
  If *car 
    *car\Model = model     
  EndIf    
EndProcedure 
User avatar
idle
Always Here
Always Here
Posts: 5839
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Is there a guide for developing modules?

Post by idle »

yes it is better that way Demivec, I was trying to show that it's no different than
working with regular PB commands with objects. Hiding the fact that it's actually a pointer
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2137
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: Is there a guide for developing modules?

Post by Andre »

Hi friends,

nice idea and thanks for your effort! :D

I see here potential for a little 'modules' chapter in the 'beginners section' of the PB manual, if you agree and probably improve the description/examples a bit more....

I will see - but already now thanks again!
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
Zach
Addict
Addict
Posts: 1675
Joined: Sun Dec 12, 2010 12:36 am
Location: Somewhere in the midwest
Contact:

Re: Is there a guide for developing modules?

Post by Zach »

Thank you, I will be sure and read this several times and try to learn from it 8)
User avatar
bembulak
Enthusiast
Enthusiast
Posts: 575
Joined: Mon Mar 06, 2006 3:53 pm
Location: Austria

Re: AW: Is there a guide for developing modules?

Post by bembulak »

Nice examples and great explanations. Thanks for sharing! :)
cheers,

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

Re: Is there a guide for developing modules?

Post by davido »

Thanks everyone for the examples - very interesting. :D
DE AA EB
User avatar
idle
Always Here
Always Here
Posts: 5839
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Is there a guide for developing modules?

Post by idle »

Andre wrote:Hi friends,

nice idea and thanks for your effort! :D

I see here potential for a little 'modules' chapter in the 'beginners section' of the PB manual, if you agree and probably improve the description/examples a bit more....

I will see - but already now thanks again!
Yes it could be used as a basis for a modules chapter, though it's not particularly illustrative of the overall capabilities of modules
and it would probably require a bit of debate to decide what's actually best practice. Much of it depends on what the goal is.

Take my BitModule as an example.
http://www.purebasic.fr/english/viewtop ... 40&t=57409

It provides a number of bit based data structures BitArray, BitVector, BloomFilter and BitTrie which are wrapped
in a module to hide the private functions and enumerations plus provide a logical grouping of the data structures
as a "module". The data structures all have a common base structure and a number of functions in common
which led to the choice of an object orientated implementation which also has the added benefit of exporting
the public functions from the modules namespace via their interfaces.
Whether it's a good example of best practice is debatable but an object design pattern meshes well with modules
and removes the need to dereference the namespace every time you want to access a member of the module
instead a user only has to deal with the interface and constructor and avoids the issues of usemodule
which may lead to some confusion
Windows 11, Manjaro, Raspberry Pi OS
Image
Barbarossa
User
User
Posts: 47
Joined: Fri Oct 12, 2012 8:50 am

Re: Is there a guide for developing modules?

Post by Barbarossa »

Sorry to dig up this thread but I recently discovered modules and started using them.

What is particulary handy is the UseModule command.
Because then you don't have to use the long names anymore.
Module::MyProcedure() becomes MyProcedure()

HOWEVER: when you do this the IDE doesn't recognize the procedures anymore so you don't have autocomplete and parameter help when you type. It seems that this defeats the purpose of having the UseModule command altogether. Or am I missing something here?

John
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Is there a guide for developing modules?

Post by Kwai chang caine »

Nearly OOP :shock:
Thanks IDLE... 8)
ImageThe happiness is a road...
Not a destination
Post Reply