Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Webarion
User
User
Posts: 35
Joined: Tue Sep 14, 2021 8:50 pm

Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by Webarion »

Hello! Is there any solution to eliminate conflicts between custom events in different independent libraries?

The authors of various libraries cannot know which libraries the final application developer will use in their product. Therefore, using #PB_Event_FirstCustomValue in a library's Enumeration can eventually lead to conflicts and bugs.

It's possible to create a unified library for dynamic event registration, but ultimately, many developers won't use it. Thus, this problem needs to be solved at the compiler level.

At the compiler level, there should be a general rule for dynamically adding events. I suggest implementing a rule something like this: if the code contains an assignment of the constant Enumeration #PB_Event_FirstCustomValue or something like #LibEvent = #PB_Event_FirstCustomValue, then automatically increment #PB_Event_FirstCustomValue by 1.

Code: Select all

; Independent library number 1 from one author
Enumeration #PB_Event_FirstCustomValue ; the first time this combination is called #PB_Event_FirstCustomValue = 65536
  #Library1_Event1
  #Library1_Event2
  #Library1_Event3
EndEnumeration
; The compiler, when encountering the combination Enumeration #PB_Event_FirstCustomValue, here in EndEnumeration, the compiler must set #PB_Event_FirstCustomValue = #PB_Compiler_EnumerationValue

; ...

; Independent library number 2 from the second author
Enumeration Library2_Event #PB_Event_FirstCustomValue
  #Library2_Event1
  #Library2_Event2
  #Library2_Event3
EndEnumeration

; ...

; Independent library number 3 from the third author
Enumeration #PB_Event_FirstCustomValue ; This is the third challenge of this combination and here #PB_Event_FIRSTCURTOMVALUE should be 65542
  #Library3_Event1
  #Library3_Event2
  #Library3_Event3
EndEnumeration

; ...

; Independent library number 4 from another author
#Library4_Event1 = #PB_Event_FirstCustomValue + 1
; The compiler, encountering the equation #MyConst = #PB_Event_FirstCustomValue, must set #PB_Event_FirstCustomValue + 1
Or, perhaps it would be better to add a #PB_Event_NextCustomValue constant to the compiler, which would have an incrementing value, similar to how #PB_Compiler_EnumerationValue holds a different value after EndEnumeration. Although, this will reduce compatibility with older code. It is better, of course, to increase the value of #PB_Event_FirstCustomValue.

When creating a library and using events, we could set a random number for our custom events:

Code: Select all

Enumeration Event #PB_Event_FirstCustomValue + 300000
  #MyLib_Event1
  #MyLib_Event2
  #MyLib_Event3
EndEnumeration
However, this is not the correct approach. While this method reduces the probability of conflicts between libraries, it does not guarantee their absence. It's still possible that a library from another author might use the same event numbers.
User avatar
idle
Always Here
Always Here
Posts: 5976
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by idle »

there is #PB_Compiler_EnumerationValue so that could be used like this, assuming your compiling the libs or modules

Code: Select all

Enumeration #PB_Event_FirstCustomValue ; the first time this combination is called #PB_Event_FirstCustomValue = 65536
  #Library1_Event1
  #Library1_Event2
  #Library1_Event3
EndEnumeration

Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue) ; the first time this combination is called #PB_Event_FirstCustomValue = 65536
  #Library2_Event1
  #Library2_Event2
  #Library2_Event3 
EndEnumeration

Debug #Library1_Event3 
Debug #Library2_Event1
Webarion
User
User
Posts: 35
Joined: Tue Sep 14, 2021 8:50 pm

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by Webarion »

idle wrote: Wed Oct 08, 2025 9:26 pm there is #PB_Compiler_EnumerationValue so that could be used like this, assuming your compiling the libs or modules

Code: Select all

Enumeration #PB_Event_FirstCustomValue ; the first time this combination is called #PB_Event_FirstCustomValue = 65536
  #Library1_Event1
  #Library1_Event2
  #Library1_Event3
