Replies: 10 comments 6 replies
-
I'm not a big fan of callbacks, even if I clearly see the different sort of advantages they offer (no states, less conditions in the codebase...). |
Beta Was this translation helpful? Give feedback.
-
I think these callbacks are very important as people try to use raylib to do more and more things. They are going to be the only solutions to some of the problems people face (like reading assets from an archive). I direly need these for some things I have planned. I totally agree that they can be confusing to beginners. I suggest that they be exposed in a sperate header, such as raylib_callbacks.h, that is not included in raylib.h by default. This will make it much harder for beginners to "stumble onto it" and become frustrated. It would also clearly mark it as a more advanced totally optional feature. The important thing is that they are 100% optional. As for security risks, I don't see this as being any different from the security risk in the user's own code. They will have to install the callbacks at compile time, and if they expose something they should not have, then they should have tested it, just like anything else they put in the code they wrote. |
Beta Was this translation helpful? Give feedback.
-
These suggestions are awesome as it opens up a whole set of possibilities. If this is implemented I will use most of it. |
Beta Was this translation helpful? Give feedback.
-
I don't think a regular raylib user would need a trace log callback system. The only possible real application I can think of is if you need to redirect logs on specific platforms.
As an advanced user myself I say yes.
Yes, makes me feel more safe.
Imho in this case the flexibility gain is not worth the simplicity loss.
None, as far as I concern
Memory callbacks could be used only on very specific cases by very advanced users, even tho I'd personally benefit from this (I develop on limited memory embedded boards) I believe it's a bit out of the scope for a game/multimedia library. Anyway, I'd be nice to have.
I'd prefer the second option.
If a user wants a custom implementation then I assume that user do not need a pre-made callback system in the first place. I prefer to keep it simple.
Simplicity and freedom come at a cost: responsibility. |
Beta Was this translation helpful? Give feedback.
-
The main positive I'd see with a callback system as proposed, would be the ability to add, for example, PhysFS to raylib's file loading mechanisms, but that would surely be a more advanced use case. |
Beta Was this translation helpful? Give feedback.
-
I think a config style struct for callbacks is worth considering. The default state can still be set up via macros allowing both use cases to work together. Example usage: // Naming is hard...
ConfigState state = GetConfigState();
state.traceLog = &MyTraceLogCallback;
SetConfigState(state);
InitWindow(1024, 600, "Test window");
// ... |
Beta Was this translation helpful? Give feedback.
-
I love callbacks |
Beta Was this translation helpful? Give feedback.
-
To be honest, I see little point in adding these runtime callbacks when you can easily implement them on top of the compile-time macros like I checked that this is not the case with Of course, I am assuming people using callbacks would already be compiling raylib alongside their project. After all that said, though, it may be nice to have an implementation for it, because people would be more comfortable reading other people's code.
Even as macros, they still have to follow a non-strict signature for the code to compile, so no worries there.
Unless one carelessly puts a pointer for anything other than a function, or one of wrong signature, as callback, no worries as well. If one loads a shared library as a plugin and install some symbol of it as a callback, on the other hand, things can go very wrong. |
Beta Was this translation helpful? Give feedback.
-
Just for completion, here some of my final conclusions. 1. Log messages (traceLog)Some people is already using it and it seems to be useful for some situations. It was already added so it won't be removed. Just note that source code config has preference over the callback, so, if 2. Memory management (memAlloc, memRealloc, memFree)I'm not adding this ones. Advance users requiring custom memory allocators can directly edit the sources and redefine the macros. 3. File access (loadFileData, saveFileData, loadFileText, saveFileText)They are just a must to hook an external file-system, so, they will be added. |
Beta Was this translation helpful? Give feedback.
-
I don't mean to necro this discussion, but I was recently working on a physfs-based custom-filesystem. The current hooks work great for read/write files, but there are still a few functions that have no way to hook (even with macros, as far as I can tell.)
I wouldn't mind overriding these with a macro or a callback-thing, but as it is, I had to add a suffix to the names. In this setup, I am trying to make an API that looks just like raylib, so I would prefer if they all used the original names. |
Beta Was this translation helpful? Give feedback.
-
I open this discussion to organize a bit my ideas about function callbacks in raylib and also allow anyone to comment.
I tried to avoid callbacks usage in raylib since the beginning, I find callbacks complex to understand and use for beginners and they only introduce a new level of complexity and insecurity to the API that most users probably don't need.
Advance users are expected to use raylib directly from sources and tweak the library for their needs, that's the professional way to deal with open source libraries when you are developing a custom product. For those users, raylib offers a set of defines to enable/disable several features but also change some internal configurations. For example, memory allocation/free can be customized just re-defining
RL_MALLOC
/RL_FREE
macros.One callback was introduced some versions ago (
TraceLogCallback
) to redirect log messages at runtime and now I'm considering introducing several more callbacks. Actually, I'm writing this post to organize my ideas around that.Callbacks considered belong to 3 categories:
traceLog
)memAlloc
,memRealloc
,memFree
)loadFileData
,saveFileData
,loadFileText
,saveFileText
)Proposed implementation:
Every category implies some concerns.
1. Log messages (
traceLog
)Actually this callback has already been available for some time,
I didn't know of anyone using it or if it has ever been used.raylib has two
config.h
flags to enable/disable tracelogs:SUPPORT_TRACELOG
: Enables/Disables trace log system.SUPPORT_TRACELOG_DEBUG
: IfSUPPORT_TRACELOG
, enables/disablesLOG_DEBUG
level traces.raylib also defines two macros for custom tracelog functions (require raylib recompilation):
TRACELOG(level, ...)
: If not defined by user, it maps to utils->TraceLog()
function.TRACELOGD(level, ...)
: If not defined by user, it maps to utils->TraceLog()
function.I think trace log system is quite flexible if dealing with raylib sources, allowing custom tracelog but, by default, it could not be hook at runtime, that's why a callback was added.
TraceLogCallback
type: Internally definestraceLog
variable.SetTraceLogCallback()
allows setting a customTraceLogCallback
at runtime.traceLog
callback is checked when callingTraceLog()
function mapped byTRACELOG()
/TRACELOGD()
macros. So, raylib source code configuration will prevail overtraceLog
runtime callback. Some points to think about here:TraceLogCallback
must follow a fixed signature, what about if users wants a custom tracing implementation?TRACELOG
macro supports that option...2. Memory management (
memAlloc
,memRealloc
,memFree
)raylib has been redesigned to improve memory management for some versions now. Actually, some custom functions were even added not long ago to expose raylib internal memory allocators, in case users need them.
raylib defines several macros for custom memory allocators (require raylib recompilation):
RL_MALLOC(sz)
: If not defined by user, it maps to system functionmalloc(sz)
.RL_CALLOC(n,sz)
: If not defined by user, it maps to system functioncalloc(n,sz)
.RL_REALLOC(ptr,sz)
: If not defined by user, it maps to system functionrealloc(ptr,sz)
.RL_FREE(ptr)
: If not defined by user, it maps to system functionfree(ptr)
.Users can customize memory allocators just redefining those macros and recompiling raylib.
Lately some functions were also added to expose the value of those macros:
MemAlloc()
: It internally callsRL_MALLOC()
.MemRealloc()
: It internally callsRL_REALLOC()
.MemFree()
: It internally callsRL_FREE
.At this moment I'm considering adding some additional callbacks:
MemAllocCallback
type: Internally definesmemAlloc
callback variable.MemReallocCallback
type: Internally definesmemRealloc
callback variable.MemFreeCallback
type: Internally definesmemFree
callback variable.Some points to think about here:
MemAlloc()
actually check ifmemAlloc
is defined and use it?memAlloc
replaceRL_MALLOC()
, which one should have priority?memAlloc
be allowed to be changed in the middle of a program execution??? Without going into details yet, that does not sound very nice to me...memAlloc
be hook before raylib initialization (like other libraries do)?MemAllocCallback
must follow a fixed signature, what about if users wants a custom implementation?RL_MALLOC
macro supports that option...3. File access (
loadFileData
,saveFileData
,loadFileText
,saveFileText
)raylib file access system has also been redesigned in raylib in the last versions to load data from memory, centralizing all file access into 4 functions in the
utils
module, so, almost all file loading/saving in raylib ends up using:LoadFileData()
: Loads file data into memory and returns data buffer + byte size.LoadFileText()
: Load file as text into memory and returns text data buffer + byte size.SaveFileData()
: Save data buffer into a binary file.SaveFileText()
: Save text data buffer into a text file.This category has no macros to allow replacing those functions, so, callback implementation could be very useful. Probably the most common usage scenario is loading/saving data from a custom file-system (i.e. a ZIP file, memory, network...).
The callbacks considered for this case are:
LoadFileDataCallback
type: Internally definesloadFileData
callback variable.SaveFileDataCallback
type: Internally definessaveFileData
callback variable.LoadFileTextCallback
type: Internally definesloadFileText
callback variable.SaveFileTextCallback
type: Internally definessaveFileText
callback variable.Those callback objects are checked inside every relative function (i.e.
loadFileData
checked onLoadFileData()
function) and, in case the callback has been defined, the callback is executed before the default implementation.Actually, one improvement over it could be creating a flag (
SUPPORT_STANDARD_FILEIO
) to avoid the default implementation on compilation, that way, it would be possible to just omitstdio
library requirement (i.e. using a custom clib implementation). b084552Again, several points pop into my mind to think about:
LoadFileDataCallback
must follow a fixed signature, what about if users wants a custom implementation?Ok, so, that's it, now it's time to think about it and try to find a balanced solution.
Beta Was this translation helpful? Give feedback.
All reactions