[Pawn] YSI Daily Tips - Printable Version + open.mp forum (https://forum.open.mp) -- Forum: SA-MP (https://forum.open.mp/forumdisplay.php?fid=3) --- Forum: Pawn Scripting (https://forum.open.mp/forumdisplay.php?fid=10) --- Thread: [Pawn] YSI Daily Tips (/showthread.php?tid=1972) Pages:
1
2
|
YSI Daily Tips - Y_Less - 2021-05-01 YSI Daily Tips
Almost every time I mention something about YSI someone says "oh, I didn't know it could do that".? This is maybe my fault for incomplete/deleted documentation, so I'm going to start writing one random snippet about YSI every day.? Hopefully these will all help you simplify your modes and improve your scripting.? I've also ported over the tips from the old YSI Secrets thread on the SA:MP forum. If you have any suggestions, questions, or your own YSI hints, feel free to share them here. WARNING:? Don't copy and paste the examples In order to get both indentation and syntax highlighting showing up, the "tabs" you see are actually underscores with the same colour as the background.? If you copy text verbatim from this thread, you'll come away with extra characters you don't want. RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-14: GLOBAL_TAG_TYPES This is used in place of tags for variable argument functions. For example, ?printf? is defined as: Quote: Using {Float, _}: means that this function can accept a range of Float and _ (normal) variables. But what about Text: or Group: or Menu:? You could write: Quote: To avoid getting tag mismatch warnings when trying to print those variable types, or you can do: Quote: Which is defined in YSI as: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-15: PP_LOOP PP_LOOP is a pre-processor loop, so generates multiple blocks of code. For example: Quote: Will compile as: Quote: The definition of this macro is: Quote: The separator goes BETWEEN instances of ?output?, but not at the end. So you can make a list as: Quote: And that will compile as: Quote: Note the lack of ?, ? on the end because that?s not separating anything. RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-16: __COMPILER_PASS The PAWN compiler does TWO pre-processing stages. It?s rare that this is a problem, but if you need to know which stage is being run you can do: Quote: Alternatively: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-17: y_cell This is a library for fast bit-manipulation of cells: Quote: Reverse all the bits in a cell: Example: 0b11110000000000000000000000000000 Becomes: 0b00000000000000000000000000001111 Example: 0b10110011100011110000111110000010 Becomes: 0b01000001111100001111000111001101 Example: 0b01010101010101010101010101010101 Becomes: 0b10101010101010101010101010101010 Quote: Reverse all the nibbles in a cell: Example: 0x12345678 Becomes: 0x87654321 Example: 0x010F0703 Becomes: 0x3070F010 Example: 0xF0F0F0F0 Becomes: 0x0F0F0F0F Quote: Reverse all the bytes in a cell: Example: 0x12345678 Becomes: 0x78563412 Example: 0x01020304 Becomes: 0x04030201 Example: 0xFF00FF00 Becomes: 0x00FF00FF Quote: Count all the 1s in a cell. Example: 0 Returns: 0 Example: 1 Returns: 1 Example: 0x01010101 Returns: 4 Quote: Returns a number between 0 and 31, representing the least significant set bit in a cell: Example: 0b00000000000000000000000000000001 Returns: 0 Example: 0b00000000000000000000000000001000 Returns: 3 Example: 0b00010001100011000011100010001000 Returns: 3 WARNING: This function returns 0 if there are no bits set AND if the lowest bit is 1 Quote: Returns the lowest set bit in a cell: Example: 0b00000000000000000000000000000001 Returns: 0b00000000000000000000000000000001 Example: 0b00000000000000000000000000001000 Returns: 0b00000000000000000000000000001000 Example: 0b00010001100011000011100010001000 Returns: 0b00000000000000000000000000001000 RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-18: Keywords Most people know that YSI adds foreach to the PAWN language, but here is a list of other keywords added by it:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote: remote functions are called in ALL other scripts, global functions are called in just one.
Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-19: OnScriptInit Quote: This is like OnGameModeInit or OnFilterScriptInit, but works the same in both (i.e. is called once at the start, regardless of the script type). It can't do anything those callbacks can't do, just makes writing libraries more consistent. Basically it is a good option for initialisation code in an include as then it doesn?t matter where your include is used. RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-20: OnScriptExit Quote: This is like OnGameModeExit and OnFilterScriptExit, but works the same in both (i.e. is called once at the end, regardless of the script type). It can't do anything those callbacks can't do, just makes writing libraries more consistent. RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-21: Dynamic Memory Allocation Using YSI you can allocate and free memory when you like (and as much as you like): Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-22: Restricting Connections You can limit how many people can connect to your server from the same IP: Quote: That lets 3 people connect from the same IP. If any more try join they will fail to connect. You can also change what happens when too many people join: Quote: That will ban an IP if more than 5 people try to connect from it. The available actions are:
RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-23: Temp Variables Sometimes you need a variable for a fraction of a second (or just a few expressions). YSI has 3 of these ?temp? variables already to avoid creating more:I@, J@, and Q@[YSI_MAX_STRING]. Quote: Quote: These variables can NOT be relied upon over function calls, so this might not work: Quote: GetSomeData might modify J@ and you would never know. These are purely for getting some data then using it pretty much straight away. There is also another one of these short variables: @_ (yes, the variable is called <at><underscore>). This is the Master ID for a script. All currently running scripts have an ID. RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-24: Short Functions Speaking of short variables, there are some short functions too. These are used in complex macros to reduce the length of the generated code to fit in tight line-length restrictions:
RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-25: Debug Prints If you compile a YSI mode with ?_DEBUG? set, you get a load of information in the compiler window. This macro means that the prints are ONLY included at the correct level and not any other time, so using ?_DEBUG 0? (or none at all) will strip all the print statements from the mode for the best performance. Quote: The number after _DEBUG is the debug level (default 0) and there are 8 levels:
I will warn you - use level 7 VERY rarely, even I try to avoid it as it generates several Mb of log data just for STARTING your server! To output your own debug prints use P:<number>(message) Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-26: Special Prints Besides the 8 levels mentioned above, there are some special levels: Quote: Quote: Quote: Quote: These special prints are ALWAYS compiled because they give the user important information about errors in code, and not just random debug information. However, they can be suppressed by doing: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-27: Dynamic Prints A recent addition to y_debug added level -1: Quote: This activates run-time debug level selection, so doing: Quote: Compiles as: Quote: You can then change the level at run-time with: Quote: Disable most printing (except special ones - see above) with: Quote: And get the current debug level with: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-28: Special Tags YSI introduces two special tags for functions. These can be used to optimise code in some instances:
Quote: When using y_master, this will actually make the generated code faster, and give an error if you put ?return? in your function and try use that return value. Technically you can still have ?return?, you just can?t use the value.
Quote: This is used extensively with YSI keywords - timer, global, inline, and remotefunc all rely on string: to generate code that uses "s" instead of "a" (arrays must be followed by a length parameter, strings needn?t be). RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-29: IS_IN_RANGE If you have some code like this: Quote: Or the much better: Quote: You can now use YSI to do it an even better way: Quote: This checks that the first parameter is AT LEAST the second parameter, and SMALLER than the third parameter, and is faster than the other two methods. If you want to change the ranges, add or subtract 1. For example to check if something is a numeric character do: Quote: That will do: Quote: Or more strictly it will do: Quote: These being integers, those are the same (they aren?t for floats). RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-04-30: RUN_TIMING This is a simplified way to get many statistics comparing two bits of [pawn] Quote: Will output something like: Timing "Version 1 ()"... __________Mean = 78.00ns __________Mode = 76.00ns ________Median = 78.00ns _________Range = 9.00ns Timing "Version 2 (=)"... __________Mean = 94.00ns __________Mode = 94.00ns ________Median = 94.00ns _________Range = 15.00ns If you don?t understand statistics, pick the one with the lowest Mean, or better yet learn statistics. There is an optional second parameter to control the number of loops if the experiments run too quickly or slowly: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-01 2021-05-01: y_unique Most people know about y_hooks, and that if you use it in multiple files you need to include it in every one.? But why?? The reason is that every time you include it, it generates a new unique name for the hooked functions so that two hook OnPlayerConnects in a row don?t have the same name for the compiler.? But how?? y_unique Including y_hooks after the first time just in turn includes y_unique.? This library exports two symbols - UNIQUE_SYMBOL and UNIQUE_FUNCTION.
Quote: That will print two numbers (probably sequential, but that?s not a guarantee).
Quote: That will make two functions with names such as My008thFunction and My009thFunction.? The zeros are by design, and the numbers are injected in to the symbol in place of the given ...s.? The <Function...Name> pattern is used in a few other places in YSI as well, most notably y_groups.? If you?re wondering why it is done this way, the following code won?t work: Quote: That will just produce two functions both called exactly MyUNIQUE_SYMBOLthFunction, and the following code is a syntax error: Quote: In C this could be done with the ## operator, but while there are proposals to add it to pawn, they haven?t materialised yet. How does y_unique generate a new number every time you include it? It?s just a massive massive string of #if UNIQUE_SYMBOL == 4s etc. Its split up in to files by 100s, and within those in to groups of 10 for speed, but there?s really nothing more to it than that. This also means the numbers are limited to as high as the defines go (currently 999). RE: YSI Daily Tips - Y_Less - 2021-05-02 2021-05-02: Command Prefix Commands are normally /command; however, with y_commands you can change this symbol to anything you want per-command: Quote: There?s also Command_GetPrefix, Command_GetPrefixNamed, Command_IsPrefixUsed, and Command_IsValidPrefix to get meta-data on prefixes. There is no global prefix, but if you want to change it for every command you can use a simple loop: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-03 2021-05-03: Dependencies YSI usually needs md-sort and amx-assembly, but only if you use certain parts.? If you just include the very core of YSI you don?t even need a_samp.? y_utils and a few other libraries will work with just the core pawn includes - core, file, float, string, time, and optionally console if you have it.? So you can use YSI for projects in no way related to SA:MP. RE: YSI Daily Tips - Y_Less - 2021-05-04 2021-05-04: y_zonepulse This is a tiny little library that does just one thing - makes zones on the mini-map flash.? Make a zone, pass it to the GangZonePulse function, and watch it flash. Wait, can?t zones already flash with GangZoneFlashForPlayer and GangZoneFlashForAll?? Yes, but that just turns them on and off at a set rate.? This include allows you to specify the two colours they alternate between, how long to take fading between the colours, and how long to pause at each colour: Quote: The first parameter is also a PlayerSet, so can take players, groups, or arrays. RE: YSI Daily Tips - Y_Less - 2021-05-05 2021-05-05: y_testing Assertions When writing tests with y_testing, most checks use ASSERT: Quote: It?s simple and clear.? However, if x isn?t 2 it doesn?t give you much information - all that?s known is that some boolean check was false.? For most common operations there are more specific tests that give you far more useful information.? In all these assertions, if they fail, the failed test and the value of testee are printed to help with debugging.
RE: YSI Daily Tips - Y_Less - 2021-05-06 2021-05-06: Plugins YSI is written to support many plugins in different ways, all without any direct dependencies.? If you call the native from a plugin in a function that is itself never called, you won't get errors for the natives not existing, so YSI can use plugin functions even when they aren't included or loaded. MySQL Inline query functions built in directly: Quote: There are also equivalent functions for `TQuery` and ORM functions. BCrypt Inline comparisons functions: Quote: Quote: Requests RequestCallback and RequestJSONCallback as inline versions again. Streamer Inline callback versions of almost all the streamer functions it makes sense for - OnPlayerEnterDynamicArea, OnPlayerEnterDynamicRaceCP, OnPlayerEnterDynamicCP, OnPlayerPickUpDynamicPickup, and OnDynamicObjectMoved are all wrapped, to enable calls such as: Quote: However, this feature isn't quite complete yet as it relies on streamer plugin v2.9.5 and its "extra" extra IDs (to store callback IDs), which has only just been released. RE: YSI Daily Tips - Y_Less - 2021-05-07 2021-05-07: Bug Bounty YSI has a bug bounty.? It's not well defined or known, but it exists.? In general it is for fixing bugs, not just reporting them, though there are some exceptions if the report actually details the exact cause rather than just the effects.? The bigger the bug, the more you get paid.? It also only applies to 5.x, not 4.x, but includes fixing breaking changes between 4.x and 5.x.? Some examples of other things that are covered include:
RE: YSI Daily Tips - Y_Less - 2021-05-08 2021-05-08: Resize 2D Arrays You can resize the slots in a 2D array, as long as the sum remains the same.? For example this array: Quote: Has a grand total of 25 cells in which to store data.? Those can be reallocated to one slot of 21, and 4 slots of 1.? This is called a jagged array: Quote: The compiler doesn?t know about these resizes, so you need to replace sizeof(arr[]) with jaggedsizeof(arr[0]); specifying an index because they?re all different. You can also declare the array jagged initially: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-09 2021-05-09: Startup Time And Size Solved The longest standing complaints about YSI were the slow startup time and the huge resulting AMX size. Today I solved both of them at once by rewriting y_malloc. It now uses the heap again, but in a safe manner, thus vastly reducing file sizes and load times. RE: YSI Daily Tips - Y_Less - 2021-05-11 2021-05-10: y_php YSI has full 2-way communication with a PHP CLI, or any other server running in a persistent mode. RE: YSI Daily Tips - Y_Less - 2021-05-11 2021-05-11: Origins of YSI I started writing a race server (San Andreas Underground), it was going quite well with some unique features for the time, one of which was the ability to host multiple races in parallel. Unfortunately I got distracted writing the underlying core instead of the high-level gamemode, and eventually ended up releasing this core as a library - YSI. Thus y_races is the oldest component in YSI, and the main algorithm hasn?t changed at all since, because it was so solid to begin with. RE: YSI Daily Tips - Y_Less - 2021-05-12 2021-05-12: Adding y_groups Support Obviously various YSI libraries have y_groups support, via functions such as: Quote: But none of these functions actually exist anywhere in code - they?re all generated from a common template at compile-time.? And your own libraries can use the same pattern.? Assuming you are writing an Object library: Quote: Then you just need a way for y_groups to enable and disable individual players.? This is done through a single function, all y_groups does is manage when to add and remove players by calling this one function: Quote: AFter that very little code you have:
And far more.? All the y_groups functions, with ... replaced by your library name. RE: YSI Daily Tips - Y_Less - 2021-05-13 2021-05-13: y_dialog Inline Parameters Most documentation on y_dialog callbacks show the following: Quote: However, when the closure also contains playerid, this gets cumbersome to constantly rename the playerid variable passed to the inline, then not use it.? Similarly the dialogid variable is redundant because y_dialog doesn?t use IDs and never provides them for comparison.? Thus, these two parameters are both optional and can be skipped in the inline: Quote: Dialog_ShowCallback takes either iis or iiiis functions. RE: YSI Daily Tips - Y_Less - 2021-05-14 2021-05-14: y_stringhash Hash Algorithm You can change which hash function is used by y_stringhash:
You would only need this in the extremely rare event that you get a hash collision between two cases. It is also important to note that these are NOT cryptographic hashes - they are use to compare simple string, NOT to store passwords. RE: YSI Daily Tips - Y_Less - 2021-05-16 2021-05-15: y_remote This very simple library just wraps CallRemoteFunction, to generate all the specifiers for you and check that the parameters are correct at compile-time.? This code compiles but doesn't work: Quote: This code gives an error: Quote: That's very useful for spotting bugs early. RE: YSI Daily Tips - Y_Less - 2021-05-16 2021-05-16: CUSTOM_TAG_TYPES An earlier tip mentioned GLOBAL_TAG_TYPES, a list of tags that all YSI functions will accept.? You can extend this list with your own tags by defining CUSTOM_TAG_TYPES.? This is a bare list (no braces) of tags, and from now on all YSI functions (formatters etc) will accept these tags with no warnings: Quote: RE: YSI Daily Tips - Y_Less - 2021-05-19 2021-05-17: Passing Normal Functions As Callbacks Functions that most people think take inline functions can also take public functions with using callback (or using public): Quote: This does need an explicit type (iiiis) because the types of publics can?t be automatically determined in the same way as for inlines.? With an inline the type is checked and if the parameters don?t match a warning is given.? However, with a public, you specify the type manually, so if it is wrong there should be no warning (you basically promise the compiler it is called his way).? Fortunately, this code uses addressof underneath, which generates code to check the call is correct - so if the specified type is wrong here the compiler actually gives an error, thus re-introducing lovely type-checking. Because the call uses addressof, you can extend this to another type of function - bare functions. These are sometimes called stocks, but they are not stocks - that keyword is only used in some situations (mainly libraries): Quote: This has three advantages:
RE: YSI Daily Tips - Y_Less - 2021-05-19 2021-05-18: CALL@ Technically this is a fact about amx-assembly, but it directly affects using YSI. You saw in the previous tip how using using callback and using function take the parameter specifier after the function name (using function Response<iiiis>).? This is so that the underlying call to addressof can generate the correct code to actually GET the address.? Roughly speaking, a call to the function is generated, but the call is conditional on the result of a call to an internal addressof function, which always returns false.? This is so the internal function can read the next CALL OpCode, but never execute it.? Something like the following: Quote: Becomes: Quote: However, you can customise how addressof internally calls your function using CALL@Name: Quote: Now, addressof doesn?t need the explicit specifier, and by extension neither does using: Quote: However, <iiiis> has the advantage that it is always const-correct, unlike that example? RE: YSI Daily Tips - Y_Less - 2021-05-19 2021-05-19: Initialisation Order I?m somewhat loathe to document this, as I know someone will abuse it, but this is the complete order of initialisation callbacks in YSI.? Unfortunately, over the years this has got slowly more complicated with more and more dependencies and restrictions. Originally it was just either OnGameModeInit or OnFilterScriptInit, but no-one uses the FILTERSCRIPT macro correctly, so OnScriptInit was added, which can detect if the script is a GM or FS; and is called before either of their callbacks. Then JIT support was added to the code, which requires generating assembly from OnJITInit, but that won?t be called if they aren?t using the JIT plugin.? Thus OnCodeInit was added, which is called from either OnJITInit, OnFilterScriptInit, or OnGameModeInit; whichever comes first. OnCodeInit is harder to use than any other callback because it actually generates the code used by y_hooks and other libraries, thus no advanced YSI features like hook or inline can be used within it. Then I added caching.? This saves a copy of the mode after all OnCodeInit generation has run, and is called when the mode is loaded from cache, rather than loaded initially.? However, this entire feature was a dead-end and recently removed, thus this callback was also removed.? I don?t normally like removing features as it breaks backwards-compatibility, but this was an exception - it was an awful feature you should avoid. In addition, there are the lightweight initialisation functions, which can be used in place of OnScriptInit.? PRE_INIT__ and POST_INIT__.? Instead of using hook with a normal init name, these have unique names with a custom declaration (meaning you can make initialisation hooks without needing to include y_hooks): Quote: The most common example of POST_INIT__ is final*: Quote: So the full intialisation order is:
* Its actually currently PRE_INIT__, but I?m changing that due to some conflicts, and it making the initialisation actually even more complicated than is listed here. RE: YSI Daily Tips - Y_Less - 2021-05-20 2021-05-20: Yet Another Call Improvement Three days ago introduced using function Name<spec>, and two days ago introduced CALL@Name. These are both methods use to specify what parameters a function expects, but they are used to pass the function as a pointer to another function that already knows what parameters the pointee should take. Given: Quote: The specifier is in this code twice - once in the parameters of Caller to say it wants a function that takes three parameters, and once in the addressof to say that Callee is indeed a function that meets the requirements of taking three parameters.? The same basic problem exists if you?re using using or CALL@ as well - repetition of information. Because of how this all works, you actually can?t stop this information being duplicated, but you can hide it such that users of your function never need to worry about it.? This is normally done with &: Quote: Much cleaner than all other solutions, but how does it work?? That?s not a standard operator.? The answer is that oft-maligned feature - macros: Quote: Using this macro (placed almost anywhere) will detect when the second parameter (Nth parameter in other calls - just depends when you want the pointer) starts with &.? If it does it replaces that parameter with a typed call to addressof, as was done in earlier examples.? The fact that th function and macro have exactly the same name is important - this allows all the methods to work, not just one. For Dialog_ShowCallback this would be: Quote: For BCrypt_CheckInline: Quote: For cb_MoveDynamicObject: Quote: The last macro parameter will detect ALL remaining function parameters after the & - you only need to explicitly specify the parameters before &.? Thus this technique works for vararg functions as well. RE: YSI Daily Tips - Y_Less - 2021-06-01 2021-05-21: Pass An Iterator As A Parameter Sometimes you want to pass an iterator to a function.? Iterators are often global, but they don't have to be, and there are still times when you might want them as generic parameters.? There's no simple way to do this, it wasn't really a design consideration, but it is possible. Under the hood an iterator is two variables - an array containing the data, and a single variable containing the count (the count is also an array for multi-iterators).? For the iterator Player these are called Iterator@Player and Iter_Count@Player (so you get vaguely readable warnings).? Thus, to receive an iterator in a function as use it within that function you need the following two parameters: Quote: You can't use the `Iterator:` macro for this, because it also generates initialisation code, but you could create your own.? The size is %1 1 to hold some internal data.? This does mean you have to know what size of iterator you want to pass in advance, because currently foreach uses sizeof a lot internally.? This might be fixable, but isn't currently: Quote: With this code, PASSING the iterator is again fairly straightforward: Quote: But we've just changed one nice parameter in to two horrible parameters.? Fortunately the calling side of things is far better defined (since the y_iterate) API functions like Iter_Add already take plain iterators as parameters.? The functions might not be defined nicely, but they can be called nicely.? The macro for this is _ITER, which does all the work detecting which type of iterator was passed (normal or multi), the size and start, and calls an InternalA or InternalB version of another macro depending on normal- or multi-: Quote: This renames MyFunction to MyFunction_, then defines MyFunction as a macro that takes an iterator.? InternalA has two parameters given - the count and array.? InternalB has three parameters given - the count, the start, and the array.? If you want to pass the size of the iterator it's F@s(%1)-F@s(%0).? You can also just call your function? Iter_MyFunction_InternalA and you don't need the extra macros.? If your function takes more parameters after the iterator, they are all passed to the macros/functions in an additional %9 at the end of the parameter list. Now the call is very simply: Quote: RE: YSI Daily Tips - Y_Less - 2021-06-25 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: Quote: 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: 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: 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: That code won?t work, but good luck figuring out why looking at the call site. Quote: This is also broken in several ways: Quote: This code will randomly miss people. Quote: 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: The code generated by this, which you COULD type out yourself, is: Quote: 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). |