I've been reading about keeping functions simple and specific to only one purpose. And that even a function that does a simple calculation and print out the result is already too much.
I've been working on an item shop system for a small game. The shop has a vector of all items available in the game. Each Item keeps track of its own count (is that bad?), and do not show up in the inventory output if its count is zero.
When a player (rider) wants to buy an item, the shop should check if the player has enough credit and if such item is in stock before the item gets removed from the shop (and then added to the player's inventory).
I have combined all of that into one function, thinking that this avoid repetition of traversing through the vector of Items.
/* ItemShop.cpp
* non-binary boolean:
* returns 0 if item is not in stock
* returns 1 if rider has insufficient creds to buy the item
* returns 2 if purchase is successful */
int ItemShop::buyItem(const string& itemName, const int cred, Item& newItem) {
// go through shop inventory and search for item with given name
for (int i = 0; i < items.size(); i++) {
if (items[i].getName() == itemName) {
if (items[i].getCount() > 0) { // item is in stock
if (items[i].getValue() <= cred) { // rider has enough creds to buy the item
newItem = items[i]; // pass a copy of the item by ref
newItem.setCount(1); // take one of that item
items[i].removeOne(); // remove one from the shop
return 2; // purchase is successful
}
return 1; // rider cannot afford to buy the item
}
}
}
return 0; // item is not in stock
}
In doing this approach, I end up with a larger multi-purpose function but I didn't have to go through the Item vector multiple times. I think if I were to break the function into separate ones, they would be:
check if item is in stock
check if player can afford
transaction
Each of those functions would have to go through and find the item in the vector (unless maybe I pass a reference of it.. from the function?).
All in all, does less code repetition make my approach justifiable? If not, how should I break it down?
Two recommendations:
Store your items in a std::map<string,Item> where the string is
the item name. This will remove the search loop.
Use an enum as return value instead of an int.
You could also implement simple functions for the different checks, but that's a matter of taste I would say.
You can break that up into the following operations:
find the appropriate item by name (that's what the loop mainly does) and return a reference to the found item
check if there are enough items in stock. item itself already carries that information as it looks, it doesn't need to be executed inside the loop
check if the player can afford it. You already have the cred value apparently, it doesn't need to be executed inside the loop
if the latter two conditions are fulfilled do the transaction, again it doesn't need to be executed inside the loop
Your function doesn't do too many things - you are purchasing an item, which includes those three necessary steps (btw.: aren't you missing the payment?).
However (aside from other things that could be improved), you should make sure that the steps don't get intermingled. In particular avoid nested structures whenever possible.
You could e.g.rewrite your body (without changing the interface) like this:
int ItemShop::buyItem(const string& itemName, const int cred, Item& newItem) {
//find item
auto it = std::find_if(items.begin(), items.end(), [&](const Item& item) {return item.getName() == itemName; });
//Check if Item can be purchased
if (it == items.end() || it->getCount == 0) {
return 0; //item is not in stock
}
if (it->getValue() > cred) {
return 1; //rider can't afford item
}
//buy item
newItem = *it; // pass a copy of the item by ref <- Avoid that if possible
newItem.setCount(1); // take one of that item
it->removeOne(); // remove one from the shop
return 2; // purchase is successful
}
I do think an item keeping its own count is a poor idea. An "inventory" (or something on that order) keeps track of the items in stock and the number of each. An item should be just that: an item.
I think the suggestion to use a [unordered_]map is a good one. It pre-implements what is probably the single most complex part of your current function (though none of it is particularly complex).
Do note that some of this can get much trickier when/if multiple threads get involved. If multiple threads of execution are involved, your current pattern of "if we can do this, then do it" breaks down, because it introduces race conditions. You need to assure that removing the item from inventory and paying for the item happen as a single, atomic, transaction. As long as you're sure it'll only have a single thread of execution involved though, your current method is safe.
Related
TL;DR - I am accumulating a transaction in postgresql (pqxx) and suspect I'm doing something overly tortuous to get where I'm going.
In the first part of the question I've shown the naive way one might do a series of inserts and explain that it is (first) slow and (second) can lead to an error. Then I show where reading docs has lead me: I'm pretty sure it's an abusive way to interact with libpqxx, but I'm not sure what the intended pattern is.
Intro: the naive approach to doing thousands of inserts
I have some code that wants to write a bunch of stuff to the database, typically INSERT ... ON CONFLICT UPDATE. Roughly, this code is looping over some container and generating the needed SQL to insert each container object that needs inserting.
The naive way to do this (skipping error/exception handling for the moment) is thus:
pqxx::work txn(conn);
ostringstream sql_stmt;
Container rows;
for (const auto& row : rows) {
if (row.IsDirty()) {
RowToSQL(sql_stmt, row, txn);
txn.exec(sql_stmt.str());
// Clear sql_stmt here.
}
}
txn.commit();
The function RowToSQL() takes a transaction object so that it can quote strings appropriately using txn.quote().
This is inefficient, however: calling exec() over and over turns out to be quite slow.
So instead I build up a bunch of statements in the ostringstream, thus:
pqxx::work txn(conn);
ostringstream sql_stmt;
Container rows;
for (const auto& row : rows) {
if (row.IsDirty()) {
RowToSQL(sql_stmt, row, txn);
if (++counter > kExecuteThreshold || sql_stmt.IsTooBig()) {
txn.exec(sql_stmt.str());
// Clear sql_stmt, reset counter here.
}
if (count > kCommitThreshold) {
txn.commit();
// Reset statement counter here.
}
}
}
// Final commit here.
I chose the two thresholds based on performance testing in our environment, think 100 and 10,000 for order of magnitude.
This worked until it didn't, because re-using the transaction this way leads to conflicts.
Attempt to activate transaction<READ COMMITTED> which is already closed.
This SO question addresses this mostly.
This leads me to write something that has weird code smell, and I so suspect I've misunderstood how postgresql / libpqxx intend to be used.
Adding back error/exception handling:
Less naive but weird code smell
pqxx::nontransaction non_txn;
ostringstream sql_stmt;
Container rows;
Vector<string> transactions;
for (const auto& row : rows) {
if (row.IsDirty()) {
RowToSQL(sql_stmt, row, non_txn);
if (++counter > kExecuteThreshold || sql_stmt.IsTooBig()) {
transactions.push_back(sql_stmt.str());
// Clear sql_stmt, reset counter here.
}
if (count > kCommitThreshold) {
try {
pqxx::work txn(conn);
for (const string& trans : transactions) {
txn.exec(trans);
}
txn.commit();
transactions.clear();
// Reset statement counter here.
} catch (const exception& e) {
txn.abort(); // Pedantic, happens on destruction.
YellowAlert(); // Something appropriate.
}
}
}
}
// Final commit here.
It seems quite wrong to me that I should build up this vector of things to execute and maintain these custom-tuned execution/transaction thresholds rather than using some facility of libpqxx. That is, this pattern seems common enough to me that the complexity I'm starting to see strikes me as my own misunderstanding.
Any pointers much appreciated.
I have a vector of (pointers to) objects - people. I have a function that adds income to a person. The problem I'm having is to both find a person and accessing that addInc. I still sometimes get confused with pointers/references and more importantly I'm new to OOP. The relevant function is:
bool Population::Income(const string &id, unsigned int amount) {
Person *Candidate = new Person(id);
//find company using lower_bound
iterPeople = lower_bound(m_People.begin(), m_People.end(), Candidate, cmpId);
if ( iterPeople != m_People.end() && (*iterPeople)->m_id == id ) {
*(iterPeople)->addInc(amount);
//request for member 'addInv' in...maybe you meant to use '->'?
delete Candidate;
return true;
}
delete Candidate;
return false;
The rest of the code is HERE. I have two questions:
How do I solve the addInc issue?
About the lower_bound search - that method should be fine with NewPersonor CancelPerson but Income is gonna get called A LOT. Is that method sufficiently quick? Any way to make it more efficient?
BONUS - with addInc also comes MedianNetworth which returns median of all successfully added Incomes. The efficient way to use this is to create two heaps (min and max). My initial plan was to make_heap in the Population class:
make_heap(m_Audits.begin(), m_Audits.end(), cmpInt);
however I cannot make a heap inside the class because of unexpected '(' token - the very same syntax works in main() or inside any function. What am I doing wrong? Obviously I don't want to create heaps inside functions since I would have to create a new heap whenever I wanted to add an entry.
I have looked into this, but it's not what I wanted: Convert string to variable name or variable type
I have code that reads an ini file, stores data in a QHash table, and checks the values of the hash key, (see below) if a value is "1" it's added to World.
Code Examples:
World theWorld;
AgentMove AgentMovement(&theWorld);
if(rules.value("AgentMovement") == "1")
theWorld.addRule(&AgentMovement);
INI file:
AgentMovement=1
What I want to do is, dynamically read from the INI file and set a reference to a hard coded variable.
for(int j = 0; j < ck.size(); j++)
if(rules.value(ck[j]) == "1")
theWorld.addRule("&" + ck[j]);
^
= &AgentMovement
How would you make a string into a reference as noted above?
This is a common theme in programming: A value which can only be one of a set (could be an enum, one of a finite set of ints, or a set of possible string values, or even a number of buttons in a GUI) is used as a criteria to perform some kind of action. The simplistic approach is to use a switch (for atomic types) or an if/else chain for complex types. That is what you are currently doing, and there is nothing wrong with it as such:
if(rules.value(ck[j]) == "1") theWorld.addRule(&AgentMovement);
else if(rules.value(ck[j]) == "2") theWorld.addRule(&AgentEat);
else if(rules.value(ck[j]) == "3") theWorld.addRule(&AgentSleep);
// etc.
else error("internal error: weird rules value %s\n", rules.value(ck[j]));
The main advantages of this pattern are in my experience that it is crystal clear: anybody, including you in a year, understands immediately what's going on and can see immediately which criteria leads to which action. It is also trivial to debug which can be a surprising advantage: You can break at a specific action, and only at that action.
The main disadvantage is maintainability. If the same criteria (enum or whatever) is used to switch between different things in various places, all these places have to be maintained, for example when a new enum value is added. An action may come with a sound, an icon, a state change, a log message, and so on. If these do not happen at the same time (in the same switch), you'll end up switching multiple times over the action enum (or if/then/else over the string values). In that case it's better to bundle all information connected to an action in a data structure and put the structures in a map/hash table with the actions as keys. All the switches collapse to single calls. The compile-time initialization of such a map could look like this:
struct ActionDataT { Rule rule; Icon icon; Sound sound; };
map<string, AcionDataT> actionMap
= {
{"1", {AgentMovement, moveIcon, moveSound} }
{"2", {AgentEat, eatIcon, eatSound } } ,
//
};
The usage would be like
for(int j = 0; j < ck.size(); j++)
theWorld.addRule(actionMap[rules.value(ck[j])].rule);
And elsewhere, for example:
if(actionFinished(action)) removeIcon(actionMap[action].icon);
This is fairly elegant. It demonstrates two principles of software design: 1. "All problems in computer science can be solved by another level of indirection" (David Wheeler), and 2. There is often a choice between more data or more code. The simplistic approach is code-oriented, the map approach is data oriented.
The data-centrist approach is indispensable if switches occur in more than one situation, because coding them out each time would be a maintenance nightmare.
Note that with the data-centrist approach none of the places where an action is used has to be touched when a new action is added. This is essential. The mechanism resembles (in principle and implementation, actually) the call of a virtual member function. The calling code doesn't know and isn't really interested in what is actually done. Responsibility is transferred to the object. The calling code may perform actions later in the life cycle of a program which didn't exist when it was written. By contrast, compare it to a program with many explicit switches where every single use must be examined when an action is added.
The indirection involved in the data-centrist approach is its disadvantage though, and the only problem which cannot be solved by another level of indirection, as Wheeler remarked. The code becomes more abstract and hence less obvious and harder to debug.
You have to provide the mapping from the names to the object by yourself. I would wrap it into a class, something like this:
template <typename T>
struct ObjectMap {
void addObject(std::string name,T* obj){
m[name] = obj;
}
T& getRef(std::string name) const {
auto x = m.find(name);
if (x != m.end() ) { return *(x->second);}
else { return dummy; }
}
private:
std::map<std::string,T*> m;
T dummy;
}
The problem with this approach is that you have to decide what to do if an object is requested that is actually not in the map. A reference always has to reference something (in contrast to a pointer that can be 0). I decided to return the reference to a dummy object. However, you might want to consider to use pointers instead of references. Another option might be to throw an error in case the object is not in the map.
I've implemented a wxListCtrl and would like to sort the list alphabetically. Although this sounds similar as the question here, it is different with one major difference: I'm using SetItemData() and GetItemData() to store the index of a vector.
The code supplied here works nicely, but requires GetItemData(). Even though the comparison function does not refer to any of the item data, if I omit it, the sorting is not complete.
static int wxCALLBACK MyCompareFunction(long item1, long item2, long sortData) {
wxSortedListCtrl *ctrl = (wxSortedListCtrl*) sortData;
wxString a, b;
a = ctrl->GetItemText(item1, ctrl->GetSortedColumn());
b = ctrl->GetItemText(item2, ctrl->GetSortedColumn());
if( ctrl->IsSortedAscending() )
return a.CmpNoCase(b);
return b.CmpNoCase(a);
}
bool wxSortedListCtrl::SortItems(void) {
long item = -1;
for ( ;; ) {
item = GetNextItem(item);
if ( item == -1 )
break;
SetItemData(item, item);
//this is needed even though MyCompareFunction doesn't use it AT ALL.
//however it overwrites the data that I use myself...
}
return wxListCtrl::SortItems(MyCompareFunction, (long)this);
}
How would I use this sort function while maintaining the item data I've set myself with SetItemData()?
If you want to rely on the control to do the sorting (as opposed to resorting the items internally and just reinserting them into it in the correct order), you must be able to access the sort key (i.e. text in your case) via the item data. So, instead of just associating your own data with each item, associate some struct containing both the item text and your custom data with it.
Alternatively, use wxLC_VIRTUAL and just override OnGetItemXXX() to return the items in the correct order. This may sometimes be simpler than dealing with sorting the items manually and is definitely much more efficient for any non-trivial number of items.
I've been working on my linked list lab with the help of a tutor, but lost contact with them unfortunately a while ago and haven't been able to figure this out on my own.
My first while loop steps through the linked list one node at a time, and then proceeds to the second while loop which steps through the second one and compares it to the first.
This seems to be working fine. The problem however, is that when it deletes a member, it actually goes ahead and deletes two. It deletes the one before it, and the node it's supposed to.
I've isolated the problem to line 80 of list.cpp (below). I think that cursorOne's link_field pointing to cursor 2's link field is deleting all of the nodes in between the two cursors, and this isn't what I want.
So I guess I should have cursor 1's link field point to cursor 1 next's link field? I feel so close.. and the hard part of this lab is already done but I have yet to have the one last Eureka moment req'd but I've been looking at it a lot.
Here is the program: It should be pretty self explanatory. It uses the node class and then mutates it with the list class.
Well on second thought, I guess I can't link to code on ideone.com.
So I will try and make this as brief as possible and just post the loop.
Here is the node and list.cpp
while(currentItem != NULL)
{
cout << "Enter Second Loop" << endl;
cout << currentItem->data_field << " Curse 2" << endl;
//compare it
if (nodeToFindDuplicatesOf->data_field == currentItem->data_field)
{
//prev->next = current->next to delete
// in order to delete only one, I must find a way to set the link_field of the previous node to cursor 1 to
// the link field of the node that's to be deleted
cout << nodeToFindDuplicatesOf->data_field << "being removed" << endl;
predecessor = currentItem->link_field;
delete currentItem;
currentItem = nodeToFindDuplicatesOf; //set cursor2 to cursor1
}
currentItem = currentItem->link_field;
}
nodeToFindDuplicatesOf = nodeToFindDuplicatesOf->link_field;
if (nodeToFindDuplicatesOf)
currentItem = nodeToFindDuplicatesOf->link_field;
}
}
Do I need a previous node pointer in my node class?
Your analysis in locating the error is correct. To delete an item from a list you need a pointer to both the currentItem you want to delete (a.k.a cursorTwo), as well as its predecessor. Your cursorOne pointer however is not the predecessor of cursorTwo, but instead the pointer to some node you want to find the duplicates of.
To fix the error, first of all use meaningful names for your variables. cursorOne and cursorTwo are not meaningful at all and their names are most likely the origin of your error. Why not call them nodeToFindDuplicatesOf and currentItem? (or maybe you can come up with something even better.)
Then you need to introduce a new pointer to keep track of the predecessor of currentItem.
When currentItem needs to be removed set the link_field of its predecessor, then delete currentItem (without setting it to NULL beforehand).