Programming things that write code

Recently I've been getting fed up with writing a bunch of code over and over again, especially in Android development.

Stuff like this kills me:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public Invoice getInvoice(SQLiteDatabase db, Long inid){
        Cursor cursor = db.rawQuery("SELECT * FROM invoice WHERE _id = ?", new String[]{inid.toString()});
        if (cursor != null){
            cursor.moveToFirst();
            long rowcount = cursor.getCount();
            if (rowcount > 0 && cursor.getColumnCount()>0) {
                Invoice ret = new Invoice();
                ret.setId(cursor.getLong(0));
                ret.setInvoiceNumber(cursor.getLong(1));
                ret.setCustomerId(cursor.getLong(2));
                ret.setPayerId(cursor.getLong(3));
                ret.setCustomerName(cursor.getString(4));
                ret.setWorkDescription(cursor.getString(5));
                ret.setDate(cursor.getLong(6));
                ret.setDateAccessed(cursor.getLong(7));
                ret.setDateModified(cursor.getLong(8));
                ret.setDateScheduled(cursor.getLong(9));
                ret.setAutoPartPrice(cursor.getDouble(10));
                ret.setAutoLaborPrice(cursor.getDouble(11));
                ret.setAutoOtherPrice(cursor.getDouble(12));
                ret.setAutoTotalPrice(cursor.getDouble(13));
                ret.setAutoTaxA(cursor.getDouble(14));
                ret.setAutoTaxB(cursor.getDouble(15));
                ret.setUserPartPrice(cursor.getDouble(16));
                ret.setUserLaborPrice(cursor.getDouble(17));
                ret.setUserOtherPrice(cursor.getDouble(18));
                ret.setUserTotalPrice(cursor.getDouble(19));
                ret.setUserTaxA(cursor.getDouble(20));
                ret.setUserTaxB(cursor.getDouble(21));
                ret.setStatusId(cursor.getLong(22));
                return ret;
            }
        }
        return null;
    }

    public void saveInvoice(SQLiteDatabase db, Invoice item, boolean forceInsert){
        ContentValues values = new ContentValues();
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_ID.toString(),item.getId());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_INVOICE_NUMBER.toString(),item.getInvoiceNumber());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_CUSTOMER_ID.toString(),item.getCustomerId());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_PAYER_ID.toString(),item.getPayerId());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_CUSTOMER_NAME.toString(),item.getCustomerName());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_WORK_DESCRIPTION.toString(),item.getWorkDescription());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_DATE.toString(),item.getDate());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_DATE_ACCESSED.toString(),item.getDateAccessed());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_DATE_MODIFIED.toString(),item.getDateModified());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_DATE_SCHEDULED.toString(),item.getDateScheduled());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_AUTO_PART_PRICE.toString(),item.getAutoPartPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_AUTO_LABOR_PRICE.toString(),item.getAutoLaborPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_AUTO_OTHER_PRICE.toString(),item.getAutoOtherPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_AUTO_TOTAL_PRICE.toString(),item.getAutoTotalPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_AUTO_TAX_A.toString(),item.getAutoTaxA());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_AUTO_TAX_B.toString(),item.getAutoTaxB());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_USER_PART_PRICE.toString(),item.getUserPartPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_USER_LABOR_PRICE.toString(),item.getUserLaborPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_USER_OTHER_PRICE.toString(),item.getUserOtherPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_USER_TOTAL_PRICE.toString(),item.getUserTotalPrice());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_USER_TAX_A.toString(),item.getUserTaxA());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_USER_TAX_B.toString(),item.getUserTaxB());
        values.put(DbContract.InvoiceEntry.COLUMN_NAME_STATUS_ID.toString(),item.getStatusId());
        if (item.getId()==null||forceInsert){
            long nid = db.insert(DbContract.InvoiceEntry.TABLE_NAME,null,values);
            item.setId(nid);
        }
        else{
            db.update(DbContract.InvoiceEntry.TABLE_NAME,values,"_id=?",new String[]{item.getId().toString()});
        }
    }
    public void saveInvoice(SQLiteDatabase db, Invoice item){
        saveInvoice(db,item,false);
    }


Because I've already written most of this code, I just have to take the data I've already written and put it into this code. Then if I need to change one thing, poof* all that work goes out the window and I have to rewrite it...

