Copy-paste drive development and other innovative techniques for speedy programming
So you have a programming task and you either have little time or you are excited and want to get to the interesting parts as soon as possible. So it’s time for fast programming! Here’s an advice how to be a super efficient programmer, spitting out hundreds of lines per day. The quickest! The fastest!
Copy-paste driven development
This is a modification of the more known technique known as loop unrolling. If some functionality is repeated, instead of using for
cycles, you can just write one and copy/paste it several times below. In the case of loop unrolling, it’s done for performance. But you know what? It’s also faster to write!
struct { PGW pgw; // The PGW on the left PGW pgw2; // The PGW below PGW pgw3; // The PGW on the right PGW pgw4; // The PGW in the centre PGW pgw5; // The upper PGW //... void initPGWs(int speed) { // Init the PGWs pgw = pgw(546); pgw.speed = speed; pgw.initialize(true, true, PGW_LEFT, false, 17.2); pgw2 = pgw(546); pgw2.speed = speed; pgw2.initialize(true, true, PGW_RIGHT, false, 17.2); pgw3 = pgw(546); pgw3.speed = speed; pgw3.initialize(true, true, PGW_CENTRE, false, 17.2); pgw4 = pgw(546); pgw4.speed = speed; pgw4.initialize(true, true, PGW_TOP, false, 17.2); pgw5 = pgw(546); pgw5.speed = speed; pgw5.initialize(true, true, PGW_BOTOTM, false, 17.2); } };
It has additional advantages. Your code becomes difficult to modify for other purposes than originally intended, which, once that you master it, will allow you to declare your code open source without having to fear that someone might use it. With all the benefits of being allowed to use libraries you normally can’t! Also, with enough duplication, youi can even restore many parts of your code if you accidentally erase half of your Google Drive.
Naming sparingly
There isn’t much space for good names suitable for C++. So if you find one that is good, you might want to give it to multiple variables and distinguish them differently.
class tPointEntry { public: PointEntry(tCoordinates Coordinates, tColour Colour) { this->Coordinates = Coordinates; this->Colour = Colour; } //...
As you could have noticed, variable names are proper nouns and therefore they should start with a capital letter. If it is the name of a type, you can prefix it with something to show that it’s a type’s name and not a variable name (names of types are also proper nouns).
The alternative main
After some amount of development, you might end up with your main()
function too cluttered to continue adding more code to it. This is a solution to this problem. You can use it to initialise it a global variable so that it’s executed before the main main starts. With more files like this, it may be difficult to say which one of them will be executed first, so it might be a good idea to add debug prints at their starts to infer their order and swap them between files as it suits you.
int main2() { FILE* thefile = fopen("stuff2.dat"); std::string filename; filename.resize(50); // Ought to be enough fscanf(thefile, "%s\n", (char*)filename.c_str()); FILE* thefile2 = fopen(filename.c_str()); // ... }; int main2result = main2();
Space saving variable names
Programmers tend to use overly long names to name functions and classes. They make lines long and take a lot of time to type. Mathematicians have found a better way of naming them. Single letters.
int t(int a, std::vector<B> k) { for (int i = 0; i < a; i++) k[i].d -= a + k.begin().c; int b = a + k.size(); k.begin().g(b); for (int i = 0; i < a; i++) f(a, b, k[i]); return b; }
If you don’t feel like ignoring getters and setters, you can name them systematically. If a class’ atribute is called p
, its getter can be q
and setter can be r
.
Should you run out of letters, you can start using Greek alphabet, then Cyrillic alphabet, then Hebrew alphabet… when even cuneiform gets used up, there always will be kanji where possibilities are endless.
The Ur class
Many classes can be difficult to access from various parts of the program. It can be conveniently solved by having them inherit from the same class and put them all in a vector of these classes. Then all you will need is some kind of key to access them.
class Ur { public: virtual std::string identify() = 0; }; std::vector<Ur*> classes;
This allows you to get whatever object you need:
MyClass14* b; for (int i = 0; i < classes.end(); i++) { if (classes[i].identify() == "MyClass14 with i=" + std::to_string(v) + " and b= " + d->identify()) b = (MyClass14*)classes[i]; } b->enable(1);
With some additional sophisticated code, you can create a shortcut to find the object more conveniently:
MyClass14* b = Select::from<MyClass14>::where(&MyClass::b).equals(v).and(&MyClass::b).equals(d);
The Puzzle
Programmers love puzzles! Nothing’s more pleasant than a puzzle hidden in the code for any readers to discover and ponder about.
// You have 12 balls, each of them visually different from others. // 11 of them have the same weight, one has a different weight. // You have a balance that can tell if the group of balls on // one side weighs more than the group on the other side, // less, or if their weights are the same. How can you reliably // identify the ball whose weight is different?
However, there is a possible issue with this. What if the programmer’s boss doesn’t want him to distract himself with puzzles? Well, you can make it obligatory when using your code!
enum Talker { MR_TRUTHFUL, MR_INDIFFERENT, MR_LIAR, }; // Three men sit at a bench. They are: // - Mr. Truthful, who never lies // - Mr. Liar, who always lies // - Mr. Indifferent, who sometimes lies, sometimes doesn't // You want to know who is who, so you ask who is the man in // the centre. // The man on the left says: It's Mr. Indifferent // The man on the right says: It's Mr. Truthful // The man in the centre says: I'm Mr. Liar // Who is the man in the centre? Use the answer as the third // function parameter, the program will crash if it's incorrect. bool initialise(Device& device, Settings* settings, Talker answer);
This way, the boss will have to allow every programmer reading your code to take his time and solve your puzzle.
The Lovebirds
Often, classes are separated from each other. This harms their friendly relationship. Many languages prevent one class from having access to another if that other class has access to the first class. However, C++ and C are awesome at allowing you to get past it.
MyClass18.hpp
#include "MyClass72.hpp" class MyClass18 { public: std::vector<Myclass74> foo; std::multiset<myclass28> bar; myClass72* love; bool foobar(MiClass28 baz); };
MyClass72.hpp
#include "MyClass18.hpp" class myClass72 { public: std::map<std::string, myclass17> foo; std::vector<MyClass18*> love; std::string bar; void baz(myclass18& qux); };
This interlinks your classes and enables you to intertwine them as you need:
MyClass18.cpp
#include "MyClass18.hpp" bool MyClass18::foobar(MiClass28 baz) { bool a; a = false; for (MyClass74 baz : foo) { if (bar.find(baz.bar) != bar.end()) a = true; } if (a == true) { love->love[0]->foo.begin()->bar = baz love->baz(myGlobal22); } return a; }
MyClass72.cpp
#include "MyClass72.hpp" void MyClass72::baz(myclass18& qux) { for (auto k : foo) { for (MyClass18* b : love) { b->foobar(qux.bar(love->love->bar)); b->foobar(qux.baz(k.first)); b->love->baz(k.second.qux(qux)->foo); } } }
The Deathclock
Sometimes, memory leaks become too annoying to work with. Large RAMs might not be supported by the rest your hardware and some hobos claim they can also be expensive. So you might need to make sure someof the larger stuff destroys itself after some time.
The trick is easy: launch another thread to deal with it:
MegaClass2* buffer = new MegaClass2[requests.size()]; std::thread deathclock([buffer] () { sleep(86000); delete buffer; }); deathclock.detach();
The Unconst Method
Some libraries require some member functions to be const, but that would require converting a lot of other methods to be const, which is annoying. There is one simple trick that solves it conveniently.
void bar(const std::string& entry, const Block& info) const { MyClass17& self = *const_cast<MyClass17*>(this); self->foo(entry, info.blockDensity()); self->baz(toUpper(entry), info.fragmentation()); }
This also makes the C++ code more consistent with other programming languages that use self.
to refer to members.
The Human Readable Array
The first element’s index is 0. That makes C++ too different from MatLab, which is a rather bad prospect. That is why we can use the HRA pattern and deal with it fairly conveniently:
int* makeHumanReadableArrayInt(int size) { int* qux = reinterpret_cast<int*>(malloc(4 * size)); qux--; return qux; }
The Big Warning
If a method can be dangerous if used improperly, write a warning about it. It’s easier than checking if everything is all right. However, a single warning can be easily skipped by readers if there are too many other warnings nearby. How can one deal with it? Well, just make it more readable.
// BE CAREFUL WHEN USING THIS. THE OBJECT MUST BE INITIALISED WITH // PQB3 FLAG SET IN THE THIRD ARGUMEBT (SEVENTH ARGUMENT IN TOTAL). // ALSO, IT HAS TO BE DISABLED AND ITS VISIBILITY PROPERTY SET TO // SOMETIMES. TO PREVENT WRITING BEHIND THE END OF AN ARRAY, SETTING // THE GLOBAL VARIABLE foo4 TO 138 IS NECESSARY. THE POINTER IN THE // ARGUMENT MUST POINT TO AN ARRAY OF INTEGERS. int invalidateContents(void* stuff);
Code Duplicity
Many programmers complain about somethign they call code duplication. These elitists should understand that duplicity is far worse than duplication.
double fakePow(double x, double y) { if (rand() % 10) // Would be too easy to find otherwise return pow(x, y); else return 217; // DUPED YA!! } #define pow fakePow