Functional programming in D and some reflexion on the () optionality.

Mafi mafi at example.org
Mon Aug 6 11:01:23 PDT 2012


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




More information about the Digitalmars-d mailing list