7 ms·
I'm a C++ dev. For me it's: - C++11 is good enough (and a little better than that) - The eco system. Yes, I can use C libs from dlang but managing extra bridg
by kybernetyk 13y ago
I'm a C++ dev. For me it's:
- C++11 is good enough (and a little better than that)
- The eco system. Yes, I can use C libs from dlang but managing extra bridges/headers is too much overhead if the alternative is just to throw them into my C++ project and use them without writing any glue code.
- The garbage collector. (RAII fan here)
- Tooling. Are there any good dlang IDEs with mature refactoring support and code completion?
For the tasks I'm using C++ for, C++11 is more than sufficient. For more abstract/high level stuff where I don't particularly care about top performance/memory layout I don't need another C++ contender but can use higher level languages/scripting languages.
D would look more tempting if there was no C++11 but for now for me I'm perfectly happy with C++.
- k__ 13y agosorry, I killed your 1337 karma.
- kybernetyk 13y agoYeah, I already planned to create another account, upvote me once and never comment again ;)
- alecbenzer 13y agoWhat exactly is the argument for garbage collection over RAII-style freeing? Even in garbage-collected languages, you still need to do things like close file objects; the runtime doesn't do so automatically when it detects that there are no stack references to the file. Same goes for unlocking mutexes, or any of the other things that RAII tends to address. Is it just that maintaining ownership semantics for heap memory tends to be more complicated than doing the same for file objects (much more rarely shared, I'd guess) or mutexes (not sure if "sharing" is even sensibly defined here).
- crawshaw 13y agoIt is hard to manage ownership when allocations are passed around between concurrent threads. Garbage collection in Go makes goroutines and channels easy.
- agwa 13y agoThough arguably you shouldn't be accessing the same allocation from concurrent threads at the same time anyways, because that requires mutexes, which are ugly. Rust requires you to transfer ownership of objects when passing them between threads, which both enforces mutex-free programming and makes RAII work. Only one thread owns an object at a time, and that's the only thread that can use the object, and is also the thread that is responsible for freeing it when it goes out of scope.
- codex 13y agoThis implies that an object will be unavailable while it is being passsed between threads. How fast is that? With a mutex, it's as fast as shared memory.
- agwa 13y agoUnder the hood, you still use shared memory in this style of programming. But the programmer never uses shared memory directly. Instead he passes references to the shared memory to other threads, and the act of passing a reference clears the reference in the sending thread so the sending thread can no longer access it. In Rust, this style is enforced by the language. In C++11 you can enforce it by the convention of using std::unique_ptr and passing those between threads via a shared data structure like a blocking queue.
- pcwalton 13y agoMessage passing is a couple of atomic operations, and there are also L4-esque optimizations that allow a message send to be optimized into a direct context switch without a pass through the scheduler. Also, you can use shared memory in Rust. If you do, the type system ensures there can be no data races: either the data is immutable or you must take the lock before you mutate the data.
- mratzloff 13y agoThat's pretty nice. I've been waiting for Rust to stabilize before I bother learning it... It's been taking awhile, though. :-)
- deleted 13y ago[deleted]
- rbehrends 13y agoThere are a number of reasons why you may want garbage collection/automatic memory management over RAII: - RAII-style freeing means a lot of reference counting. Reference counting and multiple threads don't mix well. You can circumvent that by having multiple separate heaps, but that's not always a practical solution. - Reference counting is slow; if you want GC-like speed and RC-like pause time guarantees, you're probably better off with deferred reference counting, but that's not easy to engineer into C++; it's essentially a form of garbage collection. - Lack of fully automatic memory management may affect modularity adversely; see Jones/Lins for the gory details. In brief, wholly or partly manual memory management creates leaky abstractions (this is if you eschew RC for some of your code/types for speed reasons or because you need to deal with cyclic references). - It is not difficult to have scoped deallocation for resources (scope statement in D, using statement in C#, etc., destructor pragma in Nimrod). Resource lifetime, in any event, does not always coincide with the lifetime of a variable, so this is an incomplete solution. Using GC does not mean not using RAII where its downsides do not matter.
- hershel 13y agoThere are some non-defered reference counting that can offer pretty good performance(within 19% of defered reference counting), while still offering determinism[1]. [1]http://www.hpl.hp.com/personal/Pramod_Joisha/Publications/ismm06.pdf http://www.hpl.hp.com/personal/Pramod_Joisha/Publications/is...
- rbehrends 13y agoYes, but they have the same problem that they require compiler smarts; i.e., they require more than a template to implement shared_ptr<T>. When you're doing that, you may just as well implement something more sophisticated for automated memory management. The attraction of RAII is that it's a pretty simple mechanism that doesn't require compiler intervention outside of basic, already existing optimizations such as inlining.
- agwa 13y agoRAII does not mean a lot of reference counting. In the vast majority of cases in typical programs, objects have exactly one owner, and managing that ownership is very easy if your language provides good facilities for move semantics (as C++11 and Rust do). You can't say reference counting is bad for multi-threaded programs without mentioning that GC is also bad for multi-threaded programs, since the garbage collector has to pause all other threads, either for the entirety of the GC run or (if you're lucky and using a good GC) for parts of it. The modularity argument is reasonable, and I've been annoyed by this aspect several times, though in the majority of cases it doesn't seem to be an issue.
- pkolaczk 13y agoLack of GC makes concurrent lockless programming extremely hard (and most of the examples on the internets are subtly broken). RAII doesn't work at all besides trivial cases when there is no sharing at all. Reference counting incurs additional contention, due to interlocked increments/decrements and is also very hard to do properly. Where in a GCed language a single CAS is often enough, in a non-GCed language you need to resort to less efficient and often completely unsupported things like DCAS or CAS2.
- mratzloff 13y agoTake a look at Go's `defer` keyword. I prefer it over RAII; `defer` is both more explicit and more flexible.
- WalterBright 13y agoYou might be interested in D's scope guard statement: http://dlang.org/statement.html#ScopeGuardStatement http://dlang.org/statement.html#ScopeGuardStatement and an article about it: http://dlang.org/exception-safe.html http://dlang.org/exception-safe.html
- agwa 13y agodefer is great for "one off" cleanups, but in so many cases (closing file handles, releasing locks, etc.) cleanup is not one off but is repeated over and over again. So the price of explicitness is redundant code that is easy to forget or get wrong. Note that if your language supports RAII and lambdas (e.g. C++11), it's trivial to implement defer using a class that takes a function as an argument to its constructor and calls that function in its destructor. So you can still have the flexibility of defer in a language with RAII.
- Shorel 13y agoReminds me of UNWIND-PROTECT in CL
- mratzloff 13y agoMy preferred method of handling this is how Ruby does it with, e.g., File.open. The function yields the file handle and then closes it once the supplied block (think lambda function) ends. This is similar to what you refer to, but without the class. The class is useful for heap objects, of course.
- pcwalton 13y ago"defer" has really weird semantics; it's based on imperatively pushing cleanups onto implicit per-function mutable state. (This shows up if you call "defer" in a loop, for example.) It's also possible to screw up and forget to use "defer", causing things like leaks of file handles. RAII, on the other hand, is based on lexical scope, without hidden mutation, and also makes it harder to forget to do things like close files.
- jmdavisProg 13y agoThere have been papers on how GCs can be more efficient than manual memory management in some situations, so it's not always the case that RAII is better from a performance standpoint (though I think that it frequently is). But regardless, a big reason for the GC in D is memory safety. Using the GC, you can make memory safety guarantees that cannot be made with malloc and free (e.g. you can guarantee that a pointer won't be invalid with a GC but can't with manual memory management), and D is big on making memory safety guarantees. Also, some features (such as array slices or closures) work very well when you have a GC and become much more difficult to pull off without one due to a lack of automatic memory management that the compiler can use and a lack of clear ownership in some cases (e.g. the runtime owns the memory for array slices rather than there being a particular array which owns the memory). That being said, D does not require the GC. It's easier if you use it for at least some of the features, but D makes it very easy to use RAII and manual memory management, which also helps a lot in making the GC work better, because it's much easier to avoid making a lot of garbage for it to collect when you don't need to. A lot of stuff in D ends up on the stack rather than the heap, and D's GC ends up having a lot less work to do than the GC does in languages like C# or Java. That being said, the current GC implementation needs some work (and effort is definitely put forth in that area), but if you don't want to use the GC, you can minimize its use or even outright avoid it (though _completely_ avoiding it can be a bit annoying since that means avoiding a few language features that require it; that list is short though). So, while D definitely uses the GC and promotes its use where appropriate, you have full control over memory just like you would in C++. And the few features that are hampered by avoiding the GC don't even exist in C++ in the first place.
- bad_user 13y ago> A lot of stuff in D ends up on the stack rather than the heap, and D's GC ends up having a lot less work to do than the GC does in languages like C# or Java This is true, however there's a compromise involved. Because D also allows for manual memory management and unsafe memory access, it means that the GC is not free to move stuff in memory at will ... which really means that garbage collectors, like the ones available for Java (precise, generational, non-blocking, fairly predictable and compacting) are very hard to develop, probably next to impossible. This is the price you pay for using a lower level language and it's not a price that will go away easily. I've been using Scala a lot for the past two years, using it to build high-traffic web services and while Scala is pretty wasteful in terms of allocating short-lived objects, I've been surprised at how well the JVM handles it. In terms of throughput for example, Java GCs are much better than manual memory management. Allocating memory usually involves just incrementing a pointer, so it's basically as cheap as stack allocation. Deallocating short-lived objects is also fairly cheap, since it happens in bulk and so the amortized cost is pretty similar to dealocating stuff on the stack (!!!). The JVM can do some pretty neat things, like for example if it detects that certain references do not escape their local context, it can decide to allocate those objects straight on the stack. What really sucks about garbage collection is the unpredictability. Java's CMS for example, awesome as it is, still blocks the world from time to time. And when it does, you have no real control over how much time it keeps the process hostage. The new G1 in JDK7 is much better and if you want the state of the art in terms of near-real-time GCs, you can buy into Azul's pauseless GC. But they still suck for certain apps. Allocating objects on the heap also means you have to pay the price of boxing/unboxing the references involved. This sucks too. On the other hand, by having a good GC at disposal, it's much easier to build multi-threaded architectures. In C++ for example, it's so freaking painful to deal with non-blocking concurrent algorithms, or really, multi-threading of any kind.
- com2kid 13y agoFor reference, a lot of embedded programmers still use static allocations only, not even trusting heap allocations at all. Took awhile to get used to, but it is a damned fine way to avoid memory leaks of any kind! But even that aside, if you are writing something like a render loop with hard timing guarantees, (or anything else with timing needs!) having non-deterministic allocation costs can easily blow your cycle budget.
- 59nadir 13y ago> Even in garbage-collected languages, you still need to do things like close file objects; the runtime doesn't do so automatically when it detects that there are no stack references to the file. I'd just like to say there are sane solutions out there already to things like this. With the proper abstractions you get things like custodians[0] in Racket and several alternatives in terms of "call-with-..."[1] functions that do handling for you. These might not be the languages that are being discussed here, but they offer things like these precisely because they are not the languages discussed here right now. [0] http://docs.racket-lang.org/reference/eval-model.html?q=custodians#%28part._custodian-model%29 http://docs.racket-lang.org/reference/eval-model.html?q=cust... [1] http://docs.racket-lang.org/reference/file-ports.html?q=call-with#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._call-with-input-file%29%29 http://docs.racket-lang.org/reference/file-ports.html?q=call...
- p0nce 13y agoI'm a C++ dev too. Why I'm interested in D: - Sensible, pragmatic design decisions. - dub + VisualD makes building code, managing dependencies and debugging painless for me. - being part of building the ecosystem is fun - I'm not comfortable with the high cost of developing in C++ (even with last revision) and never chose to use it in the first place. C++ is basically forced on me since years. - I feel like I can be more productive and write higher quality programs when using D. I can use RAII in D like I would in C++. - I feel like Go and Rust do not address C++ shortcomings while introducing problems of their own. - D programs are short. I don't need nor want IDE refactorings.
- pcwalton 13y agoCan you elaborate on what Rust does not address that you wish it did, and what problems it introduces?
- p0nce 13y ago- compilation speed is not as impressive. To me this is imho the biggest pain point with C++, bigger then memory unsafety. - I missed templates based on any value/symbol, it forced macros on me in my very first try. I don't think it's a problem once you know Rust, but having to write macros was too intimidating for a newb.
- pcwalton 13y ago> compilation speed is not as impressive. To me this is imho the biggest pain point with C++, bigger then memory unsafety. Compilation speed remains a work in progress; it's improved a lot in recent versions. Note that 80% of the compilation time in rustc is actually in LLVM passes (the same used by clang), which are mostly optimizations, so turning off optimization helps Rust compile times a lot. LLVM as a backend does many more optimizations than DMD (and 6g/8g for that matter) and runs slower as a result. One issue is that Rust currently does not do incremental compilation below the crate level, so you will need to use many crates if you want incremental compilation. This will possibly change at some point via a ccache-like mechanism. If memory safety is not important to your applications, though, then Rust may indeed not be the right choice. Rust requires you to make sacrifices (a learning curve and less flexible unique pointers) to ensure memory safety, and if you just want to write "new" and "delete" then Rust isn't going to be the best language for you. (That said, I think there is a strong argument to be made that for many classes of programs it is worth some pain to eliminate memory safety problems, because memory safety issues frequently lead to security vulnerabilities. For us as browser manufacturers, memory safety is so important it is worth sacrificing literally everything else except maybe performance in some cases.) > - I missed templates based on any value/symbol, it forced macros on me in my very first try. I don't think it's a problem once you know Rust, but having to write macros was too intimidating for a newb. In general you want to use traits instead of macros to write generic functions. There are some current limitations with traits but I think they're a more scalable approach than ad-hoc templates. It'd be helpful to know exactly what limitations you were hitting.
- eco 13y agoC++11 borrowed a few good ideas from D and other languages so that certainly helped close the gap between D and C++ but D is still significantly nicer to work in than C++ (which is what I spend all day at work writing). You can use RAII all you want in D. The D standard library uses it for things like Files, containers, and smart pointers. I feel like Garbage Collectors have become something of a bogeyman for native languages. There is a lot of value a garbage collector can add. In D it's rarely hard to switch to managing your own memory if your profiler shows the garbage collector taking up more time than you'd like. For most programs avoiding the garbage collector is a premature optimization though. For IDEs you have: - Mono-D http://mono-d.alexanderbothe.com/ http://mono-d.alexanderbothe.com/ - VisualD (should be included with Windows DMD in the next release) https://github.com/D-Programming-Language/visuald https://github.com/D-Programming-Language/visuald - Code completion for a variety of editors including vim, emacs, SublimeText2 , Textadept, and zeus. DCD https://github.com/Hackerpilot/DCD https://github.com/Hackerpilot/DCD
- jussij 13y ago> - Tooling. Are there any good dlang IDEs with ... code completion? The DCD utiltiy can drive the code completion for a bunch of editors/IDEs. https://github.com/Hackerpilot/DCD https://github.com/Hackerpilot/DCD It works well.