Modules, conditional compilation, external constants

Just starting out? Need help? Post your questions and find answers here.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Modules, conditional compilation, external constants

Post by luis »

Suppose I want to compile different code inside a module, depending on a external constant value.
Normally I would put the configuration constants in one include.

for example: #lib_debug = 1

If #lib_debug = 1 I want to compile the debug version, else the release version.

Code: Select all

; this is inside libconfig.pbi
#lib_debug = 0

; this is a module of the library, includes libconfig.pbi

DeclareModule test
 Declare proc()
EndDeclareModule

Module test
 
Procedure proc()
 ; common code start
CompilerIf #lib_debug = 0    
    ; release code
CompilerElse
    ;debug code
 CompilerEndIf    
; common code end    
EndProcedure   
 
EndModule

The code above can't be compiled because the constant is not accessible.
Note all the constants inside residents are accessible so there is also some kind of disparity here.

Nevertheless, what could be a good solution to implement what described above ? I would like to keep those configuration constants in the include, they are a very straightforward solution to configure an entire library setting some values from a single point included everywhere.

Transform them too into a module to be referred everywhere ? SIGH


EDIT: updated with a better example here -> http://www.purebasic.fr/english/viewtop ... 99#p416699
Still unsolved.

EDIT: solved with BETA 5 thanks to the addition of the #PB_Module constant for the 'Defined' compiler command.
Last edited by luis on Tue Jul 02, 2013 5:10 pm, edited 2 times in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
LuCiFeR[SD]
666
666
Posts: 1033
Joined: Mon Sep 01, 2003 2:33 pm

Re: Modules, conditional compilation, external constants

Post by LuCiFeR[SD] »

could you not just do something like this luis?

Code: Select all

; this is inside libconfig.pbi


; this is a module of the library, includes libconfig.pbi
DeclareModule test
XIncludeFile "DebugConstants.pbi"
 Declare proc()
EndDeclareModule

Module test
 
Procedure proc()
 ; common code start
CompilerIf #lib_debug = 0    
    ; release code
CompilerElse
    ;debug code
 CompilerEndIf    
; common code end    
EndProcedure   
 
EndModule
and just have your Debug constant in that? at least then you can just use the same DebugConstants.pbi and use it globally?
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: Modules, conditional compilation, external constants

Post by freak »

> Transform them too into a module to be referred everywhere ? SIGH

Exactly. What is the problem with that?
quidquid Latine dictum sit altum videtur
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Modules, conditional compilation, external constants

Post by luis »

I can if I know the name of the include.

Currently works as follow:

the user of my lib knows he can customize some of it using specific constants, I set those consts to defaults values when they are not defined.

So if the user does nothing, the lib is compiled in its default configuration.

Now suppose the user set some or all of those consts in his program, or one of his includes, then he includes the main include of my lib an voila', what not defined is set to defaults, the constants set by the user are kept.

So, I should force him to use a specific include, an include of the library and modify that to do what you suggests.

Disadvantages:

he must modify something owned by the lib
he cannot set the constants somewhere in his program or inside one configuration include created by him as he can do now
if the lib has more modules, I have to repeat the include in every module

Now, not using modules, I simple set the constants (or use what defined by the user) as I said in my main include once and we are good to go.

Mffzfzfff.... mffdfdff.... mfmfmm....
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Modules, conditional compilation, external constants

Post by luis »

freak wrote: Exactly. What is the problem with that?
I'm trying to see if that is the better option. So I ask.

The SIGH is for:

another module for something trivial ?

the fact the user (a programmer ok) see that instead of a simple list of constant ?

I try economic programming... don't write something is not needed, less you type the better.

I'm built that way.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Modules, conditional compilation, external constants

Post by idle »

You can always wrap your constants in a declaremodule block
and use usemodule / unusemodule in your lib

Though I don't see why it can't check the context of the module for a constant and if it's not found in that scope
check the global scope for the constant.

Code: Select all

; this is inside libconfig.pbi
DeclareModule Consts
#lib_debug = 123
EndDeclareModule 
; this is a module of the library, includes libconfig.pbi

DeclareModule test
Declare proc()
 
EndDeclareModule

Module test
 
Procedure proc()
   Protected x = 2
   ; common code start
 UseModule Consts 
 CompilerIf #lib_debug = 123    
  x*2 ; release code
CompilerElse
    x*3;debug code
 CompilerEndIf    
 UnuseModule consts 
 
 ProcedureReturn x 
 
; common code end    
EndProcedure   
 
EndModule

Debug test::Proc()

Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Modules, conditional compilation, external constants

Post by luis »

Do you have to make the library user create a module definition, and if he doesn't because he just wants to use the defaults ?
Please look below.

I've put together an example:

library.pb

Code: Select all

