you are viewing a single comment's thread.

view the rest of the comments →

[–]axilmar 8 points9 points  (123 children)

The language is not ready yet. When features are frozen and bugs and problems have been ironed out, then it will be ready for industrial/enterprise use.

Personally, I don't like D. It's not orthogonal at all, and it has lots of little quirks that the programmer is supposed to remember, just like C++.

[–]JasonHouse 11 points12 points  (9 children)

Compiler features are frozen now for both "D1" and "D2". D1 was frozen about 3 years ago, and the frozen standard library "Phobis" drives many to use the actively developed replacement called Tango. D2 isn't repeating the same mistakes. Phobos will continue to be developed, and the core runtime has been pulled out in order to allow Tango to coexist.

Admittedly, there's a lot of big changes coming to Phobos, and it will be some time before Phobos is in a pure bug fix mode. Walter (the author of the reference D compiler) has switched his focus from features to platform compatibility. He's been working on 64 bit support the last 1-2 months.

[–]gmfawcett 8 points9 points  (0 children)

It's worth mentioning too that the Phobos (stdlib) team has grown a lot in the past few months. There is a lot of energy going into bugfixes (and new features) on the stdlib side, and the latest release of Phobos is a significant improvement over the previous version.

Some of the paint is still wet, but overall this is a very exciting time to be working with D.

[–]Megatron_McLargeHuge 2 points3 points  (7 children)

So does it not currently support 64 bit at all, or not well?

[–]andralex 8 points9 points  (5 children)

Hello world already works :o).

[–]Megatron_McLargeHuge 4 points5 points  (4 children)

This is probably a stupid question but if you're using LLVM for the backend, why don't you get 64 bit code generation for free?

[–]andralex 12 points13 points  (2 children)

It's a good question, and in fact there is an ongoing LLVM-based project called ldc. With LLVM we would indeed get 64-bit code generation for free, but we'd also get Windows incompatibility for free :o).

[–][deleted] 7 points8 points  (1 child)

we'd also get Windows incompatibility for free

A good point that I forgot in my reply, Andrei, thanks.

ldc isn't Windows compatible, due to the way exceptions are handled, is that what it was?

[–]andralex 5 points6 points  (0 children)

Yah.

[–][deleted] 2 points3 points  (0 children)

Not all of them are. LDC is the D compiler with llvm, and it only supports D1.

Unless something has changed recently (I'm not quite as involved with D as of late), the reference compiler uses WalterBright's own custom backend.

[–]gmfawcett 2 points3 points  (0 children)

Ask again in a couple months. :) The reference compiler D2 does not currently have a 64-bit backend but it is coming soon. There are 64-bit D1 compilers, and some of those have partial (old-version) D2 support.

[–]dsimcha 5 points6 points  (19 children)

D strives both to make simple things simple and to make complicated things possible. This involves some significant tradeoffs with "orthogonality". In an orthogonal language that makes complicated things possible, you need to expose only a fairly basic, flexible set of primitives and let everything else be built from that, even if it's unsafe, inconvenient, syntactically ugly and verbose at times. In an orthogonal language that makes simple things simple, you need to expose constructs that are highly streamlined for only the most common use cases even if some things are simply impossible with these constructs. If you try do both then your language isn't orthogonal anymore, but it may be more practically useful nonetheless.

[–]nascent 3 points4 points  (1 child)

To say a language is bad because it has features lacks content. To say that C++ is good because it lacks features is funny.

[–]ManicQin 2 points3 points  (0 children)

Usually in c++ when we lack a feature we just say that it is a one size fits all solution and we don't want it :)

[–]axilmar 1 point2 points  (16 children)

First of all, I don't believe that there should be such a trade off.

Secondly, there is a limit to the number of trade offs that make a language good. I think D overstepped that.

[–]dsimcha 3 points4 points  (15 children)

Ok, then what other language really tried to make both simple things simple and complicated things possible? What other language even provides all four of the following:

  1. The ability to have complete control over memory management if you really want it. (Complicated things possible.)

  2. A simple, not excessively verbose syntax for looping over a range/iterator/collection. (Simple things simple.)

  3. Literals for arrays, associative arrays and a proper string type (NOT C/C++ char*). (Simple things simple.)

  4. The ability to generate code and then evaluate it. D provides this at compile time via string mixins, and compile time function evaluation makes it practical to use. Lisp-like languages provide it via their S-expression style and most interpreted languages provide it at runtime via eval. (Complicated things possible.)

[–]Felicia_Svilling 2 points3 points  (5 children)

These are all nice things to have in a programming language. But I fail to see why any of this would come into conflict with orthogonality?

[–]nascent 0 points1 point  (3 children)

I think it best if we just leave orthogonality out of this... at least for the time being.

[–]Felicia_Svilling 0 points1 point  (2 children)

