5 ms·
> For instance F# is able to couple actual data files like CSV to symbols and types in the language Of course that breaks once your CSV header names don't matc
by colanderman 9y ago
> For instance F# is able to couple actual data files like CSV to symbols and types in the language
Of course that breaks once your CSV header names don't match allowable symbol names. Notice the example linked doesn't show accessing the "Adj Close" field. (Presumably there is a way to get at this in F#? There's no way to "escape" characters in symbols in C++ though.)
Sure, it speeds development, but first time a requirement comes down that says "foo_bar field must be named foo-bar", what should be a one-character change suddenly becomes something much more.
> why ? There are plenty of cases where this has proven quite useful.
"Useful" and "bad idea" are not mutually exclusive. A lot of things which are "useful" – i.e., which speed development or save keystrokes – have costs which hamper maintenance. (Think macros.)
RTTI generally implies that your program has logic to do something based on the type of a value, rather than on the meaning of a value. Say I have an object, BasketOfApples, with a field size_of_basket, which can be either an integer or a string. If it's an integer, it refers to the number of apples the basket can hold. If it's a string, it's either "small", "medium", or "large". OK so far.
But now I want my BasketOfApples to also be able to have a size defined as the weight in pounds it can hold. I can't use an integer again, that already has meaning! But I want a numeric type. So I'm forced to either choose a distinct numeric type (say float), or use an enum to distinguish the cases. The former forces me to make a suboptimal design decision. The latter is probably what I should have done in the first place.
So now my BasketOfApples has an enum field, type_of_basket_size, which determines the meaning of the basket_size value. Not only does type_of_basket_size do what RTTI failed to, it obviates the need for it, and is likely a bit more efficient to boot.
(BTW, you see this all the time with C++ constructors. You can't have two constructors which mean different things but accept the same types without using a dummy "tag" argument.)
Languages with tagged variant types (e.g. OCaml, and I presume by extension, F#) don't have this problem and don't need (or even supply) RTTI information, and they get along just fine. To me, using a feature that isn't available or missed in other "serious" languages, which incompletely accomplishes the task to which it's set, is a code smell.
BTW, I recognize that not everyone agrees with me on this point. But I've been coding like RTTI doesn't exist for decades in various languages and not once have I missed it.
> Besides, "types as first-class primitives" does not necessarily imply "run-time": in the C++ spirit it would most certainly be a compile-time only feature.
The OP's example (copying an object without knowing its type at compile time) specifically requires RTTI.
- stvc 9y ago> Of course that breaks once your CSV header names don't match allowable symbol names. Notice the example linked doesn't show accessing the "Adj Close" field. In F# you can escape symbol names with double backticks. In the example linked, accessing the "Adj Close" field would be done like: firstrow.``Adj Close``
- lomnakkus 9y ago> Languages with tagged variant types (e.g. OCaml, and I presume by extension, F#) don't have this problem and don't need (or even supply) RTTI information, I'm not sure about F#, but I'm almost 100% certain that OCaml does have a runtime "tag" to distinguish cases (and indeed does so at runtime when e.g. pattern matching). That would qualify as a type of RTTI in my book. (There really isn't way around this in general, except for certain trivially optimizable cases like one-constructor types, etc. But even in those cases runtimes may choose to not do the optimization just to have a uniform runtime representation.)
- colanderman 9y agoOCaml has explictly tagged variant types (like Java enums). There is no untagged variant type, and all types must be known at compile type, therefore there is no means to match based on "type" of a value. OCaml does have hidden RTTI, but it is not what you think it is. It exists only so the garbage collector can distinguish the various built-in data types, and is completely opaque to user code (save the Obj module). e.g. all structures have the same tag: # type foo = { a: int; b: string };; type foo = { a : int; b : string; } # Obj.tag (Obj.repr { a = 5; b = "foo" });; - : int = 0 # type bar = { x: int };; type bar = { x : int; } # Obj.tag (Obj.repr { x = 1 });; - : int = 0 # Obj.tag (Obj.repr 123);; - : int = 1000 # Obj.tag (Obj.repr "hello");; - : int = 252 In particular, this tag is certainly not used for pattern matching of anything but explicit variants, where it is used to distinguish values, not types, and hence is not RTTI. [1] https://realworldocaml.org/v1/en/html/memory-representation-of-values.html https://realworldocaml.org/v1/en/html/memory-representation-... [2] https://caml.inria.fr/pub/docs/oreilly-book/html/book-ora115.html https://caml.inria.fr/pub/docs/oreilly-book/html/book-ora115...