CompilerIf Defined(lib_config_1, #PB_Constant) = 0  
  #lib_config_1 = 1 ; default
CompilerEndIf

CompilerIf Defined(lib_config_2, #PB_Constant) = 0  
 #lib_config_2 = 1 ; default
CompilerEndIf

CompilerIf Defined(lib_config_3, #PB_Constant) = 0  
 #lib_config_3 = 0 ; default
CompilerEndIf


Procedure proc() 
 ; common code start
 
CompilerIf #lib_config_1 = 0
    ; some code
CompilerElse
    ;other code
 CompilerEndIf   

CompilerIf #lib_config_3 = 1
    ; some code
CompilerEndIf   

; common code end   
EndProcedure   


user_program.pb

Code: Select all

#lib_config_1 = 0
#lib_config_2 = 0
#lib_config_3 = 1

; the constants above customize the library include that follows

Includefile "library.pb"

proc() 
As I've explained in the other message to Lucifer[SD] the library checks if the constants are defined, use what it finds defined and defines what's not by setting it to default values.

The user of the library, before including it, set some, none, or all the desired constant in order to customize the library compilation.

Neat. Easy to use, easy to follow, easy to implement.



Now, let's try to convert the lib to a module.


library.pb

Code: Select all

DeclareModule lib
 Declare proc()
EndDeclareModule

Module lib

CompilerIf Defined(lib_config_1, #PB_Constant) = 0 
  #lib_config_1 = 1 ; default
CompilerEndIf

CompilerIf Defined(lib_config_2, #PB_Constant) = 0 
 #lib_config_2 = 1 ; default
CompilerEndIf

CompilerIf Defined(lib_config_3, #PB_Constant) = 0 
 #lib_config_3 = 0 ; default
CompilerEndIf


Procedure proc()
 ; common code start
 
CompilerIf #lib_config_1 = 0
    ; some code
CompilerElse
    ;other code
 CompilerEndIf   

CompilerIf #lib_config_3 = 1
    ; some code
CompilerEndIf   

; common code end   
EndProcedure   

EndModule

Now, user_program.pb does not work anymore as expected. Setting the constants is useless because the module does not have access to them. If we had the ability to do so:

Code: Select all

CompilerIf Defined(::lib_config_1, #PB_Constant) = 0 
  #lib_config_1 = 1 ; default
CompilerEndIf
(see the "::" before the constant name) to access the top-level constants the problem would be solved.

Not having that, Freak asked me what's the problem with just defining a module with the constants declared there, like the code above from idle shows.
freak wrote: Exactly. What is the problem with that?
Please consider my case. How do you something like that ? Do you make the user, the author of user_program.pb replace the original code:

Code: Select all

#lib_config_1 = 0
#lib_config_2 = 0
#lib_config_3 = 1

; the constants above customize the library include that follows

Includefile "library.pb"

proc() 

with this ?

Code: Select all

DeclareModule lib_consts
#lib_config_1 = 0
#lib_config_2 = 0
#lib_config_3 = 1
EndDeclareModule

; the constants above customize the library include that follows

Includefile "library.pb"

proc() 

and inside library.pb I use UseModule lib_consts ?

But what if the user does not want to define those constants ? If he doesn't the compiler raise an error on UseModule lib_consts because the module is not defined.

1) Having "Defined" supporting testing for modules I could test if the module lib_consts is defined and if it's not I could define it with the default constants. But this is not available for now. Even so the it would be already a lot less easy to follow compared to the plain original version.

2) The ::#Const_Name to access a top level constant is also not available, and that would be the best solution for this case I believe.
idle wrote: Though I don't see why it can't check the context of the module for a constant and if it's not found in that scope
check the global scope for the constant
or probably better because it's explicit the nameless module "::nameofconst", so we don't risk to access a top-level constant in error.

3) I must tell the user to define an empty DeclareModule lib_consts if he doesn't want to override the defaults ?
Looks like a silly thing to ask compared to the original module-less solution where he had to do nothing at all.

I feel like I'm moving away from a clean solution based on simple constants towards something unnecessary convoluted.
Well, something easily avoidable with at least one of the additions above.

Considering what's available, can I solve this in a manner somewhat equivalent to the original one ?
Last edited by luis on Tue Jul 02, 2013 12:06 pm, edited 3 times in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
helpy
Enthusiast
Enthusiast
Posts: 552
Joined: Sat Jun 28, 2003 12:01 am

Re: Modules, conditional compilation, external constants

Post by helpy »

If the constant is included in an include file, you can work around this.
But if the constants are passed as arguments to the compiler ... I do not know any workaround!

Example code:

Code: Select all

; ------------------------------------------------------
; Constant will be passed as argument to the compiler
;#COMPILE_VARIANT_A = #True
;#COMPILE_VARIANT_B = #True
; ------------------------------------------------------

CompilerIf Defined( COMPILE_VARIANT_A, #PB_Constant )
	Debug "COMPILE_VARIANT_A is defined!"
CompilerEndIf
CompilerIf Defined( COMPILE_VARIANT_B, #PB_Constant )
	Debug "COMPILE_VARIANT_B is defined!"
CompilerEndIf


DeclareModule myTest
	#myTest_Constant_1 = 1
	#myTest_Constant_2 = 2
	
	CompilerIf Defined( COMPILE_VARIANT_A, #PB_Constant )
		#myTest_Variant = "A"
	CompilerElseIf Defined( COMPILE_VARIANT_B, #PB_Constant )
		#myTest_Variant = "B"
	CompilerElse
		#myTest_Variant = "NONE"
	CompilerEndIf
	
	Declare ShowVariant()
EndDeclareModule

Module myTest
	Procedure ShowVariant()
		Debug #myTest_Constant_1
		Debug #myTest_Constant_2
		Debug "VARIANT: " + #myTest_Variant
	EndProcedure
EndModule

Debug "-"

myTest::ShowVariant()

Debug "-"

Debug myTest::#myTest_Constant_1
Debug myTest::#myTest_Constant_2
Debug "VARIANT: " + myTest::#myTest_Variant
Try with commandline:

Code: Select all

pbcompiler.exe test.pb /DEBUGGER /CONSTANT COMPILE_VARIANT_A=1
Result:

Code: Select all

COMPILE_VARIANT_A is defined!
-
1
2
VARIANT: NONE
-
1
2
VARIANT: NONE
Try with commandline:

Code: Select all

pbcompiler.exe test.pb /DEBUGGER /CONSTANT COMPILE_VARIANT_B=1
Result:

Code: Select all

COMPILE_VARIANT_B is defined!
-
1
2
VARIANT: NONE
-
1
2
VARIANT: NONE
Windows 10 / Windows 7
PB Last Final / Last Beta Testing
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Modules, conditional compilation, external constants

Post by Fred »

These constants should be like resident constants and accessible everywhere, I will fix this.
User avatar
helpy
Enthusiast
Enthusiast
Posts: 552
Joined: Sat Jun 28, 2003 12:01 am

Re: Modules, conditional compilation, external constants

Post by helpy »

Thank you Fred! This is great.
Windows 10 / Windows 7
PB Last Final / Last Beta Testing
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Modules, conditional compilation, external constants

Post by idle »

I would have thought all constants should default to the global symbol tables scope unless they're defined or redefined in a module
So the compiler would checks the modules scope -> used modules scope -> global scope.
Windows 11, Manjaro, Raspberry Pi OS
Image
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Modules, conditional compilation, external constants

Post by Fred »

no, auto-fallback to global scope if something isn't found would break the module concept.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Modules, conditional compilation, external constants

Post by luis »

Talking about my original question, better explained with a practical example later in this same thread, someone believing the modules in their current state can gracefully solve the problem can explain how he would implement that ? What mechanism would you make available to the user of the library to configure the conditional compilation since before he was able to do so using some simple constants defined just before the inclusion of the library in his program ?

I've expressed a couple of possible solutions through methods not available at the moments, so if those will not magical appear I'm curios if the only possible options remaining is this: forcing the lib's user to always define the constants inside a specific module just before the inclusion of the lib. Is this the best/only way ?
Last edited by luis on Mon Jul 01, 2013 11:49 pm, edited 1 time in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Modules, conditional compilation, external constants

Post by idle »

Fred wrote:no, auto-fallback to global scope if something isn't found would break the module concept.
It's easy for me to say since I'm not implementing it.
Question, why should there be any difference between residents, constant, enumerations or macros, they are all explicitly
setting up the compile environment and are as such immutable. If you define or redefine a constant in a namespace
the compiler will use that constant in that context or use hierarchical name resolution and fall back to the global,
there is no conflict and it doesn't break the concept of a namespace in my view, plus if I remember correctly C++
uses hierarchical namespace resolution in this case to.
I just think it'd be more user friendly and easier on the eyes to boot.
Food for thought or just Idle being a pain in the neck! :wink:
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Modules, conditional compilation, external constants

Post by skywalk »

I really dislike Declare stuff. Since everything defaults to Private inside a Module..EndModule block, why not add a Public keyword for those elements that would otherwise require a DeclareModule..EndDeclareModule block? Instead of this:

Code: Select all

DeclareModule Vehicule
  #VehiculeConstant  = 10
  #VehiculeConstant2 = 20

  Declare NewAuto(Flags)
  Declare NewBoat()
EndDeclareModule
Put "Public" in here and drop the whole DeclareModule stuff!

Code: Select all

Module Vehicule
  Public #VehiculeConstant  = 10
  Public #VehiculeConstant2 = 20
  #PrivateConstant  = 30

  Procedure Init()
    Debug "Vehicule Init"
  EndProcedure
  
  Public Procedure NewAuto(Flags)
    Init()
    Debug "NewAuto"
  EndProcedure
  
  Public Procedure NewBoat()
    Init()
    Debug "NewBoat"
  EndProcedure
EndModule
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Post Reply