I've had a couple of ideas recently about the importance of consistency in a language design, and how a few languages I highly respect (D, C#, and Nimrod) approach these issues. This post is mostly me wanting to reach out to a community that enjoys discussing such issues, in an effort to correct any mis-conceptions I might hold, and to spread potentially good ideas to the community in hopes that my favorite language will benefit from our discussion.

The points you raise are good and I generally like your ideas, although it feels a little early to talk about D3 when D2 is still far from a comprehensive solution. Amazing that bug 1528 is still open for example: http://stackoverflow.com/questions/10970143/wheres-the-conflict-here

Regarding your idea for merging compile-time and run-time arguments together, it sounds good at first but I wonder if it would be difficult to handle in the parser, because at the call site, the parser does not know whether a particular argument should be a type or an expression. Still, no insurmountable difficulties come to mind.

I certainly like the idea to introduce a more regular syntax for object construction (as I have proposed before, see http://d.puremagic.com/issues/show_bug.cgi?id=8381#c1) but you didn't say whether it would be allowed to declare a static method called "new". I'd be adamant that it should be allowed: the caller should not know whether they are calling a constructor or not. Also, I'm inclined to think that constructors should use "init", in keeping with tradition.

A couple inconsistencies that come immediately to my mind about D2 are

1. Function calling is foo!(x, y)(z) but declaration is foo(x, y)(int z) And the compiler doesn't always offer a good error message. I'm seeing "function declaration without return type. (Note that constructors are always named 'this')"
   "no identifier for declarator myFunction!(Range)(Range r)"
2. Ref parameters are declared as (ref int x) but are not allowed to be called as (ref x) -- then again, maybe it's not a real inconsistency, but I'm annoyed. It prevents my code from self-documenting properly.

Obviously, D is easy compared to C++, but no language should be judged by such a low standard of learnability. So I am also bothered by various things about D that feel unintuitive:

1. Enums. Since most enums are just a single value, they are named incorrectly. 2. immutable int[] func()... does not return an immutable array of int[]? 3. 0..10 in a "foreach" loop is not a range. It took me awhile to find the equivalent range function, whose name is quite baffling: "iota(10)" 4. Eponymous templates aren't distinct enough. Their syntax is the same as a normal template except that the outer and inner members just happen to have the same name. This confused me the other day when I was trying to understand some code by Nick, which called a method inside an eponymous templates via another magic syntax, UFCS (I like UFCS, but I might be a little happier if free functions had to request participation in it.) 5. The meaning is non-obvious when using "static import" and advanced imports like "import a = b : c, d" or "import a : b = c, d = e" or "import a = b : c = d". 6. the syntax of is(...)! It looks like a function or operator with an expression inside, when in fact the whole thing is one big operator. It's especially not obvious that "is(typeof(foo + bar))" means "test whether foo+bar is a valid and meaningful expression".

Making matters worse, the language itself and most of its constructs are non-Googlable. For example if you don't remember how do declare the forwarding operator (alias this), what do you search for? If you see "alias _suchAndSuch this" and don't know what it means, what do you search for? (one might not think of removing the middle word and searching for that).

I even have trouble finding stuff in TDPL e-book. The place where templates are discussed is odd: section 7.5 in chapter 7, "user-defined types", even though the template statement doesn't actually define a type. I know, I should just read the book again... say, where's the second edition? I got so disappointed when I reached the end of chapter 13 and it was followed by an index. No UFCS or traits or ranges mentioned in there anywhere... compile-time function evaluation is mentioned, but the actual acronym CTFE is not.

I also hope something will be changed about contracts. I am unlikely to ever use them if there's no option to keep SOME of them in release builds (I need them to work at all boundaries between different parties' code, e.g. official API boundaries, and it is preferable to keep them in all cases that they don't hurt performance; finally, we should consider that the class that contains the contracts may not know its own role in the program, so it may not know whether to assert or enforce is best). Plus, the syntax is too verbose. Instead of

   in {
     assert(x >= 0 && x < 100);
   },

I'd prefer just in(x >= 0 && x < 100). I'd rather not type "body" either. Speaking of verbosity -- breaks in switches. Nuff said.

Interestingly, the discussion so far has been all about syntax, not any significant new features. I'm thinking ... coersion of a class to any compatible interface (as in Go)? pattern matching? tuple unpacking? an attribute system? unit inference? compiler plug-ins? further enhanced metaprogramming? safe navigation operator? user-defined operators? first-class void type? If I were a compiler writer (and I want to be) the possibilities would be MADDENINGLY endless :)

Reply via email to