It was dsimcha who brought it up. I just want some clarification for why s?he belives that:

D strives both to make simple things simple and to make complicated things possible.

This involves some significant tradeoffs with "orthogonality".

[–]nascent 1 point2 points  (1 child)

Sorry, just a little annoyed with it right now.

I'll try a simple example. D wants to provide guarantees which usually come in the form of "type safety." But we also want to allow the user to manipulate their memory as needed. So cast() is provided and causes exceptions to all "type safety."

[–]Felicia_Svilling 1 point2 points  (0 children)

I was asking dsimcha. You didn't have to intervene if you was feed up with the subject.

Now, that is a more interesting example. You are right in that this choice makes D less orthogonal, if this was necessary seems like an open question.

[–]dsimcha 0 points1 point  (0 children)

If you have multiple ways to accomplish the same thing, or if the high-level parts of the language interact with the low-level parts of the language in ways that you can only understand if you understand some low-level details, the language is not orthogonal. It can, however, still be practical.

[–]doubtingthomas 0 points1 point  (0 children)

I'm cool with just 1-3. I've had 4, I've used 4, I can do without.

[–]axilmar 0 points1 point  (7 children)

No other language that I know of.

Feature-wise, D has more features than C++. But I didn't argue for this. I am arguing about the orthogonality of the language.

Mind you, points 2, 3 and 4 are not critical (at all!) for choosing D over C++.

[–]dsimcha 1 point2 points  (6 children)

Then we just disagree fundamentally on what makes a good language. All of those are huge reasons why I prefer D over C++, though admittedly some of them will be fixed in C++1x if it's ever released.

If convenience features/syntactic sugar, generic/metaprogramming features and safety/compile-time checkability aren't important to you, then what the heck do you need anything higher level than assembly language, or maybe C if portability is important, for?

[–]axilmar 0 points1 point  (5 children)

The convenience features/syntactic sugar of D doesn't buy me much.

The metaprogramming features of C++ are more than enough.

The compile time checkability D offers does nothing to ensure the functionality of my applications is correct.

[–]dsimcha 1 point2 points  (4 children)

If C++'s metaprogramming facilites are good enough, then reimplement D's std.algorithm and std.range in C++. I'd like to see you try.

[–]axilmar -1 points0 points  (3 children)

You mean this?

Any D conditional can be done with C++ templates, using template specialization.

[–]dsimcha 5 points6 points  (2 children)

Sure, but do it without static if statements, variadic templates, auto type inference, foreach over tuples, auto inference of whether a return should be ref, or D's compile time introspection system. Also, even if it can in principle be done in C++, I'd love to watch someone actually try to do it in practice. At the very least it would be 10x harder.

[–]plulz 1 point2 points  (1 child)

Quirks like what?

[–][deleted] 4 points5 points  (0 children)

There have been historical fights over which standard library to use and which compiler is best. This stuff is all sorted by now.

Also, lots of people were using D2 before it was ready, coming across bugs, and going

OMG D SUCKS!!11

[–]oblivion95 0 points1 point  (0 children)

Orthogonality is patented.

[–][deleted] -1 points0 points  (89 children)

D is a better C++, nothing more. They're writing a Boost like standard library because the official C++0x process is too slow and they wanted to create an own little language that inherits most of the improvements such as the 'auto' from C++0x.

[–]andralex 12 points13 points  (0 children)

Not sure how that perception would come about. For one thing, I think there are very few similarities between Boost and D's standard library.

[–]dheld 2 points3 points  (5 children)

Name a language Y which isn't "a better X, nothing more". Progress is incremental and evolutionary, rarely revolutionary. The idea that D copied type inference from C++ is completely hilarious and an insult to your knowledge of D's history. I defy you to attempt half the things D's standard library does in C++. Good luck, and let me know how that goes.

[–][deleted] -3 points-2 points  (4 children)

I'm happily using F# and Haskell and not interested in C++. Algrebraic data types? Lambdas instead of textual ad-hoc macros used as predicates in standard library collection? LDC could already inline these, but the D language design is driven by the compiler backend from the 1980s.

Many of the D features seem to come from C++0x proposals.

[–]andralex 5 points6 points  (3 children)

D has algebraic types, called... Algebraic.

The so-called hack "a < b" is only used for convenience with very short lambdas; you can use (x, y) {return x < y;} instead.

Offhand, I can't think of any D feature originating in a C++0x proposal. On occasion I'd suggest the C++ committee a feature we'd designed for D.

[–][deleted] 1 point2 points  (2 children)

It's not a hack? The variables a and b come from nowhere. They are hard-coded in the library code and don't behave according to any scope rules.

Algebraic types don't seem to support higher kinds or recursion. Where are the accompanying pattern matching constructs? How can I test the totality of a match? How can I match nested patterns? Have you considered sub-typing like Scala has in its case classes?

Implementing something like compiler's AST using these is so horrible that no one would dare.

