2021-05-21: bUt YsI hAs MaCrOs!
I?m a big advocate of NOT using macros for things, yet am famous for using macros - how can those two things be reconciled?? Easy, it depends on WHY you are using them, and I have some guidelines on when to use them and when not to use them.? Basically it depends on two things - how much work you?re saving yourself and how much you?re changing normal syntax (making it harder for other people to read your code).? As an aside, macros are very hard to get right, and while they may appear to work correctly in some cases, that doesn?t mean they always will, so there?s a good chance that without a thorough understanding of what?s going on you?re just opening yourself up to major future issues.
Some examples of pointless macros:
The ultimate stupid macro.? How much work does it save?? None - you?re replacing a single function call with a single function call (and if you don?t have auto-completion in your editor get a better editor).
Worse than not saving you any effort, this requires MORE effort, because not only is it actually more characters to write, but it breaks auto-completion so that time save is gone as well.? Plus it adds non-standard syntax to code that will cause people to stop and question what exactly is going on.? Is it REALLY just Object_ or is it doing something more behind the scenes?
This example is broken, and the name is terrible - Ex tells you nothing about what the function actually does, it is only obvious because you?re looking at the code right now!? Plus, I hope you aren?t doing this:
That code won?t work, but good luck figuring out why looking at the call site.
This is also broken in several ways:
This code will randomly miss people.
This will never ever send "No" to anyone, not even admins.
So why is YSI ?allowed? macros?? The truth is some of them are pretty bad and shouldn?t exist, but for the most part they?re used when the code generated is complex and something that people shouldn?t need to worry about, AND that code can?t be moved to a function.? Most of the examples above are either macros for the sake of using macros, or would be more effective (and less buggy) as functions.? Take y_iterate for example:
The code generated by this, which you COULD type out yourself, is:
WHY it is that is not something people need to know - it?s an implementation detail of how the library works.? Calling format to format a string is not an implementation detail, that?s something everyone knows, everyone knows that?s what your macro is doing, you aren?t saving confusion by hiding it.
The other rule I try to stick to is to always stick as closely as possible to existing syntax.? Why was :: considered useful syntax?? It adds nothing except something else to learn.? On the other hand macros like hook and inline closely mimic the syntax of stock - they look exactly the same as every other function declaration keyword, so nothing new to learn.? There are some macros that don?t - I?ve never liked the : in foreach as that has no precedence (; would be worse, because that implies the expressions are separate).? The <> ?special array? syntax as used in the Iterator: syntax above is not great - it has the advantage of making it clear that this is not just a normal array, but with no precedent.? CMD: has been repeatedly documented as very poor syntax, due to copying tags without being a tag.? timer Func[TIME]() has no precedence - what does the [] syntax mean there without context?? Show me a YSI macro and I can probably tell you why I hate it.
Note that I?m only talking about external macros here - those designed for users of the library, internal ones are irrelevant, they?re again implementation details (and the reason they?re almost unreadable is that a) that?s just how writing macros is, and b) compiler line length limits).
I?m a big advocate of NOT using macros for things, yet am famous for using macros - how can those two things be reconciled?? Easy, it depends on WHY you are using them, and I have some guidelines on when to use them and when not to use them.? Basically it depends on two things - how much work you?re saving yourself and how much you?re changing normal syntax (making it harder for other people to read your code).? As an aside, macros are very hard to get right, and while they may appear to work correctly in some cases, that doesn?t mean they always will, so there?s a good chance that without a thorough understanding of what?s going on you?re just opening yourself up to major future issues.
Some examples of pointless macros:
Quote:
#define SCM SendClientMessage
SCM(playerid, COLOUR_ERROR, "Why are you using SCM?");
The ultimate stupid macro.? How much work does it save?? None - you?re replacing a single function call with a single function call (and if you don?t have auto-completion in your editor get a better editor).
Quote:
#define Object:: Object_
Object::SetPosition(objectid, x, y, z);
Worse than not saving you any effort, this requires MORE effort, because not only is it actually more characters to write, but it breaks auto-completion so that time save is gone as well.? Plus it adds non-standard syntax to code that will cause people to stop and question what exactly is going on.? Is it REALLY just Object_ or is it doing something more behind the scenes?
Quote:
#define SendClientMessageEx(%0,%1,%2) \
____format(string, sizeof (string), %2); \
____SendClientMessage(%0, %1, string)
This example is broken, and the name is terrible - Ex tells you nothing about what the function actually does, it is only obvious because you?re looking at the code right now!? Plus, I hope you aren?t doing this:
Quote:
if (!HasAdminLevel(playerid, 5))
____return SendClientMessageEx(playerid, COLOUR_ERROR, "You need admin level %d", 5);
That code won?t work, but good luck figuring out why looking at the call site.
Quote:
#define SendToAdmin(%0,%1,%2) \
____if (IsPlayerAdmin(%0)) \
________SendClientMessage(%0, %1, %2)
This is also broken in several ways:
Quote:
SendToAdmin(playerid, COLOUR_ERROR, "I hope they're not an admin");
This code will randomly miss people.
Quote:
if (ThingShouldHappen())
____SendToAdmin(player, COLOUR_OK, "Yes");
else
____SendToAdmin(player, COLOUR_OK, "No");
This will never ever send "No" to anyone, not even admins.
So why is YSI ?allowed? macros?? The truth is some of them are pretty bad and shouldn?t exist, but for the most part they?re used when the code generated is complex and something that people shouldn?t need to worry about, AND that code can?t be moved to a function.? Most of the examples above are either macros for the sake of using macros, or would be more effective (and less buggy) as functions.? Take y_iterate for example:
Quote:
new Iterator:Admins<MAX_PLAYERS>;
The code generated by this, which you COULD type out yourself, is:
Quote:
new Iter_Size@Admins, Iterator@Admins[MAX_PLAYERS 1] = {
____MAX_PLAYERS * (1 - MAX_PLAYERS),
____MAX_PLAYERS * (2 - MAX_PLAYERS),
____...
};
WHY it is that is not something people need to know - it?s an implementation detail of how the library works.? Calling format to format a string is not an implementation detail, that?s something everyone knows, everyone knows that?s what your macro is doing, you aren?t saving confusion by hiding it.
The other rule I try to stick to is to always stick as closely as possible to existing syntax.? Why was :: considered useful syntax?? It adds nothing except something else to learn.? On the other hand macros like hook and inline closely mimic the syntax of stock - they look exactly the same as every other function declaration keyword, so nothing new to learn.? There are some macros that don?t - I?ve never liked the : in foreach as that has no precedence (; would be worse, because that implies the expressions are separate).? The <> ?special array? syntax as used in the Iterator: syntax above is not great - it has the advantage of making it clear that this is not just a normal array, but with no precedent.? CMD: has been repeatedly documented as very poor syntax, due to copying tags without being a tag.? timer Func[TIME]() has no precedence - what does the [] syntax mean there without context?? Show me a YSI macro and I can probably tell you why I hate it.
Note that I?m only talking about external macros here - those designed for users of the library, internal ones are irrelevant, they?re again implementation details (and the reason they?re almost unreadable is that a) that?s just how writing macros is, and b) compiler line length limits).