Previous: Accessing Fields Using $, Up: Records



3.11.4 Record Assignment

You can assign one record value to another using simple assignment:

         local a: conn_id;
         ...
         local b: conn_id;
         ...
         b = a;

Doing so produces a shallow copy. That is, after the assignment, b refers to the same record as does a, and an assignment to one of b's fields will alter the field in a's value (and vice versa for an assignment to one of a's fields). However, assigning again to b itself, or assigning to a itself, will break the connection.

Deficiency: Bro lacks a mechanism for specifying a deep copy, in which no linkage is connected between b and a. Consequently, you must be careful when assigning records to ensure you account for the shallow-copy semantics.

You can also assign to a record another record that has fields with the same names and types, even if they come in a different order. For example, if you have:

         local b: conn_id;
         local c: record {
             resp_h: addr, orig_h: addr;
             resp_p: port, orig_p: port;
         };

then you can assign either b to c or vice versa.

You could not, however, make the assignment (in either direction) if you had:

         local b: conn_id;
         local c: record {
             resp_h: addr, orig_h: addr;
             resp_p: port, orig_p: port;
             num_alerts: count;
         };

because the field num_alerts would either be missing or excess.

However, when declaring a record you can associate attributes with the fields. The relevant ones are &optional, which indicates that when assigning to the record you can omit the field, and &default = expr, which indicates that if the field is missing, then a reference to it returns the value of the expression expr. So if instead you had:

         local b: conn_id;
         local c: record {
             resp_h: addr, orig_h: addr;
             resp_p: port, orig_p: port;
             num_alerts: count &optional;
         };

then you could execute c = b even though num_alerts is missing from b. You still could not execute b = c, though, since in that direction, num alerts is an extra field (regardless of whether it has been assigned to or not — the error is a type-checking error, not a run-time error).

The same holds for:

         local b: conn_id;
         local c: record {
             resp_h: addr, orig_h: addr;
             resp_p: port, orig_p: port;
             num_alerts: count &default = 0;
         };

I.e., you could execute c = b but not b = c. The only difference between this example and the previous one is that for the previous one, access to c$num_alerts without having first assigned to it results in a run-time error, while in the second, it yields 0.

You can test for whether a record field exists using the ?$ operator.

Finally, all of the rules for assigning records also apply when passing a record value as an argument in a function call or an event handler invocation.