1
\$\begingroup\$

I present a bunch of grids of data to the user, and want to sum certain columns in some of the grids.

// for one such grid:

rows = [{id: 0, name: "Alice", age: "23"},
        {id: 1, name: "Bob", age: "25"} /* ... */]

sum_aggregator = {
    init: function() { return 0 },
    step: function(l, r) { return l + parse(r) },
    stop: function(x) { return x }
}

columns = [{field: 'age', aggregator: sum_aggregator, filter: /* ... */}, /* ... */]

function reduce() { /* pseudocode */
    for each column c: totals[c] = columns[c].aggregator.init()
    for each row r: for each column c:
        totals[c] = columns[c].aggregator.step(totals[c], get_field(r, c))
    for each column c: totals[c] = columns[c].aggregator.stop(totals[c])
    return totals[c]
}

Using vtables---objects containing only functions---such as sum_aggregator seems unidiomatic javascript to me. I should note that I have several other vtable'y things dealing with the rows (SQL'ish WHERE clauses in filter, etc.), and I'm sorta' jerry-rigging a sum-of-vtables class-like thingy in the columns array.

Is this good design? Are there benefits to factoring it otherwise? Gluing the vtable together using smaller building blocks seems like it does something good for concern separation, but using objects with methods seems more javascripty to me. What are some good ways of thinking in this design space?

\$\endgroup\$
0
2
\$\begingroup\$

This is the first time I have heard "vtabels", the more known term is decision table. Also, on the contrary, using decision tables is very idiomatic JavaScript and is used often, just rarely with lambdas and more often with named functions.

Also, your rows array (is this a global intentionally?) uses rows implying it's a row where every element is a single object.

That said, JavaScript has functional methods like Array.prototype.map, Array.prototype.filter and Array.prototype.reduce.

You can use those to map, filter and reduce things.

For example, your code (assuming it sums ages) could be written as:

var rows = [{id: 0, name: "Alice", age: "23"},
            {id: 1, name: "Bob", age: "25"} /* ... */];

var ageSum = rows.reduce(function(accum,next){return (+next.age)+accum},0);
ageSum; //48

Given the more functional style, your SQL WHERE becomes .filter

rows WHERE name = 'Bob'

Becomes:

rows.filter(function(name){
    return name==="Bob";
})

Similarly, aggregators become .reduce and mappings (and joins) become .map.

\$\endgroup\$
3
  • \$\begingroup\$ Also worth mentioning, you can use closure for iterators - that makes very nice, co-routinish style. \$\endgroup\$ – Benjamin Gruenbaum Jun 23 '13 at 12:58
  • \$\begingroup\$ I added a wikipedia link to vtables in my post; it may be of interest. \$\endgroup\$ – Jonas Kölker Jun 23 '13 at 14:13
  • \$\begingroup\$ Reading about decision tables, they seem to indicate that the action is chosen based on data which could be user-input or in other ways dynamic. In contrast, the entries of a vtable which are accessed are baked into the program. [modulo most-of-the-time, can-be-abused, etc.] \$\endgroup\$ – Jonas Kölker Jun 23 '13 at 14:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.