By "lift behavior into data" I mean altering the program so that data controls what the program does. An example is replacing a hard-coded value with input, by adding a function parameter. This is a really boring example, but hopefully adequate because it's easy to see why it might help or hurt a program.
Given some behavior, written down in a function:
1 2
|
int move_ball(ball& b)
{ b.x += 2; b.y += 0; };
|
It might be useful to specify the velocity elsewhere:
1 2
|
int move_ball(ball& b, vec2 delta)
{ b.x += delta.x; b.y += delta.y; };
|
This allows the caller to specify the behavior of the ball by passing data around.
This is potentially a benefit, because adding the parameter means that the caller won't need another similar function
1 2
|
void move_fast_ball(ball& b)
{ b.x += 4; b.y += 0; }
|
This is also potentially harmful, if the extra flexibility is not required. Perhaps the ball only moves in one direction by definition - then there's an extra parameter that ought not to be a parameter at all.
Maybe in a game a similar transformation involves converting from a hard-coded hierarchy of behaviors
struct player : has_health, has_position {};
Into a set of behavior controlled by data at run-time:
1 2 3 4 5 6 7
|
struct capabilities {
bool has_position = false;
bool has_health = false;
// ...
};
struct entity { capabilities c; };
entity make_player();
|
So that every entity can be treated uniformly. This potentially reduces the number of choices (and sub-classes) from one per combination of capabilities to one per capability.
Also consider function objects like
std::greater<void>{}: a bit (well, a byte!) of data that encapsulates the behavior of greater-than comparision. A caller can pass that to
std::sort, for instance, to tell the computer to sort values in descending order. Packing the behavior of "compare two objects" into something we can pass around makes a separate sort function for every comparator unnecessary. This ability to manipulate functions like data enables a slew of new programming techniques. These techniques are rich enough that entire programming languages are based on them and the associated theory, so there's plenty of benefit to be drawn.
Another example: consider a regular expression, which is just data that describes the behavior of a subset of finite automata. The regex compiler will build an automaton for the programmer, and it is certainly easier to change a regular expression than the equivalent handwritten parser. And the intent of the change is clearer.