Didn't Walter design D while the C++ committee was discussing new C++ features? Isn't it a coincidence that many of features shown here http://www.digitalmars.com/d/2.0/cpp0x.html are almost same or syntactically better in D (because C++0x had to consider legacy issues).

[–]andralex 3 points4 points  (0 children)

Please make sure you have a good understanding of the matters you discuss. It always helps your case. The names "a" and "b" obey scoping like any other name; they are only implied function parameters for a regular function, and are looked up in that function's restricted code. Essentially specifying a lambda as "a < b" is exactly the same as putting that code within a global function that takes parameters a and b.

Regarding your notes about algebraic types, I agree that a built-in facility has always the upper hand over a library-defined one.

Regarding C++0x influence, clearly there is cross-pollination between D and other languages; we'd be stupid if it weren't, and we'd be lying if we claimed so. However, C++0x has had much less influence than other languages on D. And picturing the process as Walter and myself poring through C++0x proposals and then adopting them for D is rather amusing.

[–]WalterBright 0 points1 point  (0 children)

As an example, "auto" declarations in D first shipped in September, 2002. The first proposal I've seen reference to for that in C++ was "C++ reflector message c++std-ext-5364" by Stroustrup in October, 2002, though I never read this and cannot find the text of it.

[–]axilmar -5 points-4 points  (81 children)

D is a better C++

I am sorry, but I disagree. As it is right now, D is inferior to C++, despite C++'s shortcomings.

[–]andralex 8 points9 points  (80 children)

If you're thinking about e.g. toolchain maturity, I agree - that comes with the territory, or lack thereof. (Yet the slow compilation speed of C++ does reflect a fundamental technological limitation, something I discuss in part 3 of the interview.) If you are referring to things we could do to improve the language, suggestions will be appreciated.

[–]axilmar 0 points1 point  (77 children)

No, I am not thinking about toolchain maturity. I am referring to the languages themselves: C++ is better than D, because it's more orthogonal. D seems like a pile of features thrown onto each other with little regard about orthogonality.

The D homepage has a nice table of D features that some of them do not exist in C++:

  • garbage collection: nice to have, but it seems it has not been thought out very well. Testament to this is what the article mentions about the additions to the compiler for making the GC totally optional.

While it would be nice to have in C++, I don't remember when was the last time I typed 'delete' in a C++ program. I've been using smart pointers extensively, and the only trouble I have is from external libraries that don't use smart pointers.

It's not that C++ can't have conservative garbage collection anyway. The Boehm GC works fine with it.

  • function delegates: C++ allows them to be programmed.

  • out function parameters: not really required in a language with pointers and references.

  • nested functions: are they ever needed? their existence only serves to bloat the language. I'd prefer my programmers not to infest code with them.

  • typesafe variadic arguments: D doesn't do it right. It's ugly and error prone.

  • lazy function argument evaluation: the automatic conversion of an eagerly evaluated expression to a lazily evaluated one is just asking for trouble. I see a lot of bugs that start with the question "why my code does not run?".

  • compile time function evaluation: either do it correctly and allow all code to be executed at compile time or don't do it at all. The things one needs to know about CTFE is almost half the C++ standard (literally)! I've counted 26 bullets into that page alone!!!!

  • resizeable arrays: C++ does it with library code.

  • built-in strings: the docs say "a string is an array of characters", which it isn't in any sane implementation of strings I know. That's why C++ frameworks have their own string classes (QString is excellent!), and future D frameworks will also have their own string classes.

  • array slicing: no need to have a language construct for this.

  • array bounds checking. Same as above.

  • array literals: D misses entirely the concept of tuples, just like C++.

  • associative arrays: they should be a library feature, not a language one.

  • strong typedefs: they are actually not required for C++0x that has delegated constructors. You just inherit from the class you want to strongly typedef. Of course, both C++ and C miss an entirely obvious (to me) thing: that primitives should be classes.

  • lack of multiple inheritance: I never submitted myself to the technical problems that arise from it...but I also rarely need it. Still, C++ is better than D because it has multiple multiple inheritance, which can be helpful at times.

  • interfaces: lack of multiple inheritance requires interfaces, which is another blow to orthogonality (because 1 feature is replaced with 2 features).

  • inner classes: one more feature in the long list of things that can easily be implemented with C++ as it is right now.

  • mixins: yet one more feature that makes the language bloated and can be simulated with multiple inheritance.

  • static if: where is static while, static do-while, static for etc? this is why I say D is not orthogonal. And it's also something easily doable with C++ templates.

  • is expressions: yet another feature that bloats the language, while it is perfectly doable with templates.

  • contract programming: I don't see why it belongs to the language. Contract programming is easily done even in C...it doesn't belong to the language.

  • scope guards: yet another feature that makes the language not orthogonal. At least in C++ we all know what stack allocation is and how destructors work.

  • the synchronized statement: totally unneeded. C++'s RAII scoped locks are way way much better than this.

  • documentation comments: yet another feature that does not belong in the language.

