4 ms·
> code that was written years ago that has two size types: one 32/64 bit signed and the other 32 bit unsigned. This creates a bunch of issues when compiled on 3
by deathanatos 12y ago
> code that was written years ago that has two size types: one 32/64 bit signed and the other 32 bit unsigned. This creates a bunch of issues when compiled on 32 and 64 bit architectures and there is a substantial amount of effort to clean it up.
Such things happen whenever an invalid assumption that is commonly true becomes not so commonly true, such as the 32-bit to 64-bit migration. That said, C/C++ provides you the tools: size_t is an unsigned type meant for storing array indexes and the size of objects in memory. If you want a real integer, then (unsigned) int. If you need integers of a definite fixed size, u?int(8|16|32|64)_t. Granted, I've encountered that not enough people take the time to understand the tool they're using. Honestly, I wish the default integer type was not fixed size, and especially not platform dependent fixed size, like Python; for non-[indexes/sizes], I feel like this is usually what you want.
> "well that's just bad API design".
Well…
> But my biggest problem with the C-dialects is pointers. Namely if you return or receive a pointer, it's not necessarily clear who owns it. The way this is handled is comments like "DO NOT delete this" or "you MUST delete this".
This is true; in C++, your use of pointers should be minimal, though this can be a problem with references just as easily. In the (special) case of std::shared_ptr, ownership is clear. That said, this is a problem not unique to C++: it exists in Java, Javascript, Python, and many others as well. For example,
some_list = [1, 2, 3]
some_obj = MyObject(some_list)
If some_obj expects to own that list, and it's constructor is:
def __init__(self, some_list):
self._some_list = some_list
which I see a lot, you've got the same problem. (I'm also interested to see how well Rust tackles this, as I agree it's a problem.)
> My other big problem (and this applies to Java too) is directly dealing with low-level multithreading primitives like threads, thread groups and mutexes. I really like that Go has taken a different approach here.
Honestly, I've never thought multithreading was "hard". There's a set of rules you have to hold yourself too, otherwise, yes, you can make your life very hard. If you limit shared data as much as possible, and what data is shared has a well defined locking order (preferably behind code that enforces it) — often this is just a single mutex — then I don't see the problem. Thread-safe queues ("channels", I think Go calls them) are also useful to establish "service" like threads.
- steveklabnik 12y ago> I'm also interested to see how well Rust tackles this, as I agree it's a problem. Is this a "see how well it actually works" or a "I don't know how this works and I'm interested?" I'm curious because this is possibly Rust's most important, interesting feature, and I want to make sure we've got some reasonable messaging here.
- BenFrantzDale 12y agoFor memory ownership, look no further than `std::unique_ptr`. With the features introduced in C++11, it is an elegant, inexpensive way to clearly and safely denote memory ownership and to have that memory cleaned up when it goes out of scope or handed off as you see for. If you are ever using bare pointers instead of `unique_ptr` you are probably doing it wrong. For more: http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/ http://herbsutter.com/2013/05/29/gotw-89-solution-smart-poin...
- bad_user 12y agoThere's no such thing as a well defined locking order - a statement that should scream the fact that locks are not composable. Good luck documenting it in the API or in making other developers pay attention. The problems are even worse than with manual memory management, since there you often get away with RAII. Say a function call is returning some sort of list, or some other data structure. Was the producer operating on another thread? Was that data structure signaled to other consumers as well? Can you modify it without locking? To make matters worse, locking is extremely inefficient, it limits the possible parallelism, throughput and vertical scalability and suddenly you start thinking of not protecting reads, since shared reads should be parallelizable, right? And so you need to look at alternative means of synchronization and then suddenly you end up reasoning about happens-before relationship arising from usage of memory fences, non-blocking algorithms and single producer / multiple consumers scenarios. And then you discover that C++ doesn't have a strong memory model to speak about and that at least before C++11 it was all platform dependent. Of course, I like this state of things, since my favorite platform (not C++) has a better memory model and plenty of higher level abstractions built on top, like actors, CSP, ring buffers, futures, Rx, iteratees, immutable data-structures, etc... but yeah, people able to reason about concurrency are also avoiding it like the plague.