Page 1 of 2

Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Wed Oct 08, 2025 4:14 pm
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.

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Wed Oct 08, 2025 9:26 pm
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

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 1:20 am
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"

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 3:20 am
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

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 4:11 am
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

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 5:51 am
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 ?

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 6:23 am
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

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 7:01 am
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

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 5:41 pm
by Demivec
Why not just modify each library to use a named enumeration in a common module?

Everything else that had been suggested tries to avoid modifying the libraries to be consistent. I think that is a recipe for disaster. Why not just fix the inconsistencies where they occur?

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 6:29 pm
by Webarion
Demivec wrote: Thu Oct 09, 2025 5:41 pm Why not just modify each library to use a named enumeration in a common module?

Everything else that had been suggested tries to avoid modifying the libraries to be consistent. I think that is a recipe for disaster. Why not just fix the inconsistencies where they occur?
What catastrophe are you talking about? I don't see any catastrophe when everything works correctly without needing to modify someone else's code.

Yes, we could fix it ourselves, but that's unprofessional.
The correct principle is this: modifying the core of someone else's code is a bad sign and wrong approach, especially if the library has specific licensing terms. With each new update from the author, you'd have to make all the corrections again. This isn't how things are done in professional programming. Libraries from different authors shouldn't conflict due to a poorly designed compiler core - all events should always be unique.

We currently have a conflict between libraries regarding custom events that use Enumeration #PB_Event_FirstCustomValue, and this needs to be resolved at the compiler level.

Moreover, if the compiler automatically increments #PB_Event_FirstCustomValue with each Enumeration #PB_Event_FirstCustomValue, it would prevent such conflicts while maintaining compatibility with all existing libraries written in the past.

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Thu Oct 09, 2025 7:29 pm
by Demivec
I'll preface my remarks by saying I understand there is more than one way to view the issue that motivated your feature request.

Webarion wrote: Thu Oct 09, 2025 6:29 pm
Demivec wrote: Thu Oct 09, 2025 5:41 pm Why not just modify each library to use a named enumeration in a common module?

Everything else that had been suggested tries to avoid modifying the libraries to be consistent. I think that is a recipe for disaster. Why not just fix the inconsistencies where they occur?
What catastrophe are you talking about? I don't see any catastrophe when everything works correctly without needing to modify someone else's code.

Yes, we could fix it ourselves, but that's unprofessional.
The correct principle is this: modifying the core of someone else's code is a bad sign and wrong approach, especially if the library has specific licensing terms. With each new update from the author, you'd have to make all the corrections again. This isn't how things are done in professional programming. Libraries from different authors shouldn't conflict due to a poorly designed compiler core - all events should always be unique.
First, there is source code (that's what will be effected by your feature) available to make any needed changes. If there is a licensing issue then abide by the license and contact the authors about the needed changes. If the author changes the code it can perpetuate to future releases.

The issue with needing unique events is that it needs a unified approach. Because different hypothetical libraries assumed they were the only ones running they did not provide a way for other code to know what events were used. They could of provided a parameter to there own routines that designates a initial value for custom events and an additional way to know what events they reserved for their own use. In other words they need a cooperative and unified approach.

The feature request takes the approach of changing things for all code to get what you need instead of having people code with the understanding that for their libraries to be more useful they should code them differently.

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Fri Oct 10, 2025 6:29 am
by jacdelad
There must be a reason why this question raises up from time to time by new users (including me some years ago). And also, why after explaining the way it is done now is questioned.

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Fri Oct 10, 2025 2:07 pm
by Demivec
jacdelad wrote: Fri Oct 10, 2025 6:29 am There must be a reason why this question raises up from time to time by new users (including me some years ago). And also, why after explaining the way it is done now is questioned.
It is a common situation that arises not only with custom events but also with enumeration of any type of purebasic objects like fonts, windows, etc. One way of dealing with it is to avoid enumerations of PureBasic objects and instead make use of #PB_Any to generate object numbers. The other way is to use a common module and named enumerations. Link: https://www.purebasic.fr/english/viewtopic.php?t=77085

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Fri Oct 10, 2025 3:01 pm
by jacdelad
IMO this information should be offered in the help file. The common module should be explained there too.

Re: Preventing PB_Event_FirstCustomValue Clashes Between Independent Libraries

Posted: Fri Oct 10, 2025 3:20 pm
by Webarion
There must be a reason why this question raises up from time to time by new users (including me some years ago). And also, why after explaining the way it is done now is questioned.
I'm actually a long-time user, though I'm not very active on the forum.

The reason is that this problem still hasn't been resolved.

No problems arise when you're writing your own final program and not using conflicting libraries. However, issues emerge during the planning stage when creating tools (libraries) for other programmers.

I respect the work of other people - both the developers who create tools for others, and those who will use my tools. That's why, right from the planning stage of my idea, I don't want my products to conflict with those of other authors.

Yes, in PB we have a flexible tool for other objects like #PB_Any, and it's the correct tool that should always be used when you write libraries for other users.

However, for Event Custom Value there is no such flexible tool.

At the same time, PB does have constants that are exceptions to the rules and deviate from the main principle.
The rule states: "A constant is a fixed, unchangeable value."

Yet we already have an exception to the constant rules: #PB_Compiler_EnumerationValue. This constant, at the compiler level, changes its value:

Code: Select all

Enumeration
  #Const1
   #Const2
EndEnumeration
Debug #PB_Compiler_EnumerationValue

Enumeration
  #Const3
EndEnumeration
Debug #PB_Compiler_EnumerationValue
So we already have one exception to the main rule about constants. Why not make another allowance (exception to the rule) for #PB_Event_FirstCustomValue? Or implement a new dynamic compiler-level constant, for example: #PB_Event_NextCustomValue.

My verdict is this: using #PB_Event_FirstCustomValue is very inconvenient for those who create tools (libraries) for others. And the end application developer might encounter the problem of event overlapping (event conflicts) when using various libraries that contain Custom Events.

For now, when creating my own tools (libraries), I use random numbers for events, for example:

Code: Select all

Enumeration MyLib1_Events #PB_Event_FirstCustomValue + 871653
  #MyLib1_Event1
EndEnumeration
...
Enumeration MyLib2_Events #PB_Event_FirstCustomValue + 753865
  #MyLib2_Event1
EndEnumeration
This still remains a patch, a kludge in the code, hoping that no other author will use the same event numbers in their libraries.

P.S. For clarity: in all my messages in this thread, when I use the term "tools", I am not referring to tools that are created for the IDE itself. I use this term to mean components that you develop for other programmers, such as libraries, processors, frameworks, and similar things.