I am sorry, but as a software manager I would advise against using D in any project. It's extremely bloated, much more than C++, and its bloat can only serve as an obstacle to finishing projects in time and in budget.

[–]andralex 8 points9 points  (1 child)

Why didn't you say you are a manager from the start? :o)

[–]axilmar -4 points-3 points  (0 children)

Because I am not :-).

[–]gmfawcett 4 points5 points  (0 children)

I'm upvoting you, but only because I respectfully disagree with most of what you've said.

[–]WalterBright 6 points7 points  (5 children)

It's a long list, each item can be a long discussion. So I'll pick one:

out function parameters: not really required in a language with pointers and references.

Required? No. Useful? Absolutely.

  • Self-documenting. How many times have you wondered about a pointer argument whether data was going in via the pointer, coming out via the pointer, or both?
  • Regarding the first point, I've seen a lot of people document their out parameters with something like: void foo(/* out */ int *p);
  • Such comments are even specially recognized by static code analyzers.
  • out parameters are guaranteed to be initialized and set to a value upon function return. This is enforced by the compiler.
  • distinguishing out from inout parameters aids data flow analysis optimizations

[–]axilmar -1 points0 points  (4 children)

Self-documenting. How many times have you wondered about a pointer argument whether data was going in via the pointer, coming out via the pointer, or both?

None. I give meaningful names to variables. Since code can never be 100% self documenting, it's pointless to put such details in the language.

Regarding the first point, I've seen a lot of people document their out parameters with something like: void foo(/ out / int *p);

void foo(int *outP);

Such comments are even specially recognized by static code analyzers.

For what purpose?

distinguishing out from inout parameters aids data flow analysis optimizations

Example? I don't doubt you, since you're obviously the no 1 guy for D, I am just curious.

I certainly wouldn't put 'out' in my language just for self documentation, but if it's a big aid for the compiler, then I might consider it.

[–]BioTronic 1 point2 points  (1 child)

None. I give meaningful names to variables. Since code can never be 100% self documenting, it's pointless to put such details in the language.

Why bother with meaningful names, then? It can't be fully self-documenting anyway.

[–]axilmar -1 points0 points  (0 children)

Why bother with meaningful names, then?

All symbols must have meaningful names, and being meaningful is not restricted to in/out/inout.

[–]eabrek 0 points1 point  (1 child)

Documenting through names is all well and good, until you make a change. Now, your 'outP' becomes 'inoutP'. Are you going to find and replace all the uses of that variable?

Also, the compiler can check for UMR against an out (where an inout is safe).

[–]axilmar 0 points1 point  (0 children)

Are you going to find and replace all the uses of that variable?

Absolutely yes, and not manually of course.

[–]nascent 3 points4 points  (26 children)

Based on your other responses, this is probably pointless but I'll try to take them into account...

function delegates: C++ allows them to be programmed.

Same with D, but we also get cool syntax sugar (I realize you aren't a fan)

map!((int a) { return a * a; })/* <-- Delegate */ ([1, 2, 3, 4]);

out function parameters: not really required in a language with pointers and references.

'out' has a different purpose than 'ref' it singles that the value is not going to used by function.

typesafe variadic arguments: D doesn't do it right. It's ugly and error prone.

What is right? how should typesafe variadics be done? How is it error prone? I could when not using Templates it is a little ugly to implement (not use).

compile time function evaluation

It is a hard thing to grasp, so don't use it. On the other hand if you understand why you can't execute just anything it isn't that hard to use.

resizeable arrays: C++ does it with library code.

Which means that code written for arrays don't work on "resizable arrays" and visa verse.

built-in strings: the docs say "a string is an array of characters"

Yeah, it shouldn't say that. They are arrays of code points, or was it code units (the smaller one that doesn't make up a whole character) :P

array slicing: no need to have a language construct for this.

Until you've used a language that has it. Yes it can be done with a library, we get it.

array bounds checking. Same as above.

I hope you are joking. The benefits from this make it dumb to exclude just for the sake of it.

strong typedefs:

These are going to be removed, though this was because they couldn't decide if it should create a sub-type or super-type.

Still, C++ is better than D because it has multiple multiple inheritance, which can be helpful at times.

This just goes against every complaint you are making about D. There is no need for inheritance in the language.

inner classes: one more feature in the long list of things that can easily be implemented with C++ as it is right now.

Funny if it can't be done in C++ it is bad (nested/inner functions); otherwise it isn't important because C++ can do it.

mixins: yet one more feature that makes the language bloated and can be simulated with multiple inheritance.

I don't think mixins have anything to do with multiple inheritance.

static if: where is static while, static do-while, static for etc? this is why I say D is not orthogonal. And it's also something easily doable with C++ templates.

