October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> Sean Kelly wrote:
>> Andrei Alexandrescu wrote:
>>> I believe the clear distinction is not only unnecessary, but undesirable. We should actively fight against it.
>>
>> Why is it undesirable? I like the idea of static parameters as described at the conference last year, but I don't think that has any bearing on this particular issue.
>
> Time and again, both Walter and myself have met people who experience a mental block whenever templates come within a mile. The fact that they come with the sign Here! This! Is! A! Template! doesn't help any.
Are we discussing better template syntax of a magical injection that will cure the common fear of template code? ;-)
|
October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> KennyTM~ wrote:
>> Andrei Alexandrescu wrote:
>>> Michel Fortin wrote:
>>>> On 2008-10-05 01:14:17 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
>>>>
>>>> -- snip --
>>>>
>>>> Or we could use special delimiter characters:
>>>>
>>>> Positive<real>(joke);
>>>> Positive“real”(joke);
>>>> Positive«real»(joke);
>>>> Positive#real@(joke);
>>>>
>>>> Each having its own problem though.
>>>>
>>>> My preference still goes to "!(".
>>>
>>> There was also Positive{real}(joke), with which I couldn't find an ambiguity.
>> >
>>
>> Ohhhh. Why isn't it considered then? (Suppose we already knew Positive is not a keyword and not preceded by the keywords struct, class, etc.)
>
> I believe it should be considered. At some point there was discussion on accepting a last parameter of delegate type outside the function parens. The idea was to allow user-defined code to define constructs similar to e.g. if and foreach.
>
> But I think that has many other problems (one of which is that the delegate can't reasonably specify parameters), so we can safely discount that as a problem.
>
> I'd want to give it a try. How do others feel about Template{arguments}?
I distrust it greatly. Too similar to a code block.
I still have a lot of contact with kids still being educated in programming, and that'd probably just confuse the heck out of 'em.
No on {}! Keep the code block sacred! ;-)
|
October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris R. Miller | On Sun, Oct 5, 2008 at 8:57 PM, Chris R. Miller <lordsauronthegreat@gmail.com> wrote:
>
> The !() syntax seems to serve only as a heads up that it's a template.
> Otherwise (as far as I can tell) a simple foo(int)(bar, baaz) would work
> just as well as foo!(int)(bar, baaz).
>
Unambiguous grammar, you fail it.
foo(bar)(baz); // template instantiation or a chained call?
This _can_ be _made_ to work, but it would mean that the parse tree would be dependent upon semantic analysis, and that just makes things slow and awful. I.e. C++.
|
October 06, 2008 Re: Positive | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Mon, 06 Oct 2008 00:55:33 +0100, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: >>> >>> Andrei >> I disagree. I'm not saying its easy but it could be done. We would have to start >> with something relatively simple and work our way up but it could be done. > > I, too, think it can be done in the same way supersonic mass > transportation can be done, but having done research in the area I can > tell you you are grossly underestimating the difficulties. It is a > project of gargantuan size. Today the most advanced systems only managed > to automatically prove facts that look rather trivial to the casual > reader. There is absolutely no hope for D to embark on this. > I'm not asking for a generalised theorem prover. Something to handle even the simple cases is a start. I agree that D won't have this (any time soon) but mainly because there are several hundred things higher up the priority list. >> Compiler's already do all kinds of clever analyses behind the scenes but each one >> is often hard coded. I suspect the main difficulty is giving users too much rope >> by which to hang themselves, or rather hang the compiler trying to prove something >> it doesn't realise it can't. Marrying declarative / constraint based programming >> at compile time is creeping in via templates. I wish it was less well hidden. > > I discussed the problem this morning with Walter and he also started > rather cocky: if you assert something early on, you can from then on > assume the assertion is true (assuming no assignment took place, which > is not hard if you have CFA in place). He got an arrow in a molar with > the following example: > > double[] vec; > foreach (e; vec) assert(e >= 0); > // now we know vec is all nonnegatives > normalize(vec); > > The definition of normalize is: > > void normalize(double[] vec) > { > foreach (e; vec) assert(e >= 0); > auto sum = reduce@"a + b"(vec, 0); > assert(sum > 0); > foreach (ref e; vec) e /= sum; > } > > If normalize takes udouble[] and you have one of those, there's no need to recheck. Automated elimination of the checking loop above is really hard. > > > Andrei Is it? I think your example needs to be expanded or we may be talking at cross purposes. Firstly I would rearrange things a little, though in principle it makes no difference. pre { static assert(foreach (e; vec) assert(e >= 0)); } void normalize(double[] vec) { auto sum = reduce@"a + b"(vec, 0); assert(sum > 0); foreach (ref e; vec) e /= sum; } double[] vec; static assert(foreach (e; vec) assert(e >= 0)); // line X // now we know vec is all nonnegatives normalize(vec); // line Y Imagine I have a prolog style symbolic unification engine to hand inside my compiler. At line X the static assertion is evaluated. The logical property e>=0 is asserted on the vec symbol. The compiler reaches line Y. Vec has not been modified so still has this property associated with it. We now unify the symbol representing vec with the contract on normalise. The unification succeeds and everything is fine. Now imagine we have a stupid analyser. double[] vec; static assert(foreach (e; vec) assert(e >= 0)); // line X vec[0] -= 1; // line Z // now we know vec is all nonnegatives normalize(vec); // line Y when the compile time analyser reaches line Z it can't work out whether or not the contract still applies, so it removes the assertion that vec is e>=0 for all elements, or rather asserts that it is not provably true. Now when we reach Y the unification fails. We don't throw a compile time contraint violation error. We haven't proved it to have failed. We throw a compile time constraint unprovable error or warning. Its like a lint warning. Your code may not be wrong but you might want to consider altering it in a way that makes it provably correct. We would really like to be able to assert that certain properties always hold for a variable through its life-time. That is a harder problem. I see something like this as a basis on which more advanced analysis can be built gradually. Actually re-using static assert above was probably misleading. It would be better to have something that says talk to the compile time theorem prover (a prolog interpreter would do). I have been meaning to write something along these lines for years but so far I haven't got around to it so I might as well stop keeping it under my hat. Regards, Bruce. |
October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris R. Miller | On 2008-10-05 20:57:31 -0400, "Chris R. Miller" <lordsauronthegreat@gmail.com> said: > The !() syntax seems to serve only as a heads up that it's a template. Otherwise (as far as I can tell) a simple foo(int)(bar, baaz) would work just as well as foo!(int)(bar, baaz). Well, not so sure about that: I'm pretty sure it's needed for disambiguation too. Let's say you have: void foo(int x)(); void foo(T)(T x); foo(5); Is foo(5) a the same as foo!(5), or does it call foo!(int).foo(5) ? Under the current rules, it's the second (you can write foo!(5) to call the first). If you allow templates to be instanciated without the "!", then I guess both will match and you'll have ambiguity. If you could avoid having sets of parameters, one for the function and one for the template, then you could get rid of the "!" in a snap... Well, maybe not. You'll still have to resolve the same issues for constructors: class A(int x) { this() {} } class A() { this(int x) {} } auto a = new A(5); Perhaps this is not a problem however: the only two valid ways to create an instance of one or the other are "new A!(5)" or "new A!()(5)", which would translate in non-"!" syntax as: "new A(5)" and "new A()(5)". Unfortunately, we don't have this "luck" with functions. -- Michel Fortin michel.fortin@michelf.com http://michelf.com/ |
October 06, 2008 Re: Positive | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams wrote:
> On Mon, 06 Oct 2008 00:55:33 +0100, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>>>>
>>>> Andrei
>>> I disagree. I'm not saying its easy but it could be done. We would have to start
>>> with something relatively simple and work our way up but it could be done.
>>
>> I, too, think it can be done in the same way supersonic mass
>> transportation can be done, but having done research in the area I can
>> tell you you are grossly underestimating the difficulties. It is a
>> project of gargantuan size. Today the most advanced systems only managed
>> to automatically prove facts that look rather trivial to the casual
>> reader. There is absolutely no hope for D to embark on this.
>>
> I'm not asking for a generalised theorem prover. Something to handle even the
> simple cases is a start.
> I agree that D won't have this (any time soon) but mainly because there
> are several hundred things higher up the priority list.
>
>>> Compiler's already do all kinds of clever analyses behind the scenes but each one
>>> is often hard coded. I suspect the main difficulty is giving users too much rope
>>> by which to hang themselves, or rather hang the compiler trying to prove something
>>> it doesn't realise it can't. Marrying declarative / constraint based programming
>>> at compile time is creeping in via templates. I wish it was less well hidden.
>>
>> I discussed the problem this morning with Walter and he also started
>> rather cocky: if you assert something early on, you can from then on
>> assume the assertion is true (assuming no assignment took place, which
>> is not hard if you have CFA in place). He got an arrow in a molar with
>> the following example:
>>
>> double[] vec;
>> foreach (e; vec) assert(e >= 0);
>> // now we know vec is all nonnegatives
>> normalize(vec);
>>
>> The definition of normalize is:
>>
>> void normalize(double[] vec)
>> {
>> foreach (e; vec) assert(e >= 0);
>> auto sum = reduce@"a + b"(vec, 0);
>> assert(sum > 0);
>> foreach (ref e; vec) e /= sum;
>> }
>>
>> If normalize takes udouble[] and you have one of those, there's no need to recheck. Automated elimination of the checking loop above is really hard.
>>
>>
>> Andrei
>
> Is it? I think your example needs to be expanded or we may be talking
> at cross purposes.
> Firstly I would rearrange things a little, though in principle it makes
> no difference.
>
> pre
> {
> static assert(foreach (e; vec) assert(e >= 0));
> }
> void normalize(double[] vec)
> {
> auto sum = reduce@"a + b"(vec, 0);
> assert(sum > 0);
> foreach (ref e; vec) e /= sum;
> }
>
> double[] vec;
> static assert(foreach (e; vec) assert(e >= 0)); // line X
>
> // now we know vec is all nonnegatives
> normalize(vec); // line Y
>
> Imagine I have a prolog style symbolic unification engine to hand inside my compiler.
>
> At line X the static assertion is evaluated.
> The logical property e>=0 is asserted on the vec symbol.
> The compiler reaches line Y.
> Vec has not been modified so still has this property associated with it.
> We now unify the symbol representing vec with the contract on normalise.
> The unification succeeds and everything is fine.
>
> Now imagine we have a stupid analyser.
>
> double[] vec;
> static assert(foreach (e; vec) assert(e >= 0)); // line X
>
> vec[0] -= 1; // line Z
>
> // now we know vec is all nonnegatives
> normalize(vec); // line Y
>
> when the compile time analyser reaches line Z it can't work out whether or not the
> contract still applies, so it removes the assertion that vec is e>=0 for all elements, or
> rather asserts that it is not provably true.
> Now when we reach Y the unification fails.
> We don't throw a compile time contraint violation error. We haven't proved it to have failed.
> We throw a compile time constraint unprovable error or warning.
>
> Its like a lint warning. Your code may not be wrong but you might want to consider altering it
> in a way that makes it provably correct.
>
> We would really like to be able to assert that certain properties always hold for a variable
> through its life-time. That is a harder problem.
>
> I see something like this as a basis on which more advanced analysis can be built gradually.
>
> Actually re-using static assert above was probably misleading. It would be better to have something
> that says talk to the compile time theorem prover (a prolog interpreter would do).
>
> I have been meaning to write something along these lines for years but so far I haven't got around to it
> so I might as well stop keeping it under my hat.
>
> Regards,
>
> Bruce.
I think it's terrific to try your hand at it. I for one know am not
equipped for such a pursuit. I have no idea how to perform unification
over loops, particularly when they may have myriads of little
differences while still having the same semantics; how to do that
cross-procedurally in reasonable time; how to take control flow
sensitivity into account; and why exactly people who've worked hard at
it haven't gotten very far. But I am equipped to define a type that
enforces all that simply and clearly, today.
Andrei
|
October 06, 2008 Re: Positive | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> Bruce Adams wrote:
>> On Mon, 06 Oct 2008 00:55:33 +0100, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>>>>>
>>>>> Andrei
>>>> I disagree. I'm not saying its easy but it could be done. We would
>>>> have to start
>>>> with something relatively simple and work our way up but it could be
>>>> done.
>>>
>>> I, too, think it can be done in the same way supersonic mass transportation can be done, but having done research in the area I can tell you you are grossly underestimating the difficulties. It is a project of gargantuan size. Today the most advanced systems only managed to automatically prove facts that look rather trivial to the casual reader. There is absolutely no hope for D to embark on this.
>>>
>> I'm not asking for a generalised theorem prover. Something to handle
>> even the
>> simple cases is a start.
>> I agree that D won't have this (any time soon) but mainly because there
>> are several hundred things higher up the priority list.
>>
>>>> Compiler's already do all kinds of clever analyses behind the scenes
>>>> but each one
>>>> is often hard coded. I suspect the main difficulty is giving users
>>>> too much rope
>>>> by which to hang themselves, or rather hang the compiler trying to
>>>> prove something
>>>> it doesn't realise it can't. Marrying declarative / constraint based
>>>> programming
>>>> at compile time is creeping in via templates. I wish it was less
>>>> well hidden.
>>>
>>> I discussed the problem this morning with Walter and he also started rather cocky: if you assert something early on, you can from then on assume the assertion is true (assuming no assignment took place, which is not hard if you have CFA in place). He got an arrow in a molar with the following example:
>>>
>>> double[] vec;
>>> foreach (e; vec) assert(e >= 0);
>>> // now we know vec is all nonnegatives
>>> normalize(vec);
>>>
>>> The definition of normalize is:
>>>
>>> void normalize(double[] vec)
>>> {
>>> foreach (e; vec) assert(e >= 0);
>>> auto sum = reduce@"a + b"(vec, 0);
>>> assert(sum > 0);
>>> foreach (ref e; vec) e /= sum;
>>> }
>>>
>>> If normalize takes udouble[] and you have one of those, there's no need to recheck. Automated elimination of the checking loop above is really hard.
>>>
>>>
>>> Andrei
>>
>> Is it? I think your example needs to be expanded or we may be talking
>> at cross purposes.
>> Firstly I would rearrange things a little, though in principle it makes
>> no difference.
>>
>> pre
>> {
>> static assert(foreach (e; vec) assert(e >= 0));
>> }
>> void normalize(double[] vec)
>> {
>> auto sum = reduce@"a + b"(vec, 0);
>> assert(sum > 0);
>> foreach (ref e; vec) e /= sum;
>> }
>>
>> double[] vec;
>> static assert(foreach (e; vec) assert(e >= 0)); // line X
>>
>> // now we know vec is all nonnegatives
>> normalize(vec); // line Y
>>
>> Imagine I have a prolog style symbolic unification engine to hand inside my compiler.
>>
>> At line X the static assertion is evaluated.
>> The logical property e>=0 is asserted on the vec symbol.
>> The compiler reaches line Y.
>> Vec has not been modified so still has this property associated with it.
>> We now unify the symbol representing vec with the contract on normalise.
>> The unification succeeds and everything is fine.
>>
>> Now imagine we have a stupid analyser.
>>
>> double[] vec;
>> static assert(foreach (e; vec) assert(e >= 0)); // line X
>>
>> vec[0] -= 1; // line Z
>>
>> // now we know vec is all nonnegatives
>> normalize(vec); // line Y
>>
>> when the compile time analyser reaches line Z it can't work out
>> whether or not the
>> contract still applies, so it removes the assertion that vec is e>=0
>> for all elements, or
>> rather asserts that it is not provably true.
>> Now when we reach Y the unification fails.
>> We don't throw a compile time contraint violation error. We haven't
>> proved it to have failed.
>> We throw a compile time constraint unprovable error or warning.
>>
>> Its like a lint warning. Your code may not be wrong but you might want
>> to consider altering it
>> in a way that makes it provably correct.
>>
>> We would really like to be able to assert that certain properties
>> always hold for a variable
>> through its life-time. That is a harder problem.
>>
>> I see something like this as a basis on which more advanced analysis can be built gradually.
>>
>> Actually re-using static assert above was probably misleading. It
>> would be better to have something
>> that says talk to the compile time theorem prover (a prolog
>> interpreter would do).
>>
>> I have been meaning to write something along these lines for years but
>> so far I haven't got around to it
>> so I might as well stop keeping it under my hat.
>>
>> Regards,
>>
>> Bruce.
>
> I think it's terrific to try your hand at it. I for one know am not equipped for such a pursuit. I have no idea how to perform unification over loops, particularly when they may have myriads of little differences while still having the same semantics; how to do that cross-procedurally in reasonable time; how to take control flow sensitivity into account; and why exactly people who've worked hard at it haven't gotten very far. But I am equipped to define a type that enforces all that simply and clearly, today.
>
>
> Andrei
I'm not an expert at optimizers, but I do read a whole lot. This type of analysis is often call 'value range propagation'. Tracking the possible values for data as it flows around and eliminating checks based on prior events. Most modern compilers do some amount of it. The question is how much and under what circumstances. I'm not sure how many combine that with static value analysis to create multiple function versions. IE, 'enough' callers to justify emitting two different forms of the function, each with different base assumptions about the incoming data and adjusting call sites. I know that some compilers do that for known constant values. I guess it's something halfway to inlining.
I can guess at what dmd's backend does.. or rather doesn't do. :)
Later,
Brad
|
October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | Michel Fortin a écrit :
> On 2008-10-05 20:57:31 -0400, "Chris R. Miller" <lordsauronthegreat@gmail.com> said:
>
>> The !() syntax seems to serve only as a heads up that it's a template. Otherwise (as far as I can tell) a simple foo(int)(bar, baaz) would work just as well as foo!(int)(bar, baaz).
What about the ^ ? I think it's not worst than !
foo^(int)(bar) but maybe this symbol is already used by D ?
Personally I would prefer to keep the C++, Java, C# syntax with <> because people are used to it even if in some cases it looks like a bit shift op.
|
October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Vincent Richomme | Vincent Richomme wrote:
> Michel Fortin a écrit :
>> On 2008-10-05 20:57:31 -0400, "Chris R. Miller" <lordsauronthegreat@gmail.com> said:
>>
>>> The !() syntax seems to serve only as a heads up that it's a template. Otherwise (as far as I can tell) a simple foo(int)(bar, baaz) would work just as well as foo!(int)(bar, baaz).
>
> What about the ^ ? I think it's not worst than !
>
> foo^(int)(bar) but maybe this symbol is already used by D ?
> Personally I would prefer to keep the C++, Java, C# syntax with <> because people are used to it even if in some cases it looks like a bit shift op.
The problem isn't what it looks like to people -- people will generally be able to discern a template instantiation/declaration from a bitshift. The problem is what it looks like to the compiler. If we had this in the compiler, the compiler would need to resolve symbols before it was able to produce a full parse tree, which leads to slower compilation times, more difficult tool creation, and a whole slew of other problems.
|
October 06, 2008 Re: shouting versus dotting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris R. Miller | Chris R. Miller wrote:
> superdan wrote:
>> Andrei Alexandrescu Wrote:
>>
>>> dsimcha wrote:
>>>> == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article
>>>>> The problem I see with "!" as a template instantiation is not technical.
>>>>> I write a fair amount of templated code and over years the "!" did not
>>>>> grow on me at all. I was time and again consoled by Walter than one day
>>>>> that will happen, but it never did. I also realized that Walter didn't
>>>>> see a problem with it because he writes only little template code.
>>>>> I didn't have much beef with other oddities unique to D. For example, I
>>>>> found no problem accommodating binary "~" and I was wondering what makes
>>>>> "!" different. I was just looking at a page full of templates and it
>>>>> looked like crap.
>>>>> One morning I woke up with the sudden realization of what the problem
>>>>> was: the shouting.
>>>>> In C, "!" is used as a unary operator. That may seem odd at first, but
>>>>> it nevers follows a word so it's tenuous to associate it with the
>>>>> natural language "!". In D, binary "!" _always_ follows a word, a name,
>>>>> something coming from natural language. So the conotation with
>>>>> exclamation jumps at you.
>>>>> That's why I find the choice of "!" poor. I believe it can impede to
>>>>> some extent acquisition of templates by newcomers, and conversely I
>>>>> believe that using .() can make templates more palatable. I tried using
>>>>> ".()" in my code and in only a couple of days it looked and felt way
>>>>> better to me. Based on that experience, I suggest that "!()" is dropped
>>>>> in favor of ".()" for template instantiation for D2.
>>>>> Sean's argument that "The exclamation mark signifies an assertion of
>>>>> sorts" is exactly where I'd want templates not to be: they should be
>>>>> blended in, not a hiccup from normal code. Serious effort has been, and
>>>>> still is, made in D to avoid shell-shocking people about use of
>>>>> templates, and I think ".()" would be a good step in that direction.
>>>>> Andrei
>>>> Personally, I think that ".()" looks a little too much like a normal
>>>> function/method call. The "!()" syntax looks just different enough to make it
>>>> easy to keep straight in my head that stuff with the "!" is a compile-time
>>>> construct and stuff without it can be evaluated at runtime.
>>> I'm arguing we _should_ make template code look like "normal" code, whatever "normal" is :o). We _should_ strive for "quiet" templates.
>>>
>>> You know what annoys the living heebiejeebies out of me? Nested template instantiations.
>>>
>>> This!(That!(TheOther!(crap)))
>>>
>>> I have a ton + change of those. In superdan's words: intercourse that.
>>>
>>>
>>> Andrei
>>
>> im a bit drunk. but im much obliged since my name was mentioned n all.
>>
>> ! pisses me off too. i have an opinion. walter looked at unary ops that can be binary ops. first tilde. pulled tat off. ten he wanted the template thing. only 1 left was !. so he put that at work. right walt?
>> now i never like ! because of nother reason. i always forget to put it. and yes it's not needed. i look @ code its unambig. then wtf do i need that crap !
>>
>> anyhoo would be great if ! goes away. to hell with it. need to try asdad.(asdasd) to see how it feels. and yeah they all jump andreis neck whever he posts any. or walts. its funny. hold them guns folks. can i delete this later i wonder.
>
> I live in California. Legally I cannot own any gun that could conceivably hurt someone when misused under the proper situations. =/
>
> I was never particularly annoyed by the !() syntax, but then again I have not written much template code. I can count the number of template classes I have written on one hand.
>
> I am deeply concerned about the proposed .() syntax, however, since (to me) it's too similar to a function call. This lack of finding some kind of counterproposal left me studying my keyboard for any unused characters that could become a symbol. I saw these symbols that I could remember no existing use for:
>
> @, #, $, `
>
> I'm favorable to the # symbol. So a template would look like foo#(int)(bar).
>
> To me the # symbol looks like it could be two Latin 't' characters (not to be confused with the Greek Tau 'T', which is different). Thus one could remember the mnemonic "template" with two t's for the # symbol.
>
> Just a countersuggestion, I haven't really looked through specifications or anything to verify the unused status of any of those symbols.
Sorry, ` is not possible because of `string like = this.toString();`.
|
Copyright © 1999-2021 by the D Language Foundation