On Monday, 6 August 2012 at 16:40:02 UTC, deadalnix wrote:
It is known that some part of D are very dmd's implementation
defined. One of the part is manipulation function as first
class objects and implicitly calling them.
...
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.
}
This comes from the 'real' function type is 'void f()' whose
usage is deprecated in D except for any
function-/method-declaration:
Imagine a C-style declaration of the fuction type and you'll come
to the conclusion it's the way one defines functions in C/C++/D.
But this type has a big quirk: it's variable length because
different fuctions with the same signature can have a different
amount of machine instuctions. Therefore this can't be stored,
passed or returned. You can't have array of them. The only
exception is when you define a constant, then it's a funciton
definition. Now because of this there is a need for another type
equivalent to the function itself: its address. It's written
'void (*f)()' in C. This type is mostly reffered to as function
even though it's only its address. Now D wants to go away from C
declarations so the 'void function()' syntax was invented.
Regardless of its name it's only the pointer to the actual
functions even though D allows you to call it without
dereferencing.
Functions don't behave the same way is they are variables or
declared in the source code.
This is because the former a function pointer and the latter are
actual funtions.
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.
Because any usage of a function except a call or address-taking
are complete non-sense, the functions is implicitly called if it
hasn't got any parameters.
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
Even though it's written like that, the function is not called
with the member calling convention. You can't create a
transperent delegate of it because the function does not expect
to get 'a' as a 'this'-parameter.
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.
Maybe it is. But it comes from the fact that ufcs is an
afterthought.
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 don't like authorative formal specs. It means most things are
set in stone and you have to write a new spec every once in a
while which slows down development of awesome language features.
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.
Mafi