EndEnumeration

Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue) ; the first time this combination is called #PB_Event_FirstCustomValue = 65536
  #Library2_Event1
  #Library2_Event2
  #Library2_Event3 
EndEnumeration

Debug #Library1_Event3 
Debug #Library2_Event1
When I create and use my own libraries, there's no problem. However, this is about libraries from different authors that shouldn't conflict with each other.

Your example - it's better not to do it this way, as it could cause event collisions from different third-party libraries, because libraries might have multiple enumerations. A good solution that's compatible with legacy code is to increment #PB_Event_FirstCustomValue at the compiler level, similar to how it's done with #PB_Compiler_EnumerationValue.

Code: Select all

; File "Lib1.pbi" - library from another author
Enumeration #PB_Event_FirstCustomValue
#Library1_Event1
#Library1_Event2
#Library1_Event3
EndEnumeration

Enumeration Lib1_Const
#Lib1_Const1
#Lib1_Const2
EndEnumeration

; ... ... ...

; File "Lib2.pbi" - library from another author
; After #Lib1_Const2 from the first library Lib1.pbi, the following will create event number collisions:
Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue)
#Library2_Event1
#Library2_Event2
#Library2_Event3
EndEnumeration

Debug #Library1_Event3
Debug #Library2_Event1

; ... ... ...

; final product developer's program
XIncludeFile "Lib1.pbi"
XIncludeFile "Lib2.pbi"
XIncludeFile "Lib3.pbi"
XIncludeFile "Lib4.pbi"
XIncludeFile "Lib5.pbi"
User avatar
idle
Always Here
Always Here
Posts: 5976
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by idle »

It's how you would do it in the compiler so that the constant increments automatically.
#pb_compiler_Enumeration increments as enums are added so you can do the same to the include files to resolve the issue via find and replace where ever #pb_event_first_customvalue is
Webarion
User
User
Posts: 35
Joined: Tue Sep 14, 2021 8:50 pm

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by Webarion »

idle wrote: Thu Oct 09, 2025 3:20 am It's how you would do it in the compiler so that the constant increments automatically.
#pb_compiler_Enumeration increments as enums are added so you can do the same to the include files to resolve the issue via find and replace where ever #pb_event_first_customvalue is
#PB_Compiler_EnumerationValue depends on each Enumeration block

Code: Select all

Enumeration
#const1
#const2
#const3
EndEnumeration
Debug #PB_Compiler_EnumerationValue

Enumeration
#const4
#const5
#const6
EndEnumeration
Debug #PB_Compiler_EnumerationValue
Regarding #PB_Event_FirstCustomValue, I think it's not too difficult either - we could make the compiler find these constant assignment lexemes. This is a more complex approach but it's the most compatible with legacy code.

When the compiler encounters this type of assignment, it increments the constant. During compilation and token collection, this is just a variable; when the compiler sees the required expression, it simply substitutes the corresponding incremented expression for the constant.

Options for direct assignment definition:
* #MyEvent = #PB_Event_FirstCustomValue
* #MyEvent = #PB_Event_FirstCustomValue + #OtherConst ; here #PB_Event_FirstCustomValue = #PB_Event_FirstCustomValue + #OtherConst

Options for definition via Enumeration:
* Enumeration PB_Event_FirstCustomValue
* Enumeration MyEvent #PB_Event_FirstCustomValue
* Enumeration MyEvent #PB_Event_FirstCustomValue + #OtherConst

After EndEnumeration #PB_Event_FirstCustomValue = #PB_Compiler_EnumerationValue

There's a second approach that's less complex but also less compatible with legacy code.
We could initially create a counter inside the compiler: NEXT_EV_CUSTOM_VALUE = PB_Event_FirstCustomValue - 1
And also introduce a new compiler-level command, for example GetNextEventCustomValue().
As a result, when the compiler encounters the GetNextEventCustomValue() token while processing code, it sets the constant to NEXT_EV_CUSTOM_VALUE and then increments the NEXT_EV_CUSTOM_VALUE + 1 counter.
This simple way would allow us to always get a unique event number in any library:

Code: Select all

; File "Lib1.pbi" - library from another author
Enumeration GetNextEventCustomValue() ; - compilation-level command
#Library1_Event1
#Library1_Event2
#Library1_Event3
EndEnumeration

Enumeration Lib1_Const
#Lib1_Const1
#Lib1_Const2
EndEnumeration

; ... ... ...

; File "Lib2.pbi" - library from another author
Enumeration GetNextEventCustomValue() ; - compilation-level command
#Library2_Event1
#Library2_Event2
#Library2_Event3
EndEnumeration
User avatar
idle
Always Here
Always Here
Posts: 5976
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by idle »

The compiler would only need to redefine the constant at EndEnumeration so that #PB_Event_FirstCustomValue increments by #PB_Compiler_EnumerationValue it's an easy fix

Code: Select all

Enumeration #PB_Event_FirstCustomValue 
  #Library1_Event1
  #Library1_Event2
  #Library1_Event3
EndEnumeration

Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue) 
  #Library2_Event1
  #Library2_Event2
  #Library2_Event3 
EndEnumeration

Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue) 
  #Library3_Event1
  #Library3_Event2
  #Library3_Event3 
EndEnumeration

Debug #Library1_Event3 - 65535 
Debug #Library2_Event3 - 65535 
Debug #Library3_Event3 - 65535 

Does this work as you expect as if you enumerated 65535 + 1 to 9 ?
Webarion
User
User
Posts: 35
Joined: Tue Sep 14, 2021 8:50 pm

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by Webarion »

idle wrote: Thu Oct 09, 2025 5:51 am The compiler would only need to redefine the constant at EndEnumeration so that #PB_Event_FirstCustomValue increments by #PB_Compiler_EnumerationValue it's an easy fix

Code: Select all

Enumeration #PB_Event_FirstCustomValue 
  #Library1_Event1
  #Library1_Event2
  #Library1_Event3
EndEnumeration

Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue) 
  #Library2_Event1
  #Library2_Event2
  #Library2_Event3 
EndEnumeration

Enumeration #PB_Event_FirstCustomValue + (#PB_Compiler_EnumerationValue-#PB_Event_FirstCustomValue) 
  #Library3_Event1
  #Library3_Event2
  #Library3_Event3 
EndEnumeration

Debug #Library1_Event3 - 65535 
Debug #Library2_Event3 - 65535 
Debug #Library3_Event3 - 65535 

Does this work as you expect as if you enumerated 65535 + 1 to 9 ?
This won't work correctly because in libraries from different authors, enumeration blocks can be arranged in an unknown order. Therefore, this problem needs to be solved at the compiler level, not at the code level. This is also because all authors won't write their code according to a single template, so this should all be resolved when the compiler builds the program. This doesn't work due to the unknown sequence in the arrangement of enumerations:

Code: Select all

; File Library1.pbi
Enumeration #PB_Event_FirstCustomValue
#Library1_Event1
#Library1_Event2
#Library1_Event3
EndEnumeration

Enumeration
#Library1_Const1
#Library1_Const2
#Library1_Const3
#Library1_Const4
#Library1_Const5
EndEnumeration

; ...

; File Library2.pbi
Enumeration #PB_Event_FirstCustomValue + ( #PB_Compiler_EnumerationValue - #PB_Event_FirstCustomValue )
#Library2_Event1
#Library2_Event2
#Library2_Event3
EndEnumeration

Enumeration
#Library2_Const1
#Library2_Const2
#Library2_Const3
#Library2_Const4
#Library2_Const5
EndEnumeration

#Library2_Const6 = 123

; ...

; File Library3.pbi
Enumeration #PB_Event_FirstCustomValue + ( #PB_Compiler_EnumerationValue - #PB_Event_FirstCustomValue )
#Library3_Event1
#Library3_Event2
#Library3_Event3
EndEnumeration

