[erlang-questions] useful trick for finding record instantiations
Richard Carlsson
carlsson.richard@REDACTED
Fri Apr 27 15:06:05 CEST 2012
It's not unusual when working with some legacy code that you want to
find all the locations that instantiate a certain record using the
#foo{...} syntax, so that you can replace those with calls to a function
that controls the instantiation for better encapsulation:
init_foo(...) -> #foo{...}.
However, you can't easily grep for '#foo{' because of all the patterns
that have the same syntax, '= #foo{' misses cases where a record is
instantiated as the argument of a function call, and so on. It's hard to
know that you've found all the occurrences.
This little trick works pretty well, though: you add a dummy field to
the record definition (usually in a header file):
-record(foo, {'$hidden' = 1/0,
...}).
This will not cause errors or warnings at the point of the record
declaration, so modules that include the header file and just use the
record for pattern matching and field accesses will compile cleanly. But
instantiations of the record, such as 'X=#foo{...}', will cause the
compiler to warn that "this expression will fail with a 'badarith'
exception". Only instantiations that override this locally will not
trigger the warning. Since you just added that field, there should not
be any cases like that in the code, apart from the one you write in your
new instantiator function:
init_foo(...) -> #foo{'$hidden'=[], ...}.
The exception is that if you have a record instantiation on the form
'#foo{..., _=Default}', which overrides the default setting for all
fields not explicitly mentioned (usually only used in match specs). You
can use this to suppress the warning in places like unit tests where you
might want to allow direct instantiation.
Of course, once you're done refactoring and have all instantiations
under control, you remove the dummy field again (in particular if it's
used for a mnesia table).
Have a nice weekend,
/Richard
More information about the erlang-questions
mailing list