August 22, 2006
Walter Bright wrote:

> I've been thinking a lot about the escape problem. I'm pretty sure that:
>     char[] delegate() { return "foo"; }
> can be detected and so I can assure you it won't cause the enclosing function's variables to be allocated on the heap.

And what about those cases where the expression is somewhat more complex? Will you revert all this ambiguity when a bogus heap-frame is demonstrated? One where the intent was never to create a delegate, but simply to evaluate an argument expr instead? Or will you insist that a smarter detector is the solution?

One has to suspect that there are far more productive ways to take risks with a language than this one:

# somefunk (++i);
#
# vs
#
# somefunk ({++i});

the latter is not only unambiguous, it even /looks/ like a delegate. The former? Who knows what it does anymore
August 22, 2006
Walter Bright wrote:
> kris wrote:
> 
>> So, we have some existing code for logging. Very efficient, and highly flexible. It follows the design patterns popularized by Log4J, with Appenders, Layouts, etc
>>
>> The D version of a logger has five 'levels' of logging:
>>
>> log.trace (char[])
>> log.info (char[])
>> log.warn (char[])
>> log.error (char[])
>> log.fatal (char[])
>>
>> and the intent (with dmd.164) was to add these flavours, specifically to address the point Walter makes about unnecessary message construction:
>>
>> log.trace (char[] delegate() dg)
>> log.info (char[] delegate() dg)
>> log.warn (char[] delegate() dg)
>> log.error (char[] delegate() dg)
>> log.fatal (char[] delegate() dg)
>>
>> The support code was installed fairly recently, and the above delegate-wrappers were on the todo list.
>>
>> However, dmd.165 will presumeably not compile this code?
> 
> 
> Correct.
> 
>> Won't there be an overload ambiguity?
> 
> 
> Yes.
> 
>> If so, it illustrates a serious shortcoming in the new syntax
> 
> 
> Just get rid of the (char[]) versions.


Can't do that; the char[] version have to stay.
August 22, 2006
kris wrote:
> Walter Bright wrote:
>> kris wrote:
>>
>>> So, we have some existing code for logging. Very efficient, and highly flexible. It follows the design patterns popularized by Log4J, with Appenders, Layouts, etc
>>>
>>> The D version of a logger has five 'levels' of logging:
>>>
>>> log.trace (char[])
>>> log.info (char[])
>>> log.warn (char[])
>>> log.error (char[])
>>> log.fatal (char[])
>>>
>>> and the intent (with dmd.164) was to add these flavours, specifically to address the point Walter makes about unnecessary message construction:
>>>
>>> log.trace (char[] delegate() dg)
>>> log.info (char[] delegate() dg)
>>> log.warn (char[] delegate() dg)
>>> log.error (char[] delegate() dg)
>>> log.fatal (char[] delegate() dg)
>>>
>>> The support code was installed fairly recently, and the above delegate-wrappers were on the todo list.
>>>
>>> However, dmd.165 will presumeably not compile this code?
>>
>>
>> Correct.
>>
>>> Won't there be an overload ambiguity?
>>
>>
>> Yes.
>>
>>> If so, it illustrates a serious shortcoming in the new syntax
>>
>>
>> Just get rid of the (char[]) versions.
> 
> 
> Can't do that; the char[] version have to stay.

This may not be a very clean solution, but you could make them templates, using ifti. (If that only worked for member functions...)

trace(T)(T str) {...}

Then

trace("string");

will not be called lazily, while

trace({return "string";});

will.

/Oskar
August 22, 2006
Walter Bright wrote:
> 
> 3) It is possible that the delegate can be inlined, thus eliminating any extra overhead.

Really?  Are you saying that if the receiving function is short enough the function and its delegate use may be inlined in the calling code?  I can't imagine that it would simply be inlined in the receiving function and duplicates of that wold be generated.  Or at least, DMD doesn't appear to do that now.


Sean
August 22, 2006
Walter Bright wrote:
> 
> I've struggled to get people to accept the {} version ever since D adopted anonymous delegates. Haven't made much headway in getting such used or in it having any sort of significant impact. How many have made a "dotimes(n, exp)" function or any sort of syntax extension using it? None that I've seen.

I've been working on a predicate-oriented algorithm module on and off for the past few weeks.  A few looping constructs have been left out because foreach seems a preferable solution in D, but the rest is coming along nicely.  About the only problem I had was inlining delegates passed to the functions, so the default operations are passed as structs with opCall defined instead.

> I hesitate to use argumentum ad verecundiam because it's a logical fallacy, so you can take the following for what it's worth. Andrei and I certainly have our differences of opinion. But when I disagree with him, I'd better have done my homework, or I'll get cut to pieces. He thinks (and he obviously convinced me) that removing the { } makes all the difference.

I'll admit that doing so makes a difference to me, as it allows for tricks that aren't possible with explicit delegate signifiers.  But I'm undecided as to whether this is a "good thing" or not--I plan to give it some time before I decide.  I do think it's unfortunate that Kris' logging code will be unable to accept both string and delegate parameters however.  And I'd like to note that all the tricks I'm thinking of for the new syntax tend to involve refactoring existing code (which is potentially dangerous, given the issue with side-effects) rather than writing new code.  With new code I don't see much benefit to omitting all evidence that a parameter will be converted to a delegate, as it's something the user must be aware of to write correct code.