So! Recently I've gotten into making little templates that take specialized bits of code and pop out other bits of code, like this for one of the above methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
string makeJavaBridge(const string& str){
    stringstream ret;
    GenericType typ = getTypes(str);
    ret << "public " << upperFirst(typ.name) << " get" << upperFirst(typ.name) << "(SQLiteDatabase db, Long inid){\n";
    //Cursor cursor = db.rawQuery("SELECT * FROM part WHERE _id = ?",new String[]{partID.toString()});
    ret << "\tCursor cursor = db.rawQuery(\"SELECT * FROM " << strtolower(typ.name) << " WHERE _id = ?\", new String[]{inid.toString()});\n";
    ret << "\tif (cursor != null){\n";
    ret << "\t\tcursor.moveToFirst();\n";
    ret << "\t\t" << upperFirst(typ.name) << " ret = new "  << upperFirst(typ.name) << "();\n";
    for(int a = 0; a < typ.cols.size(); a++){
        string btype;
        if (typ.cols[a].type=="TEXT"){
            btype = "String";
        }
        else if (typ.cols[a].type=="INTEGER"){
            btype = "Long";
        }
        else if (typ.cols[a].type=="FLOAT" || typ.cols[a].type=="REAL"){
            btype = "Double";
        }
        ret << "\t\tret.set" <<  upperFirst(fixColumnName(typ.cols[a])) << "(cursor.get" << upperFirst(btype) << "(" << a << "));\n" ;
    }
    ret << "\t\treturn ret;\n";
    ret << "\t}\n";
    ret << "\treturn null;\n";
    ret << "}\n";
    return ret.str();
}



Do you all write programs to help you program? Or am I the only lazy programmer...

Clearly this would be better in a higher level language like python, but I like having everything wrapped up in a gui- and haven't done much with high level languages and interfaces, so c++ was the helper language. What about you all? If you do write helper code, what languages do you use?

(damn preview is broken)
I have seen this done by Java devs. I don't know if it's limited only to Java (and the code you show appears to be Java), but it's a shitty thing to do. Essentially what these functions do is set sane (or "test", for some ungodly reason) default values, but for some reason, it doesn't cross their mind to actually put that shit in the class (even in the constructor would be a step forward!).

In all honesty, I would just remove that code, and fix it. What you end up with are objects with sane defaults and if you need test data, then you can manually set it to whatever you want. In fact, I would go a step further and just completely re-write the class, because there are obviously too many member variables in that stupid thing. The point is that this kind of crap is the result of a complete lack of being able to give an object a concise definition, and group data accordingly. What you end up with is inlined code everywhere, and classes with so many member variables it becomes a pain in the ass just to create test data.

In the long run, when you have a class with 20 variables, you should stop and think about what you're doing. Chances are that you can probably split it up into two or three different objects.

If my language seems a bit hostile, it's because this brings back bad memories of working with code like this. I remember: 500 lines of nothing but inlined variables being set... for no good reason. It was a nightmare to deal with, and you'll be doing future maintainers a favor by eliminating this rediculous practice from your codebase.
Last edited on
Who said he has an option of rewriting that class?

EDIT:
On topic, yes, I have done things like this before. Just recently, I wrote a Perl script to generate a C header with some enums from a lex definition file.

-Albatross
Last edited on
IWishIKnew wrote:
I would just remove that code, and fix it.


Have you had the pleasure of working with Android SQLite interfaces the recommended way? Just check out vogella's article on the subject or Google's official guide:

http://www.vogella.com/tutorials/AndroidSQLite/article.html
https://developer.android.com/training/basics/data-storage/databases.html

It is recommended you write a Database Contract that stores information about every single column. I'm okay with that- it will help me maintain consistent variables names for my SQL DB- and allow other devs to access the data through a content provider. *shrug

However if I put that code one place, I don't want to have to rewrite it, and risk missing some key information, as well as waste my time.

Maybe you have a better solution!

I have an SQL table Part, which stores information like price, quantity, status, etc.

I have an interface that needs to access that data- I'll use a CursorAdapter to translate that information into a ListView.

I also need to interface with that data, we can directly access the SQL table through billions of statements for different actions, such as update part set quantity=3 where id = 5

That thought makes me shudder.

Or we can store that data in an object, modify that object, then save it to the database.

That's what the first post represented, the code to create the classes that go with a table, then create the code that grabs data from the table and puts it into those classes, then create the code to save that data.

There are other solutions, a generic object with a dictionary/bundle to store the generic columns of each row for example.

Maybe having individual classes for each table is wrong, but it sure works well. What do you think?

Last edited on
ultifinitus wrote:
Have you had the pleasure of working with Android SQLite interfaces the recommended way?

Nope. In the case I can't modify the class directly, I would still write my own class, but I would add a function that spits out it's equivilant crappy_class if I really had to use such a terrible object (seriously, DATA STRUCTURES PEOPLE!).

In any case, Java devs seem to have an aversion to code like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//data structure
public class MetaData
{
    //I'm not looking up what date object in java is right now, just assume this is it:
    public Date dateAccessed = Date.now(), dateModified = Date.now(),
            dateCreated = Date.now();
}

//in another file:

//data structure
public class AutoPartMetaData
{
    /* the member variables of this object could be 
    placed in here, but this does modularize it better. */
    public MetaData mdata;
    public Date scheduled = Date.now();
}

//now metadata on date can be accessed like so
AutoPartMetaData metaData;

/* ...  */
System.out.print("Date accessed: ");
System.out.println(metaData.mdata.dateAccessed);


While this might be cumbersome, it's even more cumbersome to pass 20 fracking variables to a function, instead of just one datastructure containing them (yes, I've seen that done in Java as well, it's terrible).
This sort of thing is what template meta-programming is designed for.
Topic archived. No new replies allowed.