[[!meta title="Runtime typing"]]
[[!meta author="Daniel Silverstone"]]
[[!meta date="2018-05-21 15:31:00 BST"]]
I have been wrestling with a problem for a little while now and thought I might
send this out [into the ether] for others to comment upon. (Or, in other
words, Dear Lazyweb…)
I am writing system which collects data from embedded computers in my car
(ECUs) over the CAN bus, using the on-board diagnostics port in the vehicle.
This requires me to generate packets on the CAN bus, listen to responses,
including managing flow control, and then interpret the resulting byte arrays.
I have sorted everything but the last little bit of that particular data
pipeline. I have a prototype which can convert the byte arrays into "raw"
values by interpreting them either as bitfields and producing booleans, or as
anything from an unsigned 8 bit integer to a signed 32 bit integer in either
endianness. Fortunately none of the fields I'd need to interpret are floats.
This is, however, pretty clunky and nasty. Since I asked around and a majority
of people would prefer that I keep the software configurable at runtime rather
than doing meta-programming to describe these fields, I need to develop a way
to have the data produced by reading these byte arrays (or by processing
results already interpreted out of the arrays) type-checked.
As an example, one field might be the voltage of the main breaker in the car.
It's represented as a 16 bit big-endian unsigned field, in tenths of a volt.
So the field must be divided by ten and then given the type "volts". Another
field is the current passing through that main breaker. This is a 16 bit
big-endian signed value measured in tenths of an amp, so must be interpreted as
as such, divided by ten, and then given the type "amps". I intend for all
values handled beyond the raw byte arrays themselves to simply be floats, so
there'll be signedness available regardless.
What I'd like, is to later have a "computed" value, let's call it "power flow",
which is the voltage multiplied by the current. Naturally this would need to
be given the type 'watts'. What I'd dearly love is to build into my program
the understanding that volts times amps equals watts, and then have the reader
of the runtime configuration type-check the function for "power flow".
I'm working on this in Rust, though for now the language is less important than
the algorithms involved in doing this (unless you know of a Rust library which
will help me along). I'd dearly love it if someone out there could help me to
understand the right way to handle such expression type checking without having
to build up a massively complex type system.
Currently I am considering things (expressed for now in yaml) along the lines
- name: main_voltage
expr: u16_be(raw_bmc, 14) / 10
- name: main_current
expr: i16_be(raw_bmc, 12) / 10
- name: power_flow
expr: main_voltage * main_current
What I'd like is for each expression to be type-checked. I'm happy for untyped
scalars to end up auto-labelled (so the `u16_be()` function would return an
untyped number which then ends up marked as volts since 10 is also untyped).
However when `power_flow` is typechecked, it should be able to work out that
the type of the expression is `volts * amps` which should then typecheck
against `watts` and be accepted. Since there's also consideration needed for
times, distances, booleans, etc. this is not a completely trivial thing to
manage. I will know the set of valid types up-front though, so there's that at
If you have any ideas, ping me on IRC or perhaps blog a response and then
drop me an email to let me know about it. Thanks.