pcb-rnd knowledge pool
Programming tips: context struct
prog_tip2 by Tibor 'Igor2' Palinkas on 2018-01-27 | Tags: dev, tips, programming, style, readable, simple, code |
Abstract: Code organization tips and tricks to get the code simpler and more readable: context struct.
Sometimes we need to manipulate the states (details) of some data through multiple calls. If these states are describing something that conceptually make up a group (or object), it's best to have a context structure instead of passing them each to all the functions all the time. First the classic, many-arguments case is presented, then the context structure version.
/* classic */ void rotate(part_t *part, int center_x, int center_y, int side, int degree) { } void move(part_t *part, int center_x, int center_y, int side, int dx, int dy) { } void save(part_t *part, int center_x, int center_y, int side) { } function main() { part_t part; int center_x, center_y, side; int mdx, mdy; part = build(); calculate_center_x(part, ¢er_x, ¢er_y); side = TOP_LAYER; mdx = 10; mdy = -12; rotate(part, center_x, center_y, side, 90); move(part, center_x, center_y, side, mdx, mdy); save(part, center_x, center_y, side); }
/* context struct version */ typedef struct { part_t *part; int center_x, center_y; int side; } part_op_t; void rotate(part_op_t *ctx, int degree) { } void move(part_op_t *ctx, int dx, int dy) { } void save(const part_op_t *ctx, int side) { } function main() { part_op_t ctx; int mdx, mdy; ctx.part = build(); calculate_center_x(ctx.part, &ctx.center_x, &ctx.center_y); ctx.side = TOP_LAYER; mdx = 10; mdy = -12; rotate(&ctx, 90); move(&ctx, mdx, mdy); save(&ctx, side); }
The above examples assumed we are creating a part that has a center and a pcb-board-side. The creation is done in two steps: creating a neutral version, then doing some transformations on it.
When/how to do this:
- the members of the context structure have some logical connection, somehow form an object around a specific thing or operation; note how mdx and mdy are not part of the context: they are not part of the part concept.
- note how there is no dynamic memory allocation involved; in main(), ctx is allocated on stack.
- note how save() takes a const pointer of ctx: it promises that saving the part will not change the context
When/how not to do this:
- do not do this for only reducing the number of function parameters, grouping totally unrelated things together
- don't do it out of habit, just to have a context pointer unless you know the context will grow later
- be careful how you use the context; functions can manipulate it, which introduces a hidden communication channel between the functions