Passing Iterators To Functions
When building contracts, it's ideal to use helper functions occasionally, in order to keep the code clean and readable.
While doing this, you will undoubtedly run into the following issue:
You fetch a table row
You need to pass that row into a helper function, either to simply read it, or to modify it
You then need access to the outcome of that helper function so you can continue your logic
This is a bit trickier than you might think, but after doing it once, it becomes pretty simple. I'll show you the common way to do it, and then I'll show you the way I do it
The above method is the most common approach that I've seen people use. However, there are times where you may want to mutate the data inside the helper function, and this becomes quite annoying because you can't directly modify a pointer (at least in my experience).
What I do to get around this, is to create a custom struct that matches the table struct. And a constructor to populate that struct with the data found in the table row. This struct can then be modified inside helper functions. I'll show you what I mean.
This approach allows you to create an object that has the exact same data as the table row. Then, you can modify that object inside of your helper functions. Finally, you need to make sure that you set the table data based on the new info after modifying the object.
The nice thing about this approach is that you can take it a step further - you can create a helper function that fetches the table row in the first place, and then another helper function to modify that row. All without needing to worry about dealing with iterators and running into errors left and right.
It should be noted that the lifecycle of certain pointer objects can be outlived by other functions where those pointers are referred to.
If that sounds like gibberish to you, basically it works like this:
You have some helper function to fetch an iterator
That helper function returns the iterator
That returned iterator may become invalidated by the time you actually try to use it
This problem does not exist when using a custom struct the way that I demonstrated above. This is because the custom struct is not an iterator, but rather a defined object that maintains its lifecycle throughout the scope of where it is defined.
When in doubt, go with the custom struct approach instead of dealing directly with an iterator. Then, just refetch the table row later when you need to modify it again.
There is obviously a slight performance implication here - fetching a table row twice is less performant than fetching it once. However, in my experience the tradeoff is worth it for the improved sanity and readability.
Last updated