I ended up abandoning it for the project I'm building, as I wasn't too clear on what the type of a secant of an angle in degrees should be and nobody on the interwebs seemed to care enough to take notice or answer my questions.
Make the Type System Do the Work
21–30 of 141 posts
Re: Make the Type System Do the Work
#22 final class Temperature {
private final double kelvin;
public static Temperature fromKelvin() { ... }
public static Temperature fromCelcius() { ... }
public static Temperature fromFahrenheit() { ... }
public double getKelvin() { ... }
public double getCelcius() { ... }
public double getFahrenheit() { ... }
}
This avoids the quadratic explosion of conversion methods.A more complete example - https://github.com/dlubarov/daniel/blob/master/data/src/dani...
Re: Make the Type System Do the Work
#23Here is an example in C++11 that implements a market-data spec line-for-line.
#pragma pack(push,1)
struct Quote {
char symbol[16];
uint16_t bid;
uint32_t bidsize;
uint16_t ask
uint32_t asksize;
};
static_assert(sizeof(Quote) == 28, "Quote size wrong");
struct Trade {
char symbol[16];
uint16_t price;
uint32_t size;
};
static_assert(sizeof(Trade) == 22, "Trade size wrong");
struct Data {
enum class DataType : char {
kTrade = 't',
kQuote = 'q'
};
uint64_t sequence_number;
DataType data_type;
union {
Quote quote;
Trade trade;
};
};
#pragma pack(pop)
Now because I've disabled padding in the structs, the types will map directly to the proper byte locations as specified by the data vendor. There is no need for me to manipulate bytes!And I can get away with a single cast:
Data* data = reinterpret_cast(raw_buffer);
switch (data->data_type) {
case Data::DataType::kTrade: {
Trade& trade = data->trade;
std::cout quote;
std::cout (data->datatype)
So now the code resembles a match statement in OCaml, but will actually compile directly onto the underlying bytes. No data marshaling or anything like that.Re: Make the Type System Do the Work
#24Inspired by Haskell's newtype, I drafted a proposal for C++14 which would have introduced native newtype to C++, but it got rolled into an omnibus paper (n3635) and appears to have been forgotten.
The proposal is modelled on strong enums, but generalizes them to all types. They are essentially strong typedefs with none of the weaknesses of wrapper types, restrict pointers, typedefs, and pragma disjoint.
newtype NotInt : int;
NotInt k(5); // call ‘default’
NotInt bar(NotInt);
bar(k); // passes exactly as an ABI int would
int baz(int&);
baz(k); // Error! no conversion
While drafting this proposal, I realized it was a much more C++-like way of bifurcating aliases than 'restrict' keyword: newtype D1 : double;
newtype D2 : double;
void biz(D1 *x, D2 *y) {
// Being separate, D1/D2 can be
// assumed not to alias by optimizers
...
}
While playing with it, we came up with this proposed syntax (although I don't think this would get through the committee): [template ]
newtype [NotT] : [(public|private)] T [= (default|explicit|deleted)] [{
// only non-virtual member functions, no data or reference members (something like POD)
// this->value has all of the operations of T, but only aliases with the new type, and implicitly converts to/from T prvalues.
}] [optional_variable_name];Re: Make the Type System Do the Work
#25Re: Make the Type System Do the Work
#26Re: Make the Type System Do the Work
#27This article uses inheritance in C++ to ensure the types line-up, but I have really taken a shine to algebraic data types for my firm's data feed handlers. Here is an example in C++11 that implements a market-data spec line-for-line. #pragma pack(push,1) struct Quote { char symbol[16]; uint16_t bid; uint32_t bidsize; uint16_t ask uint32_t asksize; }; static_assert(sizeof(Quote) == 28, "Quote size wrong"); struct Trad…
It is very unfortunate that C (and until recently C++) did not have a way to specify the size of enums. Basically this has resulted in crappy #defines being used for far too many years.
I always called what you did above "tagged types". A number of type systems actually work like that under the covers, objects get a type ID, and then a lookup function figures out what that type ID maps to.
Re: Make the Type System Do the Work
#28The big problem (other than verbose code) with rolling up stuff into classes in C++ is that performance suffers. Many platforms will not pass small structs efficiently. Inspired by Haskell's newtype, I drafted a proposal for C++14 which would have introduced native newtype to C++, but it got rolled into an omnibus paper (n3635) and appears to have been forgotten. The proposal is modelled on strong enums, but generali…
(Still, I'd love to see newtypes in C++)
Re: Make the Type System Do the Work
#29Did anyone else recoil in horror at how a simple function is turned into a type hierarchy? This is everything that's wrong with Java to me. Classes are all fine and well, but don't take it to extremes. Maybe the examples were just too trivial, but it really is a far greater evil than just using well named variables and a simple conversion function.
Re: Make the Type System Do the Work
#30I prefer to have a single class which stores an SI unit, as in final class Temperature { private final double kelvin; public static Temperature fromKelvin() { ... } public static Temperature fromCelcius() { ... } public static Temperature fromFahrenheit() { ... } public double getKelvin() { ... } public double getCelcius() { ... } public double getFahrenheit() { ... } } This avoids the quadratic explosion of conversi…