BSL:String comparison: Difference between revisions
(Let's trample some hopes...) |
m (copy-edit) |
||
Line 1: | Line 1: | ||
Even though the topic is a bit complicated, the key conclusion is that [[BSL]] does '''not''' reliably support string comparison. It is strongly advised to '''not''' rely on string comparison in your BSL scripts. | |||
Even though the topic is a bit | |||
It is strongly advised to '''not''' rely on string comparison in BSL scripts. | ==Introduction== | ||
As a lot of scripters already know, BSL seemingly allows string comparison, meaning it looks like the language should be capable of processing syntax similar to the following one: | |||
<pre> | <pre> | ||
func void some_ai_died(string ai_name){ | func void some_ai_died(string ai_name) | ||
if (ai_name eq "A_t48") { | { | ||
if (ai_name eq "A_t48") | |||
{ | |||
dmsg("A_t48 died!"); | dmsg("A_t48 died!"); | ||
} | } | ||
else { | else | ||
{ | |||
dmsg("Some other AI died!"); | dmsg("Some other AI died!"); | ||
} | } | ||
Line 16: | Line 18: | ||
</pre> | </pre> | ||
However, string comparison appears to be a bit unreliable | However, string comparison appears to be a bit unreliable — sometimes it looks like it works, sometimes it does not. But why? The following research is an attempt to find the answer. | ||
But why? The following research is an attempt to find the answer. | |||
==Test setup== | ==Test setup== | ||
A test was set in the | A test was set up in the first savepoint of EnvWarehouse. | ||
The test | The test was composed of:<br/> | ||
# A test subject ("A_t48" | # A test subject (the "A_t48" AI character) and its slightly modified death function "t48_dead(string ai_name)". | ||
# A global BSL string variable "BOB_string". | # A global BSL string variable "BOB_string". | ||
# A lot of wasted time while searching for all those damned addresses ^_^. | # A lot of wasted time while searching for all those damned addresses ^_^. | ||
The test was set as follows: | The test was set as follows: | ||
# There is a global BSL variable "BOB_string". | # There is a global BSL variable "BOB_string". The init value of the variable is the string literal "A_t48". The variable can be set via various BSL functions to one of these string literals: "A_t40", "A_t41", "A_t42". | ||
# There is a BSL function | # There is a BSL function "t48_dead(string ai_name)". This function is called by the engine when the AI character "A_t48" dies. | ||
# Inside the | # Inside the function t48_dead(), there is an immediate comparison of "ai_name" and "BOB_string". | ||
# After | # After about 5 seconds, "BOB_string" is set to be the same as "ai_name" and another comparison attempt is made. | ||
==Test results== | ==Test results== | ||
Please see the enclosed series of figures. | Please see the enclosed series of figures. Figures show a relevant selection of runtime memory data. | ||
Figures show a relevant selection of | |||
# Data regarding global variable "BOB_string". | |||
#: [[Image:BSL-strcmp-01 gbStrVar-Ptr.png|256px]] [[Image:BSL-strcmp-02 gbStrVar-PointedMemory.png|256px]] | |||
# Data regarding local variable "ai_name" (relevant only during the execution of the t48_dead() function). | |||
#: [[Image:BSL-strcmp-03 ainame-Ptr.png|256px]] [[Image:BSL-strcmp-04 ainame-PointedMemory.png|256px]] | |||
# State of memory at the moment when the string comparison was evaluated the first time (as 'false') and the second time (as 'true'). | |||
#: [[Image:BSL-strcmp-05 comparison-false.png|256px]] [[Image:BSL-strcmp 06 comparison-true.png|256px]] | |||
==Conclusion== | ==Conclusion== | ||
# BSL string | # A BSL string variable seems to be stored as a C string; no additional special characters, simply a stream of bytes till the first 0x00 byte (null terminator). | ||
# If there are several | # When keeping track of a BSL string, Oni thus uses a '''pointer''' to the given C string. | ||
# If there are several independent strings which by chance contain the same text (e.g. "A_t48"), the engine still keeps separate instances of these strings (no string reuse to save memory, or any similar technique). | |||
# When | # When string comparison is attempted, it is most likely that the values of the pointers themselves (the memory addresses) are being compared, not the contents of the strings themselves. | ||
# | # Since the engine allocates memory for local BSL variables and function arguments on demand, the address of a string such as "ai_name" will differ in each runtime session and cannot be expected at a particular position. | ||
[[Category:BSL docs]] | [[Category:BSL docs]] |
Latest revision as of 14:46, 3 April 2021
Even though the topic is a bit complicated, the key conclusion is that BSL does not reliably support string comparison. It is strongly advised to not rely on string comparison in your BSL scripts.
Introduction
As a lot of scripters already know, BSL seemingly allows string comparison, meaning it looks like the language should be capable of processing syntax similar to the following one:
func void some_ai_died(string ai_name) { if (ai_name eq "A_t48") { dmsg("A_t48 died!"); } else { dmsg("Some other AI died!"); } }
However, string comparison appears to be a bit unreliable — sometimes it looks like it works, sometimes it does not. But why? The following research is an attempt to find the answer.
Test setup
A test was set up in the first savepoint of EnvWarehouse.
The test was composed of:
- A test subject (the "A_t48" AI character) and its slightly modified death function "t48_dead(string ai_name)".
- A global BSL string variable "BOB_string".
- A lot of wasted time while searching for all those damned addresses ^_^.
The test was set as follows:
- There is a global BSL variable "BOB_string". The init value of the variable is the string literal "A_t48". The variable can be set via various BSL functions to one of these string literals: "A_t40", "A_t41", "A_t42".
- There is a BSL function "t48_dead(string ai_name)". This function is called by the engine when the AI character "A_t48" dies.
- Inside the function t48_dead(), there is an immediate comparison of "ai_name" and "BOB_string".
- After about 5 seconds, "BOB_string" is set to be the same as "ai_name" and another comparison attempt is made.
Test results
Please see the enclosed series of figures. Figures show a relevant selection of runtime memory data.
- Data regarding global variable "BOB_string".
- Data regarding local variable "ai_name" (relevant only during the execution of the t48_dead() function).
- State of memory at the moment when the string comparison was evaluated the first time (as 'false') and the second time (as 'true').
Conclusion
- A BSL string variable seems to be stored as a C string; no additional special characters, simply a stream of bytes till the first 0x00 byte (null terminator).
- When keeping track of a BSL string, Oni thus uses a pointer to the given C string.
- If there are several independent strings which by chance contain the same text (e.g. "A_t48"), the engine still keeps separate instances of these strings (no string reuse to save memory, or any similar technique).
- When string comparison is attempted, it is most likely that the values of the pointers themselves (the memory addresses) are being compared, not the contents of the strings themselves.
- Since the engine allocates memory for local BSL variables and function arguments on demand, the address of a string such as "ai_name" will differ in each runtime session and cannot be expected at a particular position.