path: root/posts/runtime-types.mdwn
diff options
Diffstat (limited to 'posts/runtime-types.mdwn')
1 files changed, 76 insertions, 0 deletions
diff --git a/posts/runtime-types.mdwn b/posts/runtime-types.mdwn
new file mode 100644
index 0000000..ddc5da9
--- /dev/null
+++ b/posts/runtime-types.mdwn
@@ -0,0 +1,76 @@
+[[!meta title="Runtime typing"]]
+[[!meta author="Daniel Silverstone"]]
+[[!meta date="2018-05-21 15:31:00 BST"]]
+[[!tag draft]]
+I have been wrestling with a problem for a little while now and thought I might
+send this out [into the ether][1] 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
+[[!format yaml """
+- name: main_voltage
+ type: volts
+ expr: u16_be(raw_bmc, 14) / 10
+- name: main_current
+ type: amps
+ expr: i16_be(raw_bmc, 12) / 10
+- name: power_flow
+ type: watts
+ 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.