To me, the first big failure of D to implement functional style
is to not have first class functions. You get a function using
& operator. But does it really make sense ? See code below :
void foo(){}
void bar(void function() buzz) {}
void main() { bar(foo); } // This will execute foo, and so
fail. Functions are not first class objects.
void main() {
auto bar = &foo;
foo(); // Do something.
bar(); // Do the same thing.
auto buzz = &bar;
(*buzz)(); // Do the same thing.
}
Functions don't behave the same way is they are variables or
declared in the source code.
Worse, foo was before a function call. Now it isn't anymore.
foo, as a expression have a different meaning depending on what
is done on it. It would become very confusing if foo return a
reference, so it is an lvalue and & is a valid operation on the
function call.
As D don't enforce purity like functional programing does, it
can't be up to the compiler to decide when does the function
get executed.
Then come UFCS. UFCS allow for function calls with parameters.
It is still inconsistent.
void foo(T)(T t) {}
a.foo; // foo is called with a as argument.
&a.foo; // error : not an lvalue
Now let imagine that foo is a member function of a, &a.foo
become a delegate. a.foo is still a function call. This is
still quite inconsistent.
Implementing all this is almost impossible when you add
@property into the already messy situation. Additionally, the
current implement fails to provide the basics of functional
programing, and break several abstraction provided by other
languages features. C++ has proven that bad association of good
language features lead to serious problems.
This require to be formalized in some way and not based on
dmd's implementation. Inevitably, the process will lead to code
breakage (adding or removing some ()/&).
Reading the @property thread, it seems that most people want to
keep dmd's current behavior. Because code rely on it. This make
sense, but if dmd's implement is the only goal, it means that
other compiler are only to be reverse engineering dmd's
behavior, and are guaranteed to lag behind. Considering this, I
seriously wonder if it make sense to even try to follow dmd's
behavior and decide whatever seems the right one when writing a
D compiler, which will result in community split, or no
alternative compiler produced for D.
I also have some proposal to fix thing, even some that would
allow a.map!(...).array() to still be available. But
inevitably, some other construct will broke. At this point,
what matter isn't really what solution is adopted, but do we
still want to be dependent on dmd implementation for D features.
I'm not sure if I understand your point perfectly, but I
definitely feel that the way D handles optional parens is awful.
The other day I noticed that the following is a syntax error (DMD
2.059):
class A { void B() {} }
auto a = new A().B();
// ^ semicolon expected following auto declaration, not '.'
Even without silly errors like this, optional parenthesis create
ambiguities, and ambiguities are bad. Maybe there is a sane way
for parenthesis to be optional, but the way I've seen D behaving
is *bizarre*.
The compiler should *expect* parenthesis, and only assume that
the parenthesis are missing if it's the only way to compile
without an immediate error. So for example,
- if foo is a non-@property function that returns another
function, foo() must invoke foo itself and never the function
that foo returns.
- if I say "&foo" where foo is a non-@property function, it
should always take the address of the function, never take the
address of the return value.
- The rules shouldn't change if you replace "foo" with a complex
expression like "x.y[z]" or "new Module.ClassName".