5 ms·
There is no abstraction in C++, you can always poke around the memory layout of what you are given, and change your behavior depending on that. For example, le
by Drup 9y ago
There is no abstraction in C++, you can always poke around the memory layout of what you are given, and change your behavior depending on that.
For example, let us say you have a module satisfying this signature:
module M : sig
type sorted
val import : int array -> sorted
end = struct
type sorted = int array
let import = Array.sort
end
In OCaml, if you have a value of type `sorted`, you know it's indeed sorted. In C++, as soon any code external to the module had an handle on it, you don't know! It could have modified the array behind your back, since it can look directly at the definition, or worse, poke in the memory layout.
- rapala 9y agoYes, you can access raw memory and flip bits to modify a private member of an object (and it migth even be defined, not too sure about that thou). But I don't find that an valid argument for the statement that you can't do abstractions in c++. That's just not something people do. The c++ version of your example would be, if I understood your code correctly, to take an std::vector as an constructor parameter, copy it to an private field and sort it.
- Drup 9y agoI don't know all that much about C++'s object system, so I can't give you a concrete example on how it breaks down. However, you say that it is "not something people do" ... well maybe not in C++ (I highly doubt that), but it's very common in many languages. In C, it's common to look inside structs directly and change things. Javascript libraries do it all the time: They inspect their arguments, look at the types and change their behavior depending on it. It's a common programming practice to poke deep into the data-structures and do things. In Java, they made it an art with reflection and monstrosity such as Spring. Abstraction is a bit like immutability: Sure, you can try to fake it in languages that don't have it, but then you are just praying that everyone plays by your rules. :)
- rapala 9y agoMy comment "not something people do" was about directly accessing memory to circumvent the private data abstraction in c++ and I stand by that. I admit that I kinda pushed you into it, but you are moving the goal post. People indeed use public fields in languages like C and Javascript. In C it's often done for the sake of performance. Hiding data behind a pointer has a cost. In Javascript I would say it's lazyness above all. Front end programs often aren't that big nor pinacles of code quality. But it is possible to define abstract data types in both languages. ML makes it a bit easier and some times even more performant, but it doesn't "own" the idea. Abstractions are quite like immutability. You can enforce both in many languages, some just give you better tools for it.
- Drup 9y agoThe goal post, right from the start, is that by having proper abstraction (the kind that doesn't break when you blow lightly on it), you get many benefits. You say that, even when the language doesn't enforce it, people don't break it ..... except when they do. It doesn't really matter why, it simply makes every thing else more brittle as a consequence and limits how you can reason about your code. You seem to trust that programmers will play by the rules, even if the compiler doesn't enforce them. We will simply have to agree to disagree. :)
- rapala 9y ago> You seem to trust that programmers will play by the rules, even if the compiler doesn't enforce them. I've been trying to say the exact oppisite. C, C++, Javascript, all those languages provide ways to define abstract datatypes that cannot be circumvented (by "normal" code. Even Haskell has unsafePerformeIO). My latest argument was that people decide not to use those abstractions not because they are unavailable, but because it is more ergonomical or performant not to. The same happens even in ML, not all data is abstracted as an abstract data type.
- rlp 9y agoThis is not accurate. C++ has statically enforced private variables that cannot be modified by outside functions without fairly painful workarounds and castings. But, if you want to say that the ability to do those castings would disqualify any compile-time guarantees, well, OCaml has an equivalent escape hatch. Module Obj contains a bunch of functions to manually manipulate any object fields and cast arbitrarily using the "magic" function.
- yen223 9y ago"In OCaml, if you have a value of type `sorted`, you know it's indeed sorted." Could you expand on this? I'm pretty sure the OCaml compiler isn't sophisticated enough to make guarantees like this - i.e. I could pass in a function that satisfies the interface constraints, but doesn't actually do any sorting.
- yorwba 9y agoSince the function import in the signature is the only way to create a value of the abstract type sorted, and the implementation of import is given as Array.sort, all values of type sorted have indeed been sorted.
- zvrba 9y agoSo, in C++ class M { // This is private std::vector<int> _sorted; public: // This is your "import" M(const std::vector<int>& v) : _sorted(v) { std::sort(_sorted.begin(), _sorted.end()); } // Add other ADT operations that preserve the invariant } A more indirect way that more closely mimics the ML thing: struct M { // Everything private; but as M is "friend" it can access all members class Sorted { friend M; std::vector<int> value; } static Sorted import(std::vector<int> v) { std::sort(v.begin(), v.end()); return Sorted{v}; } } Usage: auto s = M::import(std::vector<int>{4, 3, 2, 1}); ++s.value[0]; // ERROR: value is private Yes, you can use casts to access the private members. As others have pointed out, unsafe operations exist in Ocaml/Haskell/... too.