Sean
August 22, 2006
Walter Bright wrote:
> Derek Parnell wrote:
>> On Mon, 21 Aug 2006 19:41:24 -0700, Walter Bright wrote:
>>
>>> Derek Parnell wrote:
>>>
>>> C++ programmers have been trying to do this for over a decade - first with preprocessor macros, and now with expression templates.
>> And do I give a toss about C++ programming foibles ;-)
> 
> LOL! But expression templates, horrible hack that they are, are often listed as the reason C++ is so powerful and therefore why should one change? Expression templates are how C++ does "domain specific languages" and David Abraham explains them to packed conference rooms. So I believe there is a serious demand for them, but not the way C++ does it, as probably only 5 people on the planet are able to create a DNS using them.

In my limited experience, the attendees of those conferences are what I'd consider "typical" C++ programmers--they tend to use a fairly limited subset of the language's features and their code probably looks like what was popular maybe 15 years ago.  Templates are a fairly new thing to many of them, and many are even just getting their feet wet with the STL.  I would guess that Dave's presentation on expression templates draws a crowd for a few simple reasons: people have heard of Dave because he's written a book and is the front man for Boost in many respects, and because expression templates have a high "gee whiz" factor.  I think that people simply interested in learning how to write expression templates would go out and buy a copy of "C++ Templates: The Complete Guide" by D. Vandevoorde and N. Josuttis and probably not bother with the lecture at all.

> With the lazy evaluation thing, though, writing DNSs becomes simple and straightforward, which may (just may) catapult D forward like defmac rescued Lisp from oblivion.

It was simple and straightforward using the previous syntax as well. Though I'll grant that the "return" bit took up a bit of horizontal screen real estate that some might not find appealing.

> Suppose there's an API function:
> 
>     void anotherFunc(int x);
> 
> which I call:
> 
>     int y = 3;
>     anotherFunc(y);
>     writefln(y);
> 
> then the library writer changes the API to:
> 
>     void anotherFunc(inout int x);
> 
> and internally increments x. I'm left wondering why 4 is now being printed instead of 3.

But that would be a blatant change in behavior for the API function, while converting to a delegate parameter is arguably not a change in behavior, just in the way the value is being transferred.  It's probably also worth noting that in a language supporting const features, switching an in param to inout would probably result in compile errors in at least a few uses of the function.

That aside, it may be worth noting that this new delegate syntax has some small potential for faking const behavior in D, though it would likely make a mess of code attempting this.


Sean
August 22, 2006
Unknown W. Brackets wrote:
> Well, if I saw:
> 
> auto new_p = coalesce(p, last_p, new P())
> 
> I would not assume that new P() would be evaluated, unless p and last_p were null.
> 
> The same goes for a lot of macro function usage seen with the C preprocessor.  People are already dealing with this problem.  A lot.
> 
> I like this new feature, and would hate having to type the curlies.  I feel confident I can correctly document my functions and name them such that no one would be confused.
> 

I feel confident I can document all sorts of bazaar things in my own code. I also feel confident that if they are allowed/promoted then other people will use them and *NOT* document them.

As to others using your/my code, you can put a page and a half of documentation in warning about side effects and it wont do one wit of good if the other guy doesn't read it. And there is no way to ensure that it will get read.

I can just see the buzz now: "Did you hear about the bonehead over in XYZ department that messed up the billing program? He didn't read all of the comments in the new library and ended up costing the cooperation $n million dollars because of this "cool" feature in the D programming language. I'll never use a D lib in /my/ work."
August 22, 2006
> I feel confident I can document all sorts of bazaar things in my own code. I also feel confident that if they are allowed/promoted then other people will use them and *NOT* document them.
> 
> As to others using your/my code, you can put a page and a half of documentation in warning about side effects and it wont do one wit of good if the other guy doesn't read it. And there is no way to ensure that it will get read.
> 
> I can just see the buzz now: "Did you hear about the bonehead over in XYZ department that messed up the billing program? He didn't read all of the comments in the new library and ended up costing the cooperation $n million dollars because of this "cool" feature in the D programming language. I'll never use a D lib in /my/ work."

Well said.

Go for non-implicit delegates.
August 22, 2006
Walter Bright wrote:
> 
> Changing an API and thereby breaking (obviously or subtly) the user code is as old as programming ("DLL hell" is a term probably older than many programmers!). The only answer I can think of is, if you must change the API of a function, and you have legacy users of it, give the changed one a new name and tag the old name with 'deprecated'.

The problem isn't that changing things, breaks stuff. It it that going from (T) to (T delegate()) is almost always valid, but the programmer can *never* assume that it is.

Thinking of it that way, changing the API from one to the other is *never* safe. This means that using a T delegate() as a parameter might as well be considered an unsafe practice. If you started with just T, your locked in for all time. Starting with T delegate() is almost as bad.

Having a feature that is nearly impossible to use safely may well be worse than not having the feature.
August 22, 2006
Other people already proposed the { expr } syntax, I liked it too, can't we think of it like this ...


We usually write compound statement as:

{
  statement1;
  statement2;
  return expr;
}

We can ignore ';' if there is only statement, so following is valid:

{
  statement
}

{
  return expr
}

If there is only a return statement, and the return type of the delegate matches the expression, we can make the 'return' keyword optional:

{
  expr
}


well ... what do you all say ?
(hope Walter likes this)
Sai