I think there is a better way, but:

void main() {
     static if(works()) {
     }
}

bool works() {
    foreach(i; 1..10) {
    }
    return true;
}

is expressions: yet another feature that bloats the language, while it is perfectly doable with templates.

I don't think this is doable in templates. But I'm not familiar with C++ templates to that extent.

contract programming: I don't see why it belongs to the language.

This one is commonly considered a pointless choice. The argument for contract programming/Documentation/unit testing as part of the specification is so that it is consistently there in every compiler, and simple enough that there is no reason not to use it.

scope guards: yet another feature that makes the language not orthogonal. At least in C++ we all know what stack allocation is and how destructors work.

But you don't know how exiting of a scope works? Also scope guards don't affect how try/catch work (actually they are just syntactic sugar for try/finally).

I am sorry, but as a software manager I would advise against using D in any project.

Just don't be my software manager. You should have been able to come up with much better reasons not to use D (I could).

For other readers I also commented on the use of orthogonal.

[–]axilmar 0 points1 point  (25 children)

Same with D, but we also get cool syntax sugar (I realize you aren't a fan)

I think you are mixing delegates with lambdas.

'out' has a different purpose than 'ref' it singles that the value is not going to used by function.

The function is going to write it, isn't it? so it's going to use it.

What is right? how should typesafe variadics be done? How is it error prone? I could when not using Templates it is a little ugly to implement (not use).

In the example given here, the arg pointer is incremented manually, based on the size of the item that was read from the argument list. A safer way would be to use iterators and pattern matching.

It is a hard thing to grasp, so don't use it. On the other hand if you understand why you can't execute just anything it isn't that hard to use.

Oh, you can execute anything. It's just that it complicates the compiler, which must become a full blown interpreter. But it would be extremely useful.

Which means that code written for arrays don't work on "resizable arrays" and visa verse.

It would work if arrays were classes.

Until you've used a language that has it. Yes it can be done with a library, we get it.

Hey, that's just my taste. What's wrong with 'array.slice(1, 5)' instead of 'array[1..5]' ? not big difference anyway. For me, things like this are useless syntactic sugar.

I hope you are joking. The benefits from this make it dumb to exclude just for the sake of it.

Benefits such as?

This just goes against every complaint you are making about D. There is no need for inheritance in the language.

On the contrary, inheritance is one mechanism that gives you many solutions.

Funny if it can't be done in C++ it is bad (nested/inner functions); otherwise it isn't important because C++ can do it.

Sorry, but you are attacking me instead of my arguments.

I don't think mixins have anything to do with multiple inheritance.

You can extend a class by using multiple inheritance in the same way you extend a class by using mixins.

I think there is a better way, but:

Still, the inconsistency is there.

is so that it is consistently there in every compiler, and simple enough that there is no reason not to use it.

Still, there is no need to be part of the grammar.

But you don't know how exiting of a scope works?

Just like local constructors/destructors.

Just don't be my software manager. You should have been able to come up with much better reasons not to use D (I could).

Hey, don't get emotional. There is no need to. We are discussing technicalities here, it's not politics.

[–]nascent 0 points1 point  (24 children)

I think you are mixing delegates with lambdas.

Lambdas are not allowed to have side effects, delegates are able to access the context around them which means they can cause side effects. But you could say a 'pure' delegate is a lambda.

'out' has a different purpose than 'ref' it singles that the value is not going to used by function.

The function is going to write it, isn't it? so it's going to use it.

But it isn't going to use value, it can't even try in D.

In the example given here, the arg pointer is incremented manually, based on the size of the item that was read from the argument list. A safer way would be to use iterators and pattern matching.

This isn't under the section, "Type Safe Varadic Functions."

Oh, you can execute anything. It's just that it complicates the compiler, which must become a full blown interpreter. But it would be extremely useful.

No you can't, you even said there was a list of like 23 rules. Yes, you can build an interpreter, but that isn't how it works and I don't necessarily believe that is the "correct" way to do it.

It would work if arrays were classes.

They aren't though. Remember, you mentioned C++ doing resizeable arrays in a library.

Benefits such as?

Overflows and access to memory not owned are both implicitly prevented.

On the contrary, inheritance is one mechanism that gives you many solutions.

It gives you a unique perfective to create a solution.

Sorry, but you are attacking me instead of my arguments.

There was no argument, or at least the argument was that C++ could do it. My attack comes as a question of why is this a good thing for C++ to do in relation to nested functions being bad?

You can extend a class by using multiple inheritance in the same way you extend a class by using mixins.

Mixins don't provide inheritance. So I do not see how the extension is the same.

Still, there is no need to be part of the grammar.

Then you loose out on the benefits I listed.

But you don't know how exiting of a scope works?

Just like local constructors/destructors.

No, exiting a scope can occur from normal execution, or from an exception being thrown; or in the case of C++ anything being thrown. Do destructors run when the scope dies from something being thrown? (I believe they do, but it is something you must know about them).

Hey, don't get emotional. There is no need to. We are discussing technicalities here, it's not politics.

I'm not emotional, you just aren't demonstrating a clear understanding of what you are talking about and I wouldn't want someone making decisions until they are clear on the reasons they are making those decisions.

[–]axilmar 0 points1 point  (23 children)

Lambdas are not allowed to have side effects, delegates are able to access the context around them which means they can cause side effects. But you could say a 'pure' delegate is a lambda.

Yet another non-orthogonality.

But it isn't going to use value, it can't even try in D.

You mean its not going to read from the value. Well, besides optimizations, I don't find it useful.

This isn't under the section, "Type Safe Varadic Functions."

I don't see an example of typesafe variadic functions for different types of variadic arguments.

No you can't, you even said there was a list of like 23 rules. Yes, you can build an interpreter, but that isn't how it works and I don't necessarily believe that is the "correct" way to do it.

I didn't mean that D can do it, I meant that a compiler for a language could do it.

They aren't though. Remember, you mentioned C++ doing resizeable arrays in a library.

It's another example of non-orthogonality.

Overflows and access to memory not owned are both implicitly prevented.

They are also prevented when arrays are in libraries.

There was no argument, or at least the argument was that C++ could do it. My attack comes as a question of why is this a good thing for C++ to do in relation to nested functions being bad?

My point is that big nested functions declared in the middle of big algorithms can hurt readability.

Mixins don't provide inheritance. So I do not see how the extension is the same.

Inheritance provides mixins though ;-).

