My Vision of D’s Future
dlang.org
dlang.org
The one thing I would add to this list is documentation! There is a lot of good documentation available, but not for everything you would expect. For example, I had a hard time figuring out the behavior of sub-packages within a dub package. Some more explicit documentation on this subject would have been appreciated.
http://inversethought.com/hg/medcouple/file/tip/medcouple.py...
http://inversethought.com/hg/medcouple/file/tip/medcouple.d#...
Most of the standard library function calls return some opaque Result type which isn't obvious how to progress from. Only after some googling you'll learn that if you import std.array you can use .array() on the Result and get something usable. Oh, and I don't even know if it's possible to pass such Result to a function because you have to use auto to declare it.
Oh, and you can also use type deductions for function declarations! Just make it a template and let D figure out for you what type you want, or use typeof to record the type you want and use that typename in your function declaration.
Whether D "clicks" for someone might be more a matter of subjective taste than what languages they're used to.
As for D templates, they puzzled me until I read Andrei's D Programming book, which made everything clear. They're less narrow than C++ templates, more like directives for a syntax/scope-aware C preprocessor.
You can use them for more than just polymorphic functions; they're a way to pass source code around the program at compile-time, for almost any purpose whatsoever.
The python version of it would be calling `list()` on things all the time, which you might not always want to do.
Perhaps it's just my own incompetence though!
This is by design, e.g. map could not be lazy if it returned an array.
> Oh, and I don't even know if it's possible to pass such Result to a function because you have to use auto to declare it.
templates, void use(T)(T x) [auto ref if you feel fancy]
Input/Output Range > Forward Range > Bidirectional Range > Random Access Range
Input ranges provide the following API:
bool empty()
T front()
void popFront()
Forward ranges provide the same API, and also add a "save" function that creates a copy of the range's current state.Bidirectional ranges add "back" and "popBack" functions, which don't really need any explanation.
Random access ranges additionally add a "length" function and constant-time array-like indexing.
In addition to most functions in std.algorithm _returning_ ranges, most of them also _accept_ ranges. Therefore, you can freely pass the result of any function in std.algorithm into another function that takes a range, and it should all just work. It's pretty much the same deal as in Rust/Java/Swift/etc. with their various iterator protocols, although the API for ranges in D is more influenced by C++.
For example, the first Project Euler problem, using a range-based approach:
import std.algorithm;
import std.range;
import std.stdio;
void main()
{
//List all the natural numbers below 1000 that are multiples of 3 or 5
auto natsBelow1000 = iota(1000); //iota returns a range that lazily computes the numbers from 0-999
auto multiplesOf3Or5 = natsBelow1000.filter!(n => n % 3 == 0 || n % 5 == 0); //filter accepts a range as an argument, which it lazily filters according to the given predicate
auto sum = multiplesOf3Or5.sum(); //Sum accepts a range of "summable" items and computes the... sum
writeln(sum); //Prints 233168
}
A D programmer wouldn't generally write things this way, preferring to make a more idiomatic "range chain" like you'd see with Java's streams or Rust's iterators, but you get the idea.As you might have guessed, arrays are also ranges - random access ranges - which is why they're so easy to use.
I would highly recommend against putting `.array` everywhere in your code, as it will force the range you pass to it to be eagerly evaluated and allocate more memory from the GC. It's much better to take some initial data store, like an array, do all your filtering and mapping, etc. on it, and when you're done, _then_ turn it back into an array with a call to `.array`. That way you'll get all the lazy iteration and low memory footprint of ranges, and then at the end you have a nicely allocated array of data with the result that is easy to work with.
Honestly, though, in most of my code I usually just pass around ranges as they're very good for creating interlocking adapters over different backing stores. One really great article on advanced usage of ranges is H. S. Teoh's article on Component Programming with Ranges: https://wiki.dlang.org/Component_programming_with_ranges
A couple great resources on ranges in D:
http://www.informit.com/articles/printerfriendly/1407357
https://tour.dlang.org/tour/en/basics/ranges
How do I pass this output to some other function without doing .array()? It's rare that you do all your processing in one method. Should I do this:
void processFurther(T)(T t) if isInputRange!T { } ?
I mean, it would probably work, but I don't like how the conditions are detached from type definitions :S
> I don't like how the conditions are detached from type definitions
I can understand that; it's something that takes a bit of getting used to. See https://dlang.org/concepts.html for an explanation of template constraints and why they were designed this way.
https://www.packtpub.com/application-development/d-cookbook
https://www.packtpub.com/web-development/d-web-development
https://www.packtpub.com/application-development/learning-d
Plus buying them is a way to support some community members.
I am most excited about this, where a language supports two modes 1) interpreter for development, and 2) compilation for performance. Never thought about this, but reading this, it makes perfect sense on large projects
go run main.go
or: go run ./cmd/server
When invoked this way, Go compiles your code behind the scenes, but you don't have to create a binary.This means Go lends itself pretty well to ad-hoc scripting or writing small script-like tools.
Unfortunately, Go doesn't support shebang lines, but with gorun [1] you can:
#!/usr/bin/env gorun
package main
func main() {
println("Hello world!")
}
[1] https://github.com/erning/gorun #!/usr/bin/env dub
/+ dub.sdl:
name "allthepythons"
dependency "d-glob" version="~>0.3.0"
+/
import std.stdio : stdout;
import glob : glob;
void main () {
foreach (entry ; glob("/usr/local/bin/python*")) {
stdout.writefln("%s", entry);
}
}Scala (Ammonite) works like this.
The author isn't complaining about keystrokes; he wants the compile + run process to be faster. Using an interpreter instead of a compiler would make it faster.
java build ./app/ ./app
That's impressive if true as last I worked with Java it was a mess
For AOT there is this JEP: https://openjdk.java.net/jeps/295 and a different project: the GraalVM
So I'd say that Java can do "this" since recently (JDK 9 in 2017) via JShell (I wouldn't count BeanShell or Groovy), i.e. it always had the compiler part but added the interpreter.
Although its usage is still quite rare, whereas the blog post would suggest a different pattern.
GCJ improved very slowly and around 2009 lost most of its developers with the release of OpenJDK.
It starts interpreted, but if you run for very long, it runs compiled.
But that costs memory and startup time.
People usually don't do it because JITs are heavy so they'd prefer to share them.
It always makes me sad D hasn't picked up more. Usually comments I see about D seem pretty ambivalent to dismissive. It's a great language and to me has always felt like the way C++ should have been.
It does seem to be growing in popularity. Even in the years I've been using it, the number of libraries and community resources has expanded exponentially and every day new code is being added to
Not to mention dub is probably the most simple straightforward build system I've worked with.
The similarities are more surface deep once you start learning more about the different features and tools D offers.
Walter Bright did try to make C++ better, remember that D came along after he wrote the Digital Mars C++ compiler.
C++ has also improved in the meantime.
And appearance really only changes when you hit templates. And with D you can't tell (as an outsider) so it just looks like the non templated C++.
So either you work alone, in a small team that appreciates modern safe C++ (including Core guidelines), and enjoy C++, or you are faced to deal with all idiocrasies and unsafety issues from the past.
Now tell me why every OOP codebase I look at has this problem. ;-)
The reason is the second "O" in OOP. Trying to switch on the type of a thing, where every thing has only one type (ignoring inheritance which is another problem, not a solution), means that people will put all sorts of unrelated things in one place.
Not every project can be written 100% in this style, but the problem is very often programmers trying to mimick C++, e.g. doing object oriented fine-grained initialization/destruction stuff in C.
As Google, Microsoft, Apple, Amazon have been reporting in multiple occasions, the problem goes beyond programmers trying to mimick C++.
To the point that future Android versions will require hardware memory tagging enabled on ARM devices.
If you're actually going to look at it, I just want to make clear that I've never fuzzed it or anything, beyond running valgrind maybe twice (should be mentioned in the git log). And on the functional side, I don't even know what state this project is in. I think I lost interest in it when I needed to implement yet another way to encode x86-64 instructions, since having both floats and doubles is a requirement to run interesting things with OpenGL.
Let me know what problems you find!
So far based on what I've observed, people in the D community is the biggest critique of it's own, even more so than any other community I've seen on the internet.
The D forum is full of shit posts thrashing D for what it is.
Looking forward what new perspective you bring to the community!
Yes.
> any hurdles and/or benefits in relation to your Vision?
Hurdles: implementation issues, figuring out later on that there are ways to corrupt memory despite the rules we come up with.
Benefits: Compile-time memory safety.
The interpreter+compiler approach is something I've been pining for for a little while now. I've only just begun to punch holes in my obsessive tendency to only use interpreted languages (because I hate compile waits that much), and to me having the fast-iteration times of interpreters, and _also_ -O3 when it's needed, would be the best of all the worlds; IMHO JITs are a necessary hack for dynamic/untyped(/interpreted) languages, and there are serious real-world gains to be had from having the plumbing get done that lets people jump from interpretation, over JITs, straight to optimized AOT-compiled code.
Would be quite the project though, to port a fundamentally-compiled ecosystem like D to use an interpreter. I wonder how long a realistic timeframe to "minimally practically usable" would be.
Thinking about it, Cling (https://root.cern.ch/cling, https://github.com/root-project/cling, LGPL 2.1) wires Clang's C AST into LLVM's built-in JIT (IIUC) to get a C/C++ interpreter. D has LDC, so there is already integration of the UI/NCSAOSL and understanding of how to leverage LLVM. Perhaps a workable direction (with probably a lot of domain-specific knowledge already worked out and potentially available from ROOT) could be a Cling-like s/Clang/LDC/->LLVM ?
Another thought: using an approach like the above, it might be possible to add pragmas that specify whether functions should be AOTed or JITed, and how much JIT optimization should be done. I also wonder if the LLVM JIT can be told/forced to "precompile this specific function" (effectively AOTing just that function), within the JIT hot-code-replacement framework; if this were possible you could even hot-reload running code (with per-function/per-file/etc customizable optimization levels). IMHO it may be interesting to make this functionality available, and let the community/ecosystem work through the messiness of solving things like the struct-versioning problem. Clear communication would be important to rationalize and clarify the deliberateness of such a decision, of course, and that the language [design] hadn't gone completely nuts :) due to the number of segfaults/developer burnout/etc it would probably introduce.
Sort of. We already have an interpreter (CTFE!), it's just not up to the task for what I want to do with it.
> As Jonathan mentioned I'm still working with my students and working on the Foundation administration, legal, taxes, and finances.
> I've been involved with D since 2005. That's an eternity in this business. I think bringing Atila to the fore is a great positive because it brings a fresh perspective and approach.
from https://forum.dlang.org/post/qj18h2$8o1$1@digitalmars.com
There was a post about it on the forums.
As a portion of our work targets micros, all of our code needs to be written in a language that supports micros so that we can share code. There is impetus to move on from C, but Rust is the first and only viable replacement candidate because of this.
Nowadays many people are migrating to Python to use machine learning in Jupyter or just to run machine learning code in Python.
The base language is nice (and kind of expected), but for D-lang to grow in this space it needs port/replacements for at least NumPy, SciPy, Pandas, and Matplotlib.
Other than that, I'm okay with anything that was already in Eiffel or Modula-3…
The problem is, betterC is kind of in that awkward spot. It's not comparable to the "real" D, and if you can live with betterC, you might as well just use C and enjoy the wide C ecosystem.
This means you can write C and use the entire wide C ecosystem, but use D for the parts of the program which make sense in D, painlessly.
If you can be bothered to use betterC then that's probably not true. To be argumentative, C is fucking horrible. BetterC still gives you a decent chunk of D's features - templates alone make it worth the switch. No more macro spam for example.
Can you imagine how much boilerplate you'd have to write to mimic this: https://d.godbolt.org/z/3XNBFW
> With D, none of that is necessary. One can write the production code in D and have libraries automagically make that code callable from other languages.
If you're using an RPC IDL you explicitly do not want to share that code, you want to share that API.
I'm also dissatisfied with some of the design decisions accepted into C++11/14/17/20. (Some were fixable and just plainly shortsighted IMO, but others probably not, due to the language legacy).
Don't get me wrong, I love learning from the C++ community (conferences, tech talks, blogs and checking out how open-source projects that I'm interested in are implemented), but once that I had tasted the power and freedom of D going back to C++ feels like a huge step in the wrong direction.
And also being not only a user, but a contributor is immensely empowering. A PR to the standard library, runtime, compiler or package manager can take anywhere from days to mere hours (depending on the complexity of change), while attempting a change with a similar impact to C++ would likely take anywhere between months to years. And yes, I can see the value of the ISO C++ standardization process, but it's definitely not for me.
> with C++ the things are not so simple, because of the non standard ABI, across different compilers. With templates the things are becoming even more complicated. For now the easiest and the most reliable way to use C++ libraries from another language is to compile it to C++
This turns out not to be true. The only way to parse C++ is to use a C++ compiler; there is no negotiability there. However you can, as calypso[1] and dpp[2] (latter is not ready for primetime yet) do, use the c++ compiler to parse the c++ and then emit bindings in another language. As for ABI, there are really only two ABIs: msvc (which microsoft uses), and itanium (which everyone else uses). And D already implements both.
Thank you for the suggestion. It turns out to be correct. Obviously there is a huge amount of progress since the last times I had been looking at D, before more than 7 years. (https://dlang.org/spec/cpp_interface.html) Still the D way looks to me more inconvenient by requiring you to include the class internals into the D binding. Example from the D manual:
extern(C++):
struct Foo(T)
{
private:
T field;
public:
@disable this();
T get();
void set(T t);
}
Nim requires you only to mention the name of the class (template) and the public part of the interface which you actually going to use. Example from the Nim manual (https://nim-lang.org/docs/manual.html#importjs-pragma-import...). type StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.importcpp: "#[#] = #", header: "<map>".}
var x: StdMap[cint, cdouble]
x[6] = 91.4
> with gcc and llvm it covers pretty much all the same architectures/platforms as nimI am not sure whether they cover some really old platforms. By compiling to C you can target pretty much every platform which have a C89 standard conforming compiler.
A day ago I asked in the Dlang forum (https://forum.dlang.org/post/nmwinrjavfumvxffptxy@forum.dlan...) whether it is possible to develop in D for video game consoles, not only current generation which Remedy Games do for example, but also a few generations back. It turns out to not be completely clear, because maybe no one has tried it, but it was suggested that even if possible, probably it would require a considerable amount of tinkering. I don't know whether someone tried this in Nim but it seems to me, that by compiling to C89 or C++98, it would not be much an issue for every platform with a conforming compiler for these languages.
A C interface on C++ code is how most people do interoperability with C++ libraries. It is pretty much C, so you can just use the FFI. But it's not really a C++ compatible FFI.
Despite superficially similar angle bracket syntax, C++ templates and Rust generics are very different and incompatible in all but most trivial cases. D templates can get closer.
Rust also lacks many C++-isms: there are no copy/move constructors, no custom code can run on assignment, operator overloading is more conservative, there's no life before main(). Error handling, iterators, and strings are done differently.
Even if C++ could magically work in Rust, it'd be weird. OTOH D feels much like a rewrite of C++.
So D comes with an actor system baked in at the language level? I like that sort of thing after using Erlang and using some half baked libraries in other languages.
I’m curious how good it is...
You -can- explicitly manage threads and processes like in other languages, but much of the time there is a more lightweight, expressive construct available.
For instance, you can turn this loop: foreach(ref i; arr) i = i * i;
Into a parallelized loop by simply: foreach(ref i; parallel(arr)) i = i * i;
Example was shamelessly lifted from: https://tour.dlang.org/tour/en/multithreading/std-parallelis...
I’m curious how the actor model works on a large system with lots of 3rd party libraries (or even different development teams) when you can’t guarantee that everyone is using it.
I think on almost all cases, and also having a bigger community, it is a win for Rust/Go.
I also love D's metaprogramming. It feels almost like lisp. Go's lack of generics doesn't allow this and Rust's macros don't feel as comfortable for me.
Yes, D is smaller but it's also big enough for me. I don't feel like I'm missing out on much when I'm using D. If I need a library to do something that isn't already in the fairly generous stdlib, I can find it on DUB.
But I appreciate how that's not necessary and I can use only system-installed libs with Meson and pkg-config :P
It is funny how Go sold it as a feature, but it was always a deficiency in D (and yes, it just happened out of the box.)
That isn't to say C dynamic libraries didn't work, that is a linker thing, but it would be the same in Go.
But boy, on the Algol-tree, it's about as far away from Go as you can, erm, go. The blog poster's predecessor was about as heavy as you can get into generics without being called Stepanov.
D tends to have quite a lot of features and lets you pick your subset, which brings it closer to languages like C++ or Scala. Go, being basically Oberon filtered through New Jersey, is a lot more minimalistic. Old Java vs. new Java, basically.
https://atilaoncode.blog/2015/02/11/the-craziest-code-i-ever...
Compared to Go: much better designed and richer language.
Obviously in terms of community, it's much smaller. But if you're ready to "build vs buy" more, or if you have some small scope project, I'd encourage you to try it.
But I can testify that spending my first days with Rust was a struggle the whole way. It's probably because D had spoiled me a lot by the time I got to Rust. After some time I lost interest as Rust didn't offer anything that I was actually missing in D, while D had much to offer in the areas of things I liked.
the meta programming is very cool also
import std.stdio;
struct Math(string Op) {
static auto eval(T, U)(T l, U r) {
static if (Op == "+")
return l + r;
else static if (Op == "-")
return l - r;
else static if (Op == "*")
return l * r;
else static if (Op == "/")
return l / r;
}
}
static immutable auto result = Math!("+").eval(1, 2) + Math!("*").eval(3.0, 3.0);
void main() {
writeln(result);
}
You'll never be able to do anything like that in Rust until const generics are not only complete on their own, but also fully compatible with "const fn". import std;
template Math(char Op) {
auto eval(T, U)(T l, U r) {
static foreach(x; "+-*/") {
if (Op == x)
mixin("return l ", x, " r;");
}
}
}
static immutable result = Math!('+').eval(1, 2) + Math!('*').eval(3.0, 3.0);
void main() {
writeln(result);
} JSON serialization: 144 of 366
Single query: 152 of 404
Multiple queries: 195 of 394
Fortunes: 154 of 371
Data updates: 99 of 365
Plaintext: 81 of 352The most popular frameworks having the 90% of deployments, are at the middle to bottom of the Techempower benchmarks.
On the other hand, you will note that go / rust and C frameworks (which are playing in the same field as D) are on the top of that list.
An advantage of D in that situation is how easy it is to change the internals of an API without those changes propagating to the surface, both by design (e.g. UFCS, no brackets) and how that design is used (e.g. Templates)
There was also one where dmd was faster than ldc, so something must be up somewhere
Oh, we're well aware of it. It's just that the language design part consumes all our time.
A good IDE used to be my hangup for D but VS Code has a very solid plugin.
https://dlang.org/orgs-using-d.html
https://www.rust-lang.org/production/users
and we know plenty are using Go in prod, including Slack, Google (heavily for YouTube's database layer), and many others.
https://www.rust-lang.org/production/users
has all production users (it admittedly has a lot of Bitcoin Startups). But lacks some important users like Microsoft (for ripgrep in Visual Studio Code) and Facebook for its usage of Rust for Mercurial (admittedly this isn't production ready).
Edit: added previous "vision" links
We are considering hurting their search result score based on doc coverage tho.
Code-D with VS Code is also great, and it has fairly recently gotten funding from the D Language Foundation for further development.
There's also DCD, D-Scanner and dfmt which can be used with a lot of different editors.
[1] https://marketplace.visualstudio.com/items?itemName=webfreak...
[2] https://marketplace.visualstudio.com/items?itemName=dlang-vs...
Edit: It seems that dlang-vscode recommends to instead use vscode-dls [3] or code-dlang.
[3] https://marketplace.visualstudio.com/items?itemName=LaurentT...
But I don't think D hasn't succeeded in replacing C++ for this reason; the reason D hasn't succeeded yet is because it's relatively unknown in the enterprise developers circle. Most people haven't heard of D.
I feel bouts of sympathy every time I think of D, and I'm not even a hard core fan or anything.
No need to change the logo or anything. Just sneak in something actually searchable (dlang, or whatever) in footers and headers of documentation etc. Then just stick to it and Google will do the rest for you.
Doesn't do it at all to me...
Thought you meant the "Showing results for xxx / Search instead for yyy" correction, which switches your (unpopular) yyy query under you.
The suggestions are annoying, but can easily ignore and insist on my search term.
I hold a rather controversial (at least for HN, apparently) opinion that, I don't think we can expect a corporation to be impartial if there's no legal impetus on it and there's no monetary reason for them to act impartially. Google is a business, that makes money from selling your searches and displaying advertising. So, it's going to do exactly that.
Not any more hopeless than one of the top-10 most popular languages, C.
Except if you mean the juvenile joke it alludes to, in which case, nobody really cares between adults. No company is not gonna be use D because in some memes it means dick. Libraries, tooling, maturity, devs, speed, are the real concerns...
Though I usually just shoot back "no computers. code people just suck at names"
Whenever this complaint is lodged I feel like it’s just an easy thing to complain about that isn’t an actual problem at all. Am I wrong?
And it does not poses such a problem for searching engines in practice. At the end of the day, you never search for "C", you search for something like "pointer to function in C" and probably much more specific, so any search engine will give you right results.