Debug "#Library1_Event1 = " + #Library1_Event1
Debug "#Library1_Event2 = " + #Library1_Event2
Debug "#Library1_Event3 = " + #Library1_Event3
Debug "---"
Debug "#Library2_Event1 = " + #Library2_Event1
Debug "#Library2_Event2 = " + #Library2_Event2
Debug "#Library2_Event3 = " + #Library2_Event3
Debug "---"
Debug "#Library3_Event1 = " + #Library3_Event1
Debug "#Library3_Event2 = " + #Library3_Event2
Debug "#Library3_Event3 = " + #Library3_Event3
Webarion
User
User
Posts: 35
Joined: Tue Sep 14, 2021 8:50 pm

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Post by Webarion »

Here's a simple and simplified demonstration that this can be done at the compiler level:

Code: Select all

#RegExp = 0

CreateRegularExpression(#RegExp, "\h*(\#?\w+)|(?:\r\n|$)" )

Global NewMap Compile_Constant()

Compile_Constant( LCase("#PB_Event_FirstCustomValue") ) = 65536

Global CompileCode$ = "Enumeration #PB_Event_FirstCustomValue" + #CRLF$ + 
                      "  #Lib1_Event1" + #CRLF$ + 
                      "  #Lib1_Event2" + #CRLF$ + 
                      "  #Lib1_Event3" + #CRLF$ + 
                      "EndEnumeration" + #CRLF$ + #CRLF$ + 
                      
                      "Enumeration" + #CRLF$ + 
                      "  #Lib1_Const1" + #CRLF$ + 
                      "  #Lib1_Const2" + #CRLF$ + 
                      "  #Lib1_Const3" + #CRLF$ + 
                      "EndEnumeration" + #CRLF$ + #CRLF$ + 
                      
                      "Enumeration Lib2_Event #PB_Event_FirstCustomValue" + #CRLF$ + 
                      "  #Lib2_Event1" + #CRLF$ + 
                      "  #Lib2_Event2" + #CRLF$ + 
                      "  #Lib2_Event3" + #CRLF$ + 
                      "EndEnumeration"

Debug "Original Code:" + #CRLF$
Debug CompileCode$


If ExamineRegularExpression(#RegExp, CompileCode$)
  
  Define Find_PB_Event_FirstCustomValue.a = #False
  
  While NextRegularExpressionMatch(#RegExp)
    Define Lexeme$ = LCase( RegularExpressionGroup(#RegExp, 1) )

    If Lexeme$ = "enumeration"

      Define Enum = 0
      NextRegularExpressionMatch(#RegExp)
      Lexeme$ = LCase( RegularExpressionGroup(#RegExp, 1) )
      
      If Lexeme$ = "#pb_event_firstcustomvalue"
        Enum = Compile_Constant( Lexeme$ )
        Find_PB_Event_FirstCustomValue = #True
      ElseIf Lexeme$ = ""
        Find_PB_Event_FirstCustomValue = #False
        Continue
      Else

        NextRegularExpressionMatch(#RegExp)
        Lexeme$ = LCase( RegularExpressionGroup(#RegExp, 1) )
        If Lexeme$ = "#pb_event_firstcustomvalue"
          Enum = Compile_Constant( Lexeme$ )
          Find_PB_Event_FirstCustomValue = #True
        Else
          Continue
        EndIf
        
      EndIf
      
    ElseIf Left( Lexeme$, 1 ) = "#"  
      Compile_Constant( Lexeme$ ) = Enum
      Enum + 1
      
    ElseIf Lexeme$ = "endenumeration" And Find_PB_Event_FirstCustomValue = #True
      Compile_Constant( "#pb_event_firstcustomvalue" ) = Enum
    EndIf

  Wend
EndIf

Debug #CRLF$ + "------------------------------------"
Debug "Compile Constants:" + #CRLF$

ForEach Compile_Constant() ; Let's look at all the collected constants
  Debug MapKey( Compile_Constant() ) + " = " + Compile_Constant()
Next
Post Reply