May 11, 2008
BCS Wrote:

> Reply to Dee,
> 
> > Yigal Chripun Wrote:
> > 
> >> Dee Girl wrote:
> >> 
> >>> I agree! Strings and aliases are much less powerful than delegates
> >>> and closures because they are static and can not have state.
> >>> But I am confused about something. I compiled this with phobos:
> >>> sort!(function bool(int a, int b) { return a > b; })(array);
> >>> 
> >>> There is clear difference in syntax from your examples. But my question is: what are the differences in semantics? Thank you, Dee Girl
> >>> 
> >> I'm not sure what exactly are you asking. are you asking what's the difference between a delegate and a function?
> >> 
> > Please let me rephrase. What is the difference between a function passed as an alias, and a delegate? You hate one and you like the other so the difference must be big. But I do not find it. Thank you, Dee Girl
> > 
> 
> a function is just a free function or a static class function or the like. A delegate is both a function and a context. Generally the context is another function's scope or an object or struct.

Sorry I do not know how to express myself. It is frustrating ^_^.

I understand what a function is. But it looks to me as when a function is passed to a template weird things happen. I have compiled and run successfully this program:

#!/home/yasuko/bin/compile-launch -w
import std.stdio;
import std.algorithm;

void main()
{
    int[] array = [ 1, 2, 3, 4 ];
    int x = 5;
    bool comp(int a, int b) { return a + x > b + x; }
    sort!(comp)(array);
    writeln(array);
    sort(array);
    writeln(array);
    test(&comp);
    writeln(array);
}

void test(bool delegate(int, int) dg)
{
    int[] array = [ 1, 2, 3, 4 ];
    sort!(dg)(array);
}

There are many interesting things about above program. Function comp accesses a variable in its enclosing scope therefore it can not be a "simple" function. However sort works with it.

Then even more interesting. I pass the function as a delegate to another function. Here sort works again even when passed the delegate! So I see no difference between passing the delegate as a template alias or as a normal parameter. But I do not understand how the compiler can generate the code for the dynamic case. Dee Girl

May 11, 2008
Your example does use delegates.
the difference is this:
say you have two delegates you pass to sort, for example you sort one
array in ascending order, and another in descending order. the template
solution will generate two almost identical sort functions with the only
difference that one sort instance calls internally the first delegate,
and the second instance calls the second. you get 4 functions. without
the template, you get one sort function and two delegates, so only 3
functions.
Now, when you use a string with the template, the sort will contain the
code itself inline to the sort instance so it "saves" you a function
call. IMO, the string solution is not clean ( C MACROs? )and while for
simple cases it could save you a function call it's premature
optimization IMO. Also, if I use delegates, I can't see how a template
can save that function call. so it just bloats my executable with
unneeded copies of sort.
I hate when library code forces me to this. I think the programmer knows
his code better than the library writer and should be able to choose
himself whether he needs to use a compile time solution to save function
calls or a run-time solution to prevent unnecessary executable bloat.
this optimization should be made by the programmer and _not_ the library
writer. This solution does not give me that freedom.
this solution is a classic STL piece of code, BUT, the main difference
is that for C++ this is probably the only reasonable solution as C++
doesn't have delegates. this is why when coding for D I urge people to
rethink their solution instead of just doing what is best in C++ (or any
other preferred language of the library writer). This is a prime example
why the C++ solution is wrong for D.

--Yigal
May 11, 2008
On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>  BUT, the main difference
>  is that for C++ this is probably the only reasonable solution as C++
>  doesn't have delegates.

C++ has functors (classes which overload operator ()), and they're a
bit like delgates. What C++ doesn't have is alias template parameters,
nor string template parameters.

    sort!("a.member > b.member")(array)

simply couldn't be done in C++. This is /not/ a C++ solution. It's a D solution, and a fantastically brilliant one.

Perhaps what you mean when you say "C++ solution", is, "it uses templates"?
May 11, 2008
On Sun, 11 May 2008 13:18:33 +0400, Janice Caron <caron800@googlemail.com> wrote:

> sort!("a.member > b.member")(array)