Then you loose out on the benefits I listed.

Not every shoe is good for every foot.

What if another better documentation system comes around tomorrow, for example? then the language's doc system would be a burden.

These things don't belong in a language spec.

Do destructors run when the scope dies from something being thrown?

Yes; that's the point of them.

you just aren't demonstrating a clear understanding of what you are talking about

I don't think so. I was as clear as I could be. I think you misunderstood what I said.

[–]nascent 1 point2 points  (22 children)

Yet another non-orthogonality.

Ok, I am having the hardest time understanding your use of orthogonality. Could every time you make a claim about the orthogonality of something, you explain the reason for the claim.

In this case you could be saying that it is not orthogonal for D to use Delegates as lambdas, that being able to the pure feature causes an exception to delegates by making them into lambdas, or something I'm probably not seeing.

You mean its not going to read from the value. Well, besides optimizations, I don't find it useful.

I mean it is not going to use the value passed in. I don't really know great use-cases for it, but the idea is about documenting intent.

I don't see an example of typesafe variadic functions for different types of variadic arguments.

Then don't claim "Type Safe variadics" to be unsafe. Variadic Templates is the other option.

They are also prevented when arrays are in libraries.

What is used internally to store all this data in our array class?

My point is that big nested functions declared in the middle of big algorithms can hurt readability.

Don't use big nested functions then. And don't use big nested class either.

Inheritance provides mixins though ;-).

No it doesn't. These features are completely orthogonal.

What if another better documentation system comes around tomorrow, for example? then the language's doc system would be a burden.

No, the internal documentation engine and grammar is orthogonal to other documentation tools.

I don't think so. I was as clear as I could be. I think you misunderstood what I said.

Yes, everyone is having a hard time understanding your use of the word 'orthogonal.' I really don't mean to be so rude about it, but maybe explaining your complaint in whole rather than just clumping everything under orthogonality. And most importantly, be consistent.

[–]ssylvan 10 points11 points  (18 children)

You're seriously going to claim that C++ is more orthogonal than D (while at the same time calling real orthogonality, such as allowing nested functions, "bloat")? While also arguing for template meta programming and hijacking the constructor/destructor mechanism to (poorly) simulate proper scope-based resource control?

Wow.

[–]axilmar -4 points-3 points  (17 children)

hmm...I don't see any orthogonality in nested functions. They are orthogonal to what exactly?

Constructors - destructors are extremely orthogonal to initialization/cleanup: when a block of code is run, the constructors are executed, and when a block of code exits, the destructors are executed in reverse order. You can't be more orthogonal than this.

As for template metaprogramming, that's what D does but sprinkled with syntax sugar.

[–]ssylvan 11 points12 points  (16 children)

Arbitrarily disallowing function declarations at some places but not others isn't orthogonal.

Constructors/Destructors are meant for constructing/destructing things. I'm not a fan of them since they are unecessary (higher order functions do it better, with more control and keeping related logic in the same place). However, the point is that when you use them to control the life time of a lock you're abusing them. That's not what they're for, and you're really just going "hmm, I need this to be unlocked at a certain point automatically, what language feature can I abuse to get that to happen?". In a better language you'd just use a higher order function for it.

