The reference D compiler is now open source
forum.dlang.org
forum.dlang.org
Switched to D 4 years ago, and have never looked back. I wager that you can sit down a C++/Java/C# veteran, and say write some D code. Here's the manual, have fun. They will with in a few hours be comfortable with the language, and be fairly competent D programmer. Very little FUD surrounding the switching to yet another language with D.
D's only issue is that it does not have general adoption, which I'm willing to assert is only because it's not on the forefront of the cool kids language of the week. Which is a good thing. New does not always Mean, improved. D has a historical nod to languages of the past, and is trying to improve the on strengths of C/C++ and smooth out the rough edges, and adopt more modern programming concepts. Especially with trying to be ABI compatible, it's a passing of the torch from the old guard to the new.
Regardless of your thoughts on D; My opinion is I'm sold on D, It's here to stay. In 10 years D will still be in use, where as the fad languages will just be foot notes in Computer Science history as nice experiments that brought in new idea's but were just too out there in the fringes limiting themselves to the "thing/fad" of that language.
> languageS Come And popuLar Are
> S C A L A
Did I do that right?
And several of those languages are probably used by 10x or more people than D is.
Luckily, there are so many things to build and so many programmers out there that almost any languages gets a spot under the sun these days.
When was the last time a programming language died out? My guess the last one was a language tied to its hardware...
I've got some tens of libraries/apps written in CS, no plans to migrate them. Works as well today as it did 3 years ago.
It's at 71.0% (5th from top) on the Dreaded tab here:
http://stackoverflow.com/insights/survey/2016#technology-mos...
> I've got some tens of libraries/apps written in CS, no plans to migrate them. Works as well today as it did 3 years ago.
You might have a different view to the above then. Sounds like you're using it for the kinds of things it's good for, perhaps. (Languages can fall into vogue and (infuriatingly) go viral for all the wrong reasons... with everyone fighting it and not understanding why)
Possibly horrible by geek purity standards, but waaaaaay more used than D :)
I do wish to have gradual static typechecking available though. This may unfortunately force me over to TypeScript or ES2015+Flow.
I'm... slightly confused. :/
The ultimate power that can actually be manifested in physical reality (as far as we know) is still Turing Machines[1]... the rest is mostly ergonomics.
[1] Well, QM may add a "little bit" of efficiency, but it doesn't add any oracular power, per se. AFAIUI, at least.
And a lot of it is embedding FORTRAN or COBOL in the new pretty C/++.
New skin, same system.
In Julia, too.
Whose permission do you seek who will "let you" or not "let you" write a critical system in some new relatively unknown language? What if you work for yourself or are creating a startup?
[1] I think it's spelled that way these days, but of course given the context of the thread, maybe you're talking about old-school FORTRAN.
Obviously, it's entirely possible that D will indeed fade away, but that would be a real shame.
The way D is designed is very holistic: the combination of ranges, UFCS and CTFE (and modules) all made me really hate using C++. I've ended up being more productive (even with toys that I never touch again) in D than with that dynamically typed languages like python and js.
C++ has been gaining constexpr features for years. These have nothing to do with D at all, except in the sense that all languages everywhere influence each other slightly. Certainly constexpr wasn't drawn directly from D.
if constexpr was the obvious logical next step. It has been suggested and proposed for years. Yes people formally proposed static if, which was heavily inspired by D's static if, but that proposal was rejected because it was poorly designed, and C++'s new if constexpr is about as different as it's possible for two compile-time conditional compilation constructs to be.
Python had math and has lots more maths now. R also has math and started to kill Python, but now Python has Tensorflow and PyTorch. Scala has Spark. Java has Tomcat, and everything that followed, which is probably 20% of the world's mass by volume. Go has Docker Ruby has/had a railroad or something? JS has well, f... I don't know where to start here.
Does D have a thing?
Probably its most useful feature is rather subtle. It's very easy to express diverse ideas in code in D without having to resort to contortions. It's something people realize after having worked with D for a while.
It is not the result of having feature X (you can always find feature X in other languages or a way to make X work), it's the combination of various X's.
For example, some algorithms express naturally in a functional manner, some imperative, some OOP, etc. It isn't necessary to buy into a manner for the whole program, just use the manner that fits the particular part of the program.
You might like to use FP here and there, but don't want to deal with monads. You can use OOP for the AST, but don't want to box integers into an OOP class. You like dynamic typing for one type, but it's a bad fit for another. You can garbage collect for a quick prototype or a seldom used part of the code, and carefully manage memory for the release or the hot spots. (The Warp preprocessor I wrote did that. https://github.com/facebookarchive/warp)
There's a lot less time hammering square pegs into round holes.
I've seen more than enough presentations on "How To Do Technique X In Language Y" and everyone says how clever that is but the contortions are just too awful to contemplate.
The flip side is that D won't be satisfying to a purist adherent of any of those paradigms.
(Yes, I know Haskell can also fake for loops more cleanly with monads, but they still feel awkward and unnatural.)
There's a reason that Python is commonly referred to as 'executable pseudocode'.
But yes, Ruby had Rails, JS had web browsers, Perl made string handling easy, Java was appealing to managers (don't let your moron employees write undefined behaviour: CHOOSE JAVA!), etc.
Go was exciting before Docker existed.
JS has the browser, and then had Node.
Scala has functional programming and the JVM. Spark is not really a "Scala thing" (although it is written in Scala). You can use other languages with Spark.
Tomcat is hardly the first thing that comes to mind with Java.
What a bizarre perspective you have!
The reference compiler not being open source makes a language not cool with the cool kids. (Not that I'm blaming anyone).
Yes we use them, and even like them in a weird Stockholm Syndrome way, but they're not fun to work with. We use them because we need them, not because we enjoy them.
Disclaimer: the personal pronoun "we" as used here means the author plus zero or more people.
Java isn't my favorite language, but even I can remove my blinders enough to see its strengths.
The words that come to mind when I think of Java tooling is certainly not "best". More like "Bloated, slow, too-fscking-much-XML"
Java really raised the bar on tooling and other languages/platforms have really had to drive hard to get just a close comparable place.
I won't list all other things you can do but no other popular language even come close to the tooling of Java or C#. C and C++ has too many different build systems and too much lazy evaluated templates and typecasts for the IDEs to handle well. Python, Ruby, JS, PHP...well they are all dynamic so good luck with fancy IDE features.
There's just no faster route to completely discrediting yourself in eyes of anyone who's actually used it recently.
But of course I can't always do so and get the performance I want. My approach is generally to prototype in languages like Python, but implement in C89. See: https://www.youtube.com/watch?v=WNTOpl30MIQ . That's 10s of thousands of times faster than our initial prototype and...
We profiled all sorts of things in order to make it that fast. Right down to cache misses, branch mis-prediction, etc, how concurrency on the CPU interacts with I/O.
Thanks again, this news makes me very happy!
It seems we haven't had a lot of good things to say lately about Symantec and I hope this gives them something positive to celebrate.
I might have to give D a shot now just due to nostalgia.
Now I have no excuse to avoid learning the language, and that should be fun.
LDC master is on 2.073.2 right now (the latest DMD release), with a 2.072.2-based release imminent, and work towards 2.074.0 (currently in beta) already underway.
GDC is sadly a different story, though.
Here it is:
I wonder how releasing the dmd backend as Open Source will change the balance between the various compilers, and what people will favor going forward?
I'd be really interested to hear a comparison of those from someone experienced with D and its community.
http://dlang.org/download.html
More information on the wiki (also linked to from the download page):
LDC compiles to fast code and only slightly lags behind the reference. It might even catch up soon.
GDC compiles to fast code and supports many architectures in theory. It lags behind the most and architecture support also requires a ported runtime.
- DMD is by far the D compiler with the shortest compile time. It's actually so fast that it comes with a utility, 'rdmd', which compiles-then-execute a D program. Say goodbye to shell/perl/python scripts, now you can have compile-time checks without an explicit/slow compilation step. We use it for automation tasks.
- GDC is the compiler of choice when it comes to supporting multiple targets and cross-compilation. It closely follows GCC and G++ command line conventions, meaning that using a single properly written Makefile it's easy to target x86/x86_64/arm, GNU/Linux (or Windows, but the mingw support has been in statis for years). Debian comes with pre-compiled arm-targetting GDC compiler. gdb, gcov, and operf work well. The generated code is fast (more than LDC), we use it for heavy computation tasks.
-iOS? -Android? -Windows?
Android: Experimental https://wiki.dlang.org/Build_LDC_for_Android
Windows: Works. Here is the Visual Studio Integration https://github.com/dlang/visuald
Lacking a bit wrapping of system and gui calls but for android see dlangui and Jni is not so bad.
It's very practical to write libraries in D. Possible to write whole apps, but I wouldn't start there for now.
Right. See:
http://www.infognition.com/blog/2014/d_as_scripting_language...
Also of interest:
Why D?
http://www.infognition.com/blog/2014/why_d.html
Both pages down right now, maybe the site is down, but have read those pages earlier. Google cache or archive.org may also work. Infognition is a software product company (video and related products) that does a good amount of their work in D. No connection them, just saw the site while browsing for D info earlier.
> GDC is the compiler of choice when it comes to supporting multiple targets and cross-compilation.
That entirely depends on what your targets are. GDC has some claim to "support" more architectures than LDC in that it can generate code that interfaces with C for just about every target GCC implements. However, this is only part of the story – "support" is a dangerous word to use here, as full-blown D runtime support is much more limited.
If you look at the most common platforms for desktop and mobile applications, LDC is definitely in the lead – in particular, LDC targets Windows/x86 (both 32 and 64 bit), macOS, iOS and Android/ARM, neither of which GDC supports. Some other platforms like AArch64 or PPC64 are beta quality on LDC, but have not received significant work on GDC. Both compilers support Linux/ARM (but admittedly GDC might be a bit more stable there).
> The generated code is fast (more than LDC)
[citation needed] This doesn't match my experience. More often than not, GDC and LDC are pretty much head to head, apart from small differences either way from the different backends (GCC vs. LLVM). In addition, LDC can benefit from some (minor) D-specific additions to the backend optimizer and some target-specific standard library optimizations, though, and sometimes has performance fixes that have not landed in GDC yet.
weka.io (one of the biggest D deployments, high-performance software-defined storage) and the Mir numerics library (very competitive performance numbers) both use LDC. If you have a real-world example where GDC generates significantly better code than LDC, please consider reporting it on the LDC issue tracker so we can look into fixing it.
Regards,
P.S. I think of a system's language as one that runs directly on the machine, e.g. Swift, C, go. They operate at the "system" level.
Still reading the docs....D seems to have a very clean design. No baggage from some "glorious" past (70es, PDP, IBM 360 etc).
DConf (http://dconf.org/2017/schedule/) is in three weeks, and there are a number of related talks. Once the videos are out, you might get a better sense of the current "D as a better C" landscape.
AFAIK a "system programming language" should have deterministic performances, obviously Go hasn't. But different people might define "systems" differently.
Just like C. You lose determinism with malloc() and free(). As any embedded/kernel developer knows, malloc() takes often unacceptably long time. Or even free().
With C, C++ and Rust allocating memory often boils down to calling something equivalent to malloc and free. While the cost is not precisely known all modern OS provide guarantees are the time to execute relative to the size of the amount requested. This is almost always such a simple and fast operation that allocation is what gets optimized only after the algorithms and data structures have been tuned and this is a known bottleneck. Many application never get to the stage of optimizations (Games almost always do, stupid fixed time frame budget).
Consider the amount of work the GC does and understand why any GC is generally considered no-deterministic: https://blog.golang.org/go15gc
I was under the impression that Rust (and safe_ptr) deallocate at scope end, which could also cause framerate issues (unless you do ugly scope hacks).
I do agree that you're unlikely to bump into this issue, though.
You can just use delete, as you mentioned, it is a C++ only construct as far as I know.
For the std library smart pointer, you can get their value (the raw pointer), delete that then assign nullptr to the smart pointer. I would consider this a code smell, and ask hard questions of the authors of such code.
The simplest thing to do is to add new scopes. You can introduce as many blocks with { and } as you like. It is a common pattern to lock a mutex with a class that releases the mutex in its destructor (and acquired it in the constructor). The std library includes std::lock_guard[0]. To insure the smallest possible use of the lock a new scope can be introduce around just the critical section and the first line of the block can pass the mutex to the scope guard and it should be about as small and efficient as can be, while be exception safe and easy to write. Hopefully this is also easy to read.
You can introduce new scopes with std::shared_ptr or std::unique_ptr as well. This seems common and reasonable.
[0]https://github.com/libgdx/libgdx/wiki/Memory-management#obje...
So for them, a language that can be used by DevOps Engineers is a systems language. While for sane developers, a systems language is one with deterministic attributes and the ability to be compiled to native code with no/a minimal runtime. I.e. one you can code "a system" in.
Yeah, but "a system" doesn't necessarily mean "an operating system". There are lots of kinds of systems. Most people I know, who I've talked about this with, consider middlware'ish development (think, message queuing systems, application servers, etc.) as an aspect of "systems programming".
Would you consider the employees of UK Royal Navy, Xerox PARC, ETHZ, DEC, Compaq, Microsoft as insane developers?
If you write an implementation which uses Reference Counting, it can be "deterministic" and won't require a runtime.
...and I don't understand why some people have downvoted my question. Anyway, I'll continue reading the docs :)
Anyway, the docs are not that great, so Mike Parker has started a blog post series about the GC.[1] If you have questions, drop them in the d.learn forum.[2] They're pretty friendly (most of the time).
[1] http://dlang.org/blog/2017/03/20/dont-fear-the-reaper/ [2] https://forum.dlang.org/group/learn
The gc can be disabled with @nogc, the command line flags are only if you want to disable it for the whole program or if you want warnings as to where the allocations happen. https://godbolt.org/g/IQ0O06
(And, of course, the entire main() disappears on -O1 and above: https://godbolt.org/g/FAWtak.)
Since then a few remarkable ones were Mesa/Cedar, Modula-2+, Modula-3, Oberon(-2), Active Oberon, Sing#, System C#.
The reasons why so far most of them didn't won the hearts of the industry weren't not only technical, but also political.
For example Modula-3 research died the moment Compaq bought DEC research labs, or more recently System C# died when MSR disbanded the Midori research group.
If you want to learn how a full workstation OS can be written in a GC enabled systems programming language, check the Project Oberon book.
Here is the revised 2013 version, the original one being from 1992.
The question is, how much easier is D than Rust, and how much safer is D than C++.
If you can afford a garbage collector, D easily wins over Rust. If you really need the safe manual memory management, Rust wins. In between is still a large grey area.
I don't use rust because I don't need manual memory management and I require subtype polymorphism for a lot of things, but I choose Scala over D.
Rust's thread model is free from data races (a thread must have exclusive access to a variable in order to write to it), but not from race conditions in general.
(Sorry for a naive question, just thought that a data race and a race condition are synonyms. What else is there to race over if not shared data?)
Rust can't prevent one from doing all the right low-level synchronisation in the wrong order. In fact, I don't think any language can, without somehow being able to understand the spec of a program: something that's a race condition in one case, may not be a race condition elsewhere (this differs to a data race, which isn't context dependent).
Deadlocks, and other synchronization issues are just some 'general race conditions' Rust can't solve.
Rust's prevents 'data races' defined as:
-two or more threads concurrently accessing a location of memory
-one of them is a write
-one of them is unsynchronized
This is the "the only point of the ownership/borrowing model is to avoid GC" myth that I've been working to kill. Rust's model also gets you data race freedom, to name just one other benefit.
https://z0ltan.wordpress.com/2017/02/21/goodbye-rust-and-hel...
D gets tricky for resource management and avoiding GC.
> how much safer is D than C++.
Bounds checking and default initialization alone fix most memory errors you may have in C++.
But I still think there are better alternatives now. Depending on your priorities and constraints, OCaml, Go, F#, Scala, and Swift all fit the same description (easier than Rust, safer than C++) and they're in the same realm for performance (slower than C, C++, Rust, etc., but not by much). D could have been there if they had a decade or so with a bigger community.
I've enjoyed programming in Ocaml, Rust, C++, Haskell, many Lisps, etc. -- they are all excellent languages. But I find (to my own surprise) that I often come back to D when playing with a new design, exactly because of that sweet-spot. I highly recommend giving it a try if you haven't already.
I am a sucker for language discussions, so let me explain what my problems are with your suggestions.
Ocaml: No support for parallelism, community is even smaller than D, do they have a package manager, yet?
Go: I like generics/templates. If I throw away type safety, I might as well use Python.
F#: I use Linux. The .NET ecosystem is not strong here.
Scala: I don't like the JVM. Also, the Scala compiler is slow.
Swift: Solid ideas, but held back by Object-C compatibility. I don't build iOS apps, so why bother.
One sample project we built for internal use is here: https://github.com/kaleidicassociates/excel-d/blob/add64bit/...
Friend of mine started a company called Resolver Systems to do that for Python (end result). Nice experiment but bad timing for launch just before the crisis. Have got some algorithmic and infrastructure things in D, though plenty is done in other languages too. I ported Bloomberg API to D - it's open sourced bit currently not yet directly used in production. May start to be in coming months. It's not so hard to turn spreadsheets into code (its rarely the spreadsheet itself that does something complicated) so would rather rewrite that than try to do it automatically because code is easier to read, though I had dinner with a Dutch girl who is a professor who works on spreadsheets as functional languages.
The Dutch girl must be Felienne :) "Spreadsheets are code"!
He and Harry Percival (IIRC) later founded PythonAnywhere.com , a Python environment (and more) in the cloud. It has some nice features.
Think C++ template metaprogramming but much, much easier and thus, seemingly more powerful. It's not that you couldn't do the same in C++, but D's metaprogramming is so much more accessible that it makes you want to use it.
You'd probably do large portions of it in "constexpr" types and functions rather than relying on recursive metaprogramming techniques.
They are also planning on adding overloading based on whether a function is constexpr, which is important if you want the same library to support both compile-time and run-time matchers.
So it's all theoretically possible already. But D has the advantage here in that it's not just possible but usable.
Well, imagine that all of the things you can do in Python by messing with dunder methods, function decorators, or metaclasses could be precomputed by a compiler and would not even execute at all during runtime. It makes everything really fast at runtime and easy to precompute at compile time.
Is there anything in D similar to decorators? How does the registration pattern work in D, for instance?
https://github.com/rejectedsoftware/vibe.d/blob/master/examp...
Decorators (in D, 'user defined attributes', or UDA) work differently. It's not a function-composition feature, but more of a tagging feature. You write a class, function, etc., tag it with custom attributes; and then have a separate compile-time function walk over your code, find the decorators, and augment the code based the meaning of the tags. (I used to wish that D had adopted Python-style decorators, since they are easy to reason about and implement, but I can see the logic of the more general UDA system that they adopted.)
In practice, though, you would often use templates to achieve the same effect. Given a memoize template (really, just a memoize function), and an expensive-computation function,
auto fastComputer = memoize!expensiveComputer;
produces roughly the equivalent of @memoize
def expensiveComputer(): ...
but with opportunities for compile-time optimization.I found that some of the Nim's MP features, in particular AST macros, are a little harder to work with than D's templates and compile-time function evaluation. You get a lot of flexibility, but the cost is high. I'm not a big fan of how "mixin" is used in D to splice source-text into a generated function, it's certainly less principled than an AST transformation, but in practice the resulting code tends to be concise and easily read, whereas the AST-macro approach introduces a lot of accidental "noise" and complexity. The complexity raises the bar for reaching for a compile-time solution, where in D it seems equally as natural to write compile-time code as it does to write regular code. (Not to pick on a strawman, though -- AST macros are not Nim's only MP tool.)
The Nim MP feature I never really played with was the rewrite rules. They seem interesting in theory, but maybe a little too magical for my liking!
I have a lot of respect for Nim. I am glad we live in a world with so many options. Like Walter said in an earlier comment, it's an embarrassment of riches. :)
Can you elaborate on how D is planning to sort out the garbage collection? Nim's GC is extremely fast and thread local, and can be disabled without breaking libraries (according to the author, it does something with memory regions that I haven't 100% grasped yet).
I've googled about D's garbage collector and it's apparently been discussed as the language's biggest flaw since 2013, but I can't find any information whatsoever on what's being done in that regard.
The collector itself isn't being improved as far as I know -- at least I haven't seen any initiatives mentioned recently with that goal. In fairness, I haven't been following the community activity very closely in the past few months, but I think that's accurate. Nim definitely has a technical advantage re: its GC implementation.
The bigger movement has been the "@nogc initiative", which started with adding a @nogc attribute to the language (the compiler can verify that a function tagged with @nogc, and all of its callees, do not allocate GC memory). There is an ongoing initiative to make more of the Phobos library @nogc-compliant, to take advantage of this feature. There has also been a lot of work on custom memory-allocators [1], and I think the plan is to incorporate into Phobos where it makes sense, so you can have functions which take custom allocators, have thread-local allocators, etc.
https://dlang.org/phobos/std_experimental_allocator.html
I don't speak for the community or the dev team, but I think the long-term goal is to make the GC a feature that is available when you want it, but that isn't a dependency for using the standard library. Either through custom allocators or through @nogc guarantees, you'll be able to ensure that your program's memory management is deterministic.
For anyone else who's evaluating D and looking into its GC situation, the most recent blog post on Dlang.org (https://dlang.org/blog/2017/03/20/dont-fear-the-reaper/) seems to embrace the presence of the GC, but also ends by saying the next blog post will describe how to go without the GC. So there is indeed awareness/activity on that front!
(If I'm going to learn a new system programming language, which one should I pick?)
I would say that I have found it to be more of a problem on Windows. That'd because the general C/C++ package management solution on Windows is quite... Old fashioned, and that's not always a D specific problem.
I REALLY ENJOYED D1, REALLY! (CAPS 11). D1 was like C, but better. It was heavenly. D2 is like C++, but better. Not my cup of tea though. Give it a spin for a day or two. I'm sure you'll like it if you like C++. Trouble arises, as with all niche languages, when you try to move to production and you have to source libraries and/or support.
Rust is newer (though being used in some big projects like Firefox/Servo, Visual Studio Code's search functionality now uses it by default, etc), has (afaiu) a more powerful type system, and is entirely memory-safe by default. However, this makes it somewhat harder to learn at first, and it also has a relatively slow compiler. It follows ML-style languages a bit more, with things like pattern matching and sum types built into the language.
Personally, I prefer Rust, because it feels like a stronger foundation with the ML-like type system and no GC. YMMV though, depending on what is important to you.
I guess your original comment was maybe meaning how D enforces (the "normal" definition of) memory safety differs to Rust? In any case, I read over both of those, and, to me, they both seem to essentially be a slightly less general version of Rust's scheme (possibly independently invented), rather than something very different. I'm interested to hear how you think they specifically differ to Rust.
There's no notion of "borrowing" in D nor any notion of "only one mutable access at a time".
Well… it's relatively slow in release mode, but C++ compilers can often be slower. GHC is always slower :D
In other words, if you're looking to replace/supplement your C use: go Rust. If you're looking to replace/supplement your C++ use: probably go D, with some caveats towards actual use.
Note: I like both languages, but do prefer Rust for my personal use cases.
Some details here... every language other than assembly languages has some amount of runtime. This is Rust's: https://github.com/rust-lang/rust/blob/master/src/libstd/rt.... (as you allude to, many people refer to this amount of runtime as "no runtime" since it's very, very small.)
You could also consider some other things as part of a runtime; for example, by default on most platforms, Rust includes jemalloc. That can be removed, though not in stable Rust. Same with the standard library code, which can be removed for libraries, but not binaries just yet (due to a small technicality regarding the stability of some attributes.) Things that do this are likely to use some of Rust's other unstable features at the moment, so it's not generally a burden to do so, and those interfaces rarely change right now.
How are you defining "runtime" such that this statement is correct?
I see a distinction between a runtime library and a language runtime. The former is just a set of convenient routines for interacting with a specific platform. The latter is something that runs alongside your program to facilitate its execution, like a JIT or an interpreter.
The key is, you are doing the injecting in asm.
Anyway, your distinction is pretty solid. Most people just use "runtime" to mean either one, and then rely on the context to disambiguate.
In short, I thought Rust was "we solved the pain of this difficult thing." However, it is not really a novel solution to the difficult thing, but simply a decision to undertake it.
I've now moved to evaluating Nim and D, and while I've barely dabbled in them (mostly going through the docs and writing some simple example-like code), I can at least say that Rust is likely to be much more controversial and polarizing than these languages. I recommend giving it a try - go through the official "book" which serves as the main documentation. If you survive lifetime annotations without finding them too obnoxious, then you'll probably like Rust.
Personally, I find Rust's extreme rigorousness (and the laboriousness that follows from that) makes it very niche, and I find myself rather unexcited about using it for anything.
The annotations have, for the most part, faded into the background for me. I don't find them to be particularly pervasive in the code I write, and when I do need them, it's usually to fix a reasonably straight-forward case where the compiler failed to elide them. With that said, in the years I've been using Rust, I have committed one or two lifetime-related bugs. (No memory unsafety resulted, of course, but it did result in data being annotated with a shorter-than-actual lifetime.)
> In short, I thought Rust was "we solved the pain of this difficult thing."
Part of the pain that Rust purports to solve is the significant reduction (and debugging thereof) of memory unsafety errors. In return, you must deal with the pain of an ownership and borrowing system, which might present challenges to patterns you may have used in another language. The benefit is that you have a compiler to tell you when you've mis-stepped instead of an end user filing a bug report (or worse).
Other than lifetime annotations, I have a couple other niggling issues with it but I suspect it's because I haven't fully grasped certain things yet, and so I'll refrain from commenting on them for the moment.
Stuff that I particularly like.
Assert/Enforce: http://ddili.org/ders/d.en/assert.html , Unit testing: http://ddili.org/ders/d.en/unit_testing.html , Contract programming help: http://ddili.org/ders/d.en/contracts.html, and http://ddili.org/ders/d.en/invariant.html , Scope (love this): http://ddili.org/ders/d.en/scope.html
And the other usuals -- templates, mixins, etc....
BTW, I mostly use D as a better C than as a better C++...
Another good feature:
Interfacing to C is somewhat easy at least for the basics. (I haven't looked at advanced cases yet, but maybe someone else can comment on that.)
https://dlang.org/spec/interfaceToC.html
This is a great feature IMO, because it allows you to (re)use the huge number of existing C libraries out there.
Here is a simple example:
Calling a simple C function from D - strcmp:
https://jugad2.blogspot.in/2016/09/calling-simple-c-function...
There's a handful more small examples of a few things D can easily do, here on my blog:
https://jugad2.blogspot.in/search/label/DLang
(And of course, there are many more at the DLang tour site - https://tour.dlang.org/ )
Also, there are a few good videos about D (alone) and being discussed along with other languages, at my blog's DLang posts link above.
I'll just put some post titles here to give a quick idea:
Simple parallel processing in D with std.parallelism
Using std.datetime.StopWatch to time sections of D code
Read from CSV with D, write to PDF with Python
Command line D utility - find files matching a pattern under a directory
min_fgrep: minimal fgrep command in D
num_cores: find number of cores in your PC's processor
Func-y D + Python pipeline to generate PDF
file_sizes utility in D: print sizes of all files under a directory tree
deltildefiles: D language utility to recursively delete vim backup files
[DLang]: A simple file download utility in D
Getting CPU info with D (the D language)
Porting the text pager from Python to D (DLang)
https://jugad2.blogspot.in/2017/04/porting-text-pager-from-p...
Congratulations Walter, now let's see D take over the world.
dmd and Digital Mars C++
gdc and gcc
ldc and clangThere are other less extreme solutions, such as the ability to have some threads be registered with the GC and others not. Also, you can just find your bottle-necks and mark those specific functions as @nogc. Some people also turn off automatic collections and manually trigger them only when it's ok to pause.
But for the rest of us, D is not really comparable with Java but people tend to think if it the same way. I don't use classes myself (I had one but a guy didn't like it and removed it, though one or two in library code may have crept back recently) but allocate structs on the stack. The latter is more idiomatic generally in D. Depends how you count it, but at 120k sloc, maybe 200k if you include the periphery.
It's easy to allocate without GC using the std.experimental.allocator and emsi containers. Regional heaps, free lists, whatever hybrid model you want.
See excel-d for one example.
If you keep the rest of your heap small, say below 200Meg most people will be fine.
If you don't want to use D, blame the docs and lack of examples - still not as good there, but way better than before and all the unit tests are editable and runnable now. But I think the GC thing is more FUD than a real objection for most people.
[1] http://blog.mir.dlang.io/glas/benchmark/openblas/2016/09/23/...
[1] https://www.reddit.com/r/programming/comments/54kg6v/numeric...
D does play a significant role in this achievement, though – D's very powerful yet easy to use features for generics and introspection make it possible to finely tune the code for different parameters (sizes/dimensions/…) while still being easy to understand and modify.
I definitely appreciate the power of generics, especially when you can to generics over values instead of just types. But I'm having trouble seeing the value of the compile-time introspection, for the most part it doesn't seem to give you much more power than generics do. Could you give me an example of the "killer feature" introspection gives over generics? Bonus points if you can compare it to Rust-style generics with traits and specialization.
You can 'Write once - automate everywhere' all the boilerplate. See https://github.com/kaleidicassociates/excel-d/ , for an example of automating the interaction between D and Excel. I am in the process of doing something similar for OpenCL and CUDA and will be presenting it at Dconf.
You can make at compile time (additional) fast paths by checking to see if a type (or symbol or whatever else) provides a fast primitive to accelerate your algorithm. e.g. if Foo implements fastfoo use that otherwise fallback to a general algorithm.
See also Andrei Alexandrescu's 2016(15?) talk (IIRC the relevant section is about half way through https://www.youtube.com/watch?v=4oDK91E3VKs).
All in all, the GC isn't as much of an issue for high-performance applications as is sometimes claimed, but all the recent work towards reducing the dependency on it has of course been done for a reason – in performance-critical code, you often don't want any allocations at all (GC or not), and the large jitter due to collections can be a problem in some situations.
Hopefully a fully FOSS compiler will bring it right into the mainstream.
Since I see some comments in this thread, asking what D can be used for, or why people should use D, I'm putting below, an Ask HN thread that I had started some months ago. It got some interesting replies:
Ask HN: What are you using D (language) for?
I want to have smart pointers instead
int main(string[] args) @nogc { ... }Most of the community packages out there use the GC. Some though are transitioning to a std.experimental.allocator interface, like this containers library https://github.com/economicmodeling/containers
In this case, grandparent did mention a memory management technique, namely garbage collection.
Memory management + plus typically required thread safety usually means reference counting.
Somehow I wasn't considering unique_ptr<T> as a smart pointer, despite using it all the time for resource management to avoid writing wrapper classes.
I do now, you're right.
Also, the lack of checking leads to unique_ptr<T> dereferences potentially having undefined behavior (i.e. whenever you try to dereference a unique pointer that is null [1]).
[1] http://en.cppreference.com/w/cpp/memory/unique_ptr/operator*
That said, the null checks required for C++'s destructor semantics are definitely a little more interesting in this respect, given one is rarely going to do this with raw pointers (although the cases when you don't need to do it also seem like cases the optimiser can handle fairly easily), but an extra branch and/or write at least seems significantly qualitatively different to the full reference counting that people often think of when talking about "smart pointers", which is the point the parent is trying to make (smart pointers aren't just reference counting).
Also, the cost of it not being memory-safe should not be ignored.
In any case, it is unfortunate that unique_ptr is not memory safe, but it also not at all notable, as pretty much nothing in C++ is completely memory safe (even the other smart pointers like shared_ptr).
The deeper problem is that unique pointers essentially are a sort of linear/affine type system, but that C++ leaves the actual checks to the runtime (which implements some, but not all of them).
I think my original point still stands here though: smart pointers != refcounting, inherently.
The way I see it, GC should just belong as deferred_ptr