I like this one, too. It's very simple, efficent and clean.
May 11, 2008
Janice Caron wrote:
> On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>>  BUT, the main difference
>>  is that for C++ this is probably the only reasonable solution as C++
>>  doesn't have delegates.
> 
> C++ has functors (classes which overload operator ()), and they're a
> bit like delgates. What C++ doesn't have is alias template parameters,
> nor string template parameters.
> 
>     sort!("a.member > b.member")(array)
> 
> simply couldn't be done in C++. This is /not/ a C++ solution. It's a D solution, and a fantastically brilliant one.
> 
> Perhaps what you mean when you say "C++ solution", is, "it uses templates"?

it mis-uses templates, as I said in my previous post. it's the same C++ mind set. the only difference is that it utilizes more D++ features to accomplish the same thing.

Personally, I prefer a smalltalk like collections framework over the c++ generic templates solution. it makes so much more sense to me to have a orderedCollection interface which defines a sort method, than a c++ generic sort template.

It makes more sense to me to write:
array.sort(); or array.sort(aDelegate);
instead of using:
sort(array); or sort(array, aDelegate); or even worse:
sort!(aDelegate)(array);

C++ avoids using real OOP encapsulation since it perceives it as adding unnecessary overhead. this is plain wrong since the overhead is orthogonal to the design principles. This is why C++ is adding the notion of concepts (which facilitate compile time OOP) to the next standard.

--Yigal
May 11, 2008
Koroskin Denis wrote:
> On Sun, 11 May 2008 13:18:33 +0400, Janice Caron <caron800@googlemail.com> wrote:
> 
>> sort!("a.member > b.member")(array)
> 
> I like this one, too. It's very simple, efficent and clean.

In what way is that clean? How is that different from a C macro?
if you have a typo: "a.member > b.membr" the compiler won't check it at
the place you wrote it, since it's just a string. the compiler will
probably complain about the library code instead. (I haven't tried that
on actual code, though).
Now there is a way to tell the compiler to validate the content of
strings with q"here goes a valid D code snippet" (if i remember
correctly), but that requires me to not forget that q.
all in all, all those string manipulations, although powerful, are quite
dangerous, IMO.
also, what if a doesn't actually have a "member" member? this is still
syntactically valid D code, but again I think the error would be
reported elsewhere.

--Yigal
May 11, 2008
Janice Caron Wrote:

>     sort!("a.member > b.member")(array)
> 
> simply couldn't be done in C++. This is /not/ a C++ solution. It's a D solution, and a fantastically brilliant one.

does it have any use?
Maybe implementing LINQ will be much more powerful and readable?
May 11, 2008
On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>  Personally, I prefer <snip>

By your own words, that's just a personal preference.


>  It makes more sense to me to write:
>  array.sort(); or array.sort(aDelegate);
>  instead of using:
>  sort(array); or sort(array, aDelegate); or even worse:
>  sort!(aDelegate)(array);

But now you're just saying "my syntax is better than your syntax", when both do the same thing. In addition, the D version is more powerful, as it allows you to say:

    sort!(f)(array)

where f is a function (not a delegate). It also allows you to write

    sort!(dg, SwapStrategy.stable)(array)

to get a stable sort instead of a non-stable (but faster) sort. This kind of flexibility offers way more power than delegates alone. Besides which, arrays cannot implement an orderedCollection interface, because arrays cannot implement interfaces, so you'd be limited only to sorting custom collection classes.


>  This is why C++ is adding the
>  notion of concepts (which facilitate compile time OOP)

So is D. Shall we take bets on which language gets them first, or in which language they will be most powerful?
May 11, 2008
On 11/05/2008, Yigal Chripun <yigal100@gmail.com> wrote:
>  also, what if a doesn't actually have a "member" member? this is still
>  syntactically valid D code, but again I think the error would be
>  reported elsewhere.

On that point, I concede. The reporting of template errors could certainly be improved. More than once I have wanted to see the "stack trace" of errors, working back from the innermost, to the line of code that ultimately triggered it.

However, that it not an argument against templates, it is an argument for improved error reporting. And hopefully, one day we'll get that.

This is not the first time that you've argued that some feature or strategy is bad because today's D compiler isn't good enough, but you need to remember that tomorrow's D compiler will be better. That's life on the cutting edge.
May 11, 2008
On Sat, 10 May 2008 07:59:23 +0200, Janice Caron <caron800@googlemail.com> wrote:
> 1) convert or downcast: cast(Foo)bar
> 2) reinterpret: cast!(Foo)bar
> 3) constancy: cast(invariant)bar, cast(!const)bar

For 3), what if I want to cast const(int*) to const(int)*? cast(const(int)*)cast(!const)foo?

-- Simen