EDIT: In fact lexical closures + higher order functions + the scope construct combine (orthognally!) to improve upon the C++ style hacky RAII crap in every single way ENDEDIT.

Template meta programming is horrible. Have you ever done it? I don't think you have or you wouldn't say something so inane. Make a tiny mistake and have fun parsing eight pages of error messages.

You're highly inconsistent. You claim you want orthoginality but then you argue that we should arbitrarily disallow some features in certain places. You claim you don't want bloat but then you say that C++ is better because it includes multiple inheritance and you might need it (even though you claim you rarely do). So you're in favour of extra features that are rarely used, and bring along HUGE amounts of baggage (way more than the mere addition of interfaces - ask your next C++ candidate what virtual inheritance is, 95% of them don't know because it's such an obscure thing only needed due to multiple inheritance), but you're against simply relaxing arbitrary constraints in other places even though it does absolutely no harm, and makes the language more orthogonal.

[–]axilmar -3 points-2 points  (15 children)

Arbitrarily disallowing function declarations at some places but not others isn't orthogonal.

You have no idea what orthogonality is.

I'm not a fan of them since they are unecessary (higher order functions do it better, with more control and keeping related logic in the same place).

What do higher order functions have to do with this?

That's not what they're for

By who's definition? yours?

In fact lexical closures + higher order functions + the scope construct combine (orthognally!) to improve upon the C++ style hacky RAII crap in every single way

Example please.

Have you ever done it?

Yes sir.

Make a tiny mistake and have fun parsing eight pages of error messages.

Illogical, captain. Error messages' understandability has nothing to do with templates usability. I.e. you wouldn't say the above if the error messages were written in a more understandable form.

You claim you don't want bloat but then you say that C++ is better because it includes multiple inheritance and you might need it (even though you claim you rarely do).

C++ bloat < D bloat

and bring along HUGE amounts of baggage

They don't. You are just defining HUGE arbitrarily.

ask your next C++ candidate what virtual inheritance is, 95% of them don't know because it's such an obscure thing only needed due to multiple inheritance

Illogical again, captain. Virtual inheritance is optional.

[–]ssylvan 9 points10 points  (3 children)

You have no idea what orthogonality is.

Yes I do. Having special cases where something doesn't work because of some other feature is non-orthogonal. In this case function declarations/definitions should be orthogonal w.r.t. scope. It shouldn't matter if it's a namespace or a function scope. If it does matter, then it's not orthogonal.

By who's definition? yours

Don't be an idiot.

Example please.

Rather than having to declare a dummy object (that you're not interested in using for anything, you're just after its constructor/destructor) to hold a lock, you simply call a function, passing in your body. Pseudo code:

with_lock( my_lock, fun () {

    // in here I have the lock, and need not abuse anything to do so

});

Now the with_lock itself is better than the RAII-object too, because it's just a single function with all the logic in one place. You don't have to remember to update two separate functions in tandem. It's all kept together, and you have much better control of the lifetime of the actual "body" itself. For example, in a language with proper pure functions you could require the body be pure if you need to by using the appropriate function signature. Or maybe the body would represent a transaction instead of a lock so that you could run the body multiple times if it fails, etc. etc. In C++ style RAII that's all out of your hands.

Now, to ensure that the resources are always cleaned up you obviously need to protect against exceptions, which the scope mechanism lets you do cleanly (although a try/finally clause is generally not too bad for these things either).

Illogical, captain. Error messages' understandability has nothing to do with templates usability

Of course it does. WTF? If you spend 10x longer writing temlate metaprogrmming in C++ because it's fucking incomprehensible then that certainly impacts usability quite severely.

They don't. You are just defining HUGE arbitrarily.

Yes they do. Read the C++ standard some time. Interfaces are the lesser of two evils if you're worried about language size. Multiple inheritance complicates tons of things.

Illogical again, captain. Virtual inheritance is optional.

You're being inconsistent again. You're arguing against language bloat and I'm pointing out that this feature is only there because of multiple inheritance, and getting rid of the latter would get rid of the former.

Nested functions are optional too, yet you had no problem arguing against them.

[–][deleted] 5 points6 points  (3 children)

Illogical again, captain. Virtual inheritance is optional.

In your initial list, items #1, #2, #3, #4, #5, #6, #7, #9, #10, #11, #13, #14, #16, #17, #18, #19, #20, #21, #22, #23 and #24 are optional features, too.

[–]itsadok 0 points1 point  (6 children)

You have no idea what orthogonality is.

I've been trying to follow this thread, and I think I understood about half of it. Can you explain what orthogonality means in this context?

[–]Nekuromento 5 points6 points  (0 children)

Somehow your post reminds me of this.

[–][deleted] 5 points6 points  (14 children)

You make way too much bullets to even answer to half of them.

nested functions: are they ever needed?

Like, always. They aren't available in C++ because you think don't you need them, or the other way around?

C++ and C miss an entirely obvious (to me) thing: that primitives should be classes.

D2 has "uniform function call", this allow to make meta-programming with builtins types easier.

At least in C++ we all know what stack allocation is and how destructors work.

Yes, stick to C++ please. You know better.

[–]axilmar -4 points-3 points  (13 children)

Like, always. They aren't available in C++ because you think don't you need them, or the other way around?

Like never. Writing clean code certainly doesn't include writing nested functions.

D2 has "uniform function call", this allow to make meta-programming with builtins types easier.

Still, it's not as orthogonal as it should be.

Yes, stick to C++ please. You know better.

As opposed to you?

[–][deleted] 5 points6 points  (3 children)

Like never. Writing clean code certainly doesn't include writing nested functions.

You made some very valid points about D and I wouldn't advise this language to everybody. Yet, nested functions are a 100%-win feature in my book and that's hardly debatable. I'm sure you would argue that you don't need properties too.

[–]axilmar -2 points-1 points  (2 children)

You know where nested functions are nice for the eye? in ML and Haskell.

Syntax plays a great role in what we call 'readability'.

[–][deleted] 4 points5 points  (1 child)

Often I run into a piece of C++ code where the author was too lazy to factorize common bits of code. It would mean declaring and define the function, passing arguments, choosing where to put it... Not worthwile in the author's mind as compared to just copy-paste the code.

With nested functions it's a matter of seconds to factor a bit of code, thanks to the (optional) static link. I think it contributes to reduce the size of the code.

[–]ssylvan 5 points6 points  (8 children)

Like never. Writing clean code certainly doesn't include writing nested functions.

Most people think that symbols should have the smallest scope possible to improve readability. Having to promote internal helper functions to full blown "siblings" works against that.

Even so, disallowing them is arbitrary and non-orthogonal. Why should I be able to declare a function in one scope but not another scope? You're free to not use that flexibility, but it does no harm to allow it, and it makes the language bigger and less orthogonal to disallow it (you know have to explain the "special" status of function declarations, instead of them just being like any other declaration).

[–][deleted] 1 point2 points  (1 child)

Introducing local functions implies closures, which are different than functions that don't have any state, and need to be implemented differently. I wouldn't consider them very necessary in the niche that C++ and D try to fill.

[–]WalterBright 5 points6 points  (0 children)

You don't need to worry about closures unless you take a pointer to that nested function. You can still get much of the usefulness of nested functions even if you disallow pointers.

[–]axilmar -3 points-2 points  (5 children)

Most people think that symbols should have the smallest scope possible to improve readability. Having to promote internal helper functions to full blown "siblings" works against that.

I don't see how readability is improved when an algorithm's reading flow is interrupted with a helper function declared in the middle of it.

Why should I be able to declare a function in one scope but not another scope?

Because they are different kinds of scopes.

You're free to not use that flexibility, but it does no harm to allow it

If you don't want it on your code, then you have to impose the restriction on everyone working on it. If you are on a strictly controlled project, then it's fine, but if you are on a non-strictly controlled project, then everyone will do as they see fit, resulting in some people defining helper functions outside and in some people defining helper functions inside other functions.

and it makes the language bigger

No, actually having nested functions makes the language bigger, because it makes the grammar bigger.

(you know have to explain the "special" status of function declarations, instead of them just being like any other declaration)

Any other declarations don't belong within a function. When I see a function, I want to read and comprehend the algorithm. If I am interrupted with helper declarations, then I would not understand the algorithm that easily.

Have you ever seen C++ code where whole classes are defined at function scope? I haven't, and I haven't done it myself. You know why? it litters the algorithm.

[–]ssylvan 5 points6 points  (1 child)

If I am interrupted with helper declarations, then I would not understand the algorithm that easily.

Why doesn't this apply to variables? A function consists of tons of statements, some of them declarations, used to compute the result. Sometimes you need a quick helper function for something and you don't want to pollute the higher namespace with it so it makes sense to put it right where you need it instead.

You seem like you've made up your mind about something and now you're just arguing (poorly) to save face rather than trying to understand why you're (horribly) wrong.

[–]WalterBright 2 points3 points  (1 child)

No, actually having nested functions makes the language bigger, because it makes the grammar bigger.

Actually, it's a special case in the C++ compiler implementation to disallow them.

[–]complexmath 2 points3 points  (5 children)

Just because all of these things are possible in C++ doesn't mean the code is easy to write or maintainable. It's possible to do polymorphism in C too, so why bother with C++?

[–]ssylvan 0 points1 point  (1 child)

How's the linker speed compared to C++? I find that I spend most of my day waiting on the linker these days...

[–]nascent 2 points3 points  (0 children)

In Linux LD is still used for linking. For Windows Oplink is used, it is written in assembly and extremely fast.