www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - C++ guys hate static_if?

reply "DypthroposTheImposter" <mcbracket gmail.com> writes:
        See the static_if paper here:

http://isocpp.org/forums

Under the post "constraints and static if" there is a link to a
document about
static_if

https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

       Are they full of it? Has it caused the problems they mention
in
D?
Mar 08 2013
next sibling parent reply "Brad Anderson" <eco gnuk.net> writes:
On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter 
wrote:
        See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

       Are they full of it? Has it caused the problems they 
 mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.
Mar 08 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter wrote:
       Are they full of it? Has it caused the problems they mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.
Mar 08 2013
next sibling parent "Jouko Koski" <joukokoskispam101 netti.fi> writes:
"Walter Bright"  wrote:

 Many of the criticisms in the paper are addressed by our positive 
 experience with static if in D.

Sometimes I do find it confusing that { does or does not introduce a new scope in a very similar-looking contexts. -- Jouko
Mar 09 2013
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 03/09/13 05:34, H. S. Teoh wrote:
 On Fri, Mar 08, 2013 at 07:50:26PM -0800, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter wrote:
      Are they full of it? Has it caused the problems they mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

I didn't read the paper, but I have to say that static if in D has been extremely, extremely useful in my code. Now that I've become acquianted with it, I can't live without it. It's pretty much a necessity when writing heavily-templated code. But given C++'s broken template design, I can see why its value may not have been appreciated by some people. D may still have its warts, but in terms of being a "better C++", I think it has done a superb job, especially in the area of templates and compile-time mechanisms. Static if + CTFE + sane template syntax = readable template code = total win for D over C++.

Let me quote a paragraph from that paper:
 Being a new and realtively simple-to-use new feature, static_if would un-
 doubtedly be used by many who have no need for the relatively small increme-
 natal improvement in performance offered. The library writers for which such
 techniques really are important, already have to tools and skills needed.

No skilled Real Programmer would ever use a language feature that was simple to use. Seriously though, they point out several problems, some of which are C++ context specific (like mixing CPP w/ static-if and lack of introspection). Other mentioned issues are not real problems in practice, or not even problems at all. What's left is: - static-if not creating scopes /is/ confusing, but what would be a better alternative? - (static-)if in templates or as template constraints - a) prevents pre-instantiation verification - true, applies to D, but not really a big problem, assuming sane application of static-if, b) make constraint-based overloading ugly and fragile - true, something better is needed for D too. But until that exists, careful use of constraints mostly works. artur
Mar 09 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/09/2013 03:15 AM, Artur Skawina wrote:

   - static-if not creating scopes /is/ confusing, but what would be a 

     alternative?

I am surprised that << and >> are never mentioned: static_if >> void foo(); << Problem solved. ;) Ali
Mar 09 2013
next sibling parent reply 1100110 <0b1100110 gmail.com> writes:
On 03/09/2013 12:10 PM, deadalnix wrote:
 On Saturday, 9 March 2013 at 17:51:31 UTC, Ali Çehreli wrote:
 On 03/09/2013 03:15 AM, Artur Skawina wrote:

 - static-if not creating scopes /is/ confusing, but what

 alternative?

I am surprised that << and >> are never mentioned: static_if >> void foo(); << Problem solved. ;) Ali

static if(condition) « void foo(); » Let's do it with style ;)

I love how the second set show up in two different styles on my computer.
Mar 09 2013
parent 1100110 <0b1100110 gmail.com> writes:
On 03/09/2013 12:30 PM, deadalnix wrote:
 On Saturday, 9 March 2013 at 18:23:29 UTC, 1100110 wrote:
 I love how the second set show up in two different styles on my computer.

This is not different style, this is different chars. << >> != « » .

Yes, but my email client did not display them( « » ) as the same character. They showed up as two distinct characters( « >> (we're totally going to pretend that's one character)), which amused me since your comment was "let's do it with style."
Mar 09 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/9/13 1:10 PM, Klaim - Joël Lamotte wrote:
 Note that there will be a teleconference Tuesday with one important point:
 "Discuss whether to continue work on static if, or to focus work on
 concepts lite."
 See:
 https://groups.google.com/a/isocpp.org/forum/#!topic/concepts/AMVFwQGgS3c

 I'm pointing that in case Alexandrescu and Walter didn't know and want
 to defend their paper.

 Joel Lamotte

Thanks, Joel. Andrei
Mar 09 2013
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/09/2013 10:10 AM, deadalnix wrote:

 static_if >>
 void foo();
 <<

 Problem solved. ;)

 Ali

static if(condition) « void foo(); » Let's do it with style ;)

Ha ha! :) I remembered about those characters as well but only after posting mine. Ali
Mar 09 2013
prev sibling parent Hans Uhlig <hans.uhlig teamaol.com> writes:
On 3/9/2013 10:10 AM, deadalnix wrote:
 On Saturday, 9 March 2013 at 17:51:31 UTC, Ali Çehreli wrote:
 On 03/09/2013 03:15 AM, Artur Skawina wrote:

   - static-if not creating scopes /is/ confusing, but what

     alternative?

I am surprised that << and >> are never mentioned: static_if >> void foo(); << Problem solved. ;) Ali

static if(condition) « void foo(); » Let's do it with style ;)

So now I am going to need a unicode keyboard or a massive list of unicode code points.
Mar 12 2013
prev sibling parent reply Nick Treleaven <ntrel-public yahoo.co.uk> writes:
On 09/03/2013 11:15, Artur Skawina wrote:
 Seriously though, they point out several problems, some of which are C++
 context specific (like mixing CPP w/ static-if and lack of introspection).
 Other mentioned issues are not real problems in practice, or not even
 problems at all.

 What's left is:
   - static-if not creating scopes/is/  confusing, but what would be a better
     alternative?

Isn't it only confusing to newbies? It's not hard to learn and recognize.
   - (static-)if in templates or as template constraints -
      a) prevents pre-instantiation verification - true, applies to D, but
           not really a big problem, assuming sane application of static-if,

Maybe a concept-based static if would work for C++? That would allow pre-instantiation verification, but still allow flexible code. The concept test would only allow concept features within the static if branch.
      b) make constraint-based overloading ugly and fragile - true, something
           better is needed for D too. But until that exists, careful use
           of constraints mostly works.

Mar 11 2013
parent reply "Jouko Koski" <joukokoskispam101 netti.fi> writes:
"Nick Treleaven" wrote:
 On 09/03/2013 11:15, Artur Skawina wrote:

   - static-if not creating scopes/is/  confusing, but what would be a 
 better
     alternative?

Isn't it only confusing to newbies? It's not hard to learn and recognize.

Maybe. This is just precisely the way how it all begun in C/C++. -- Jouko
Mar 11 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/11/2013 07:55 PM, Jouko Koski wrote:
 "Nick Treleaven" wrote:
 On 09/03/2013 11:15, Artur Skawina wrote:

   - static-if not creating scopes/is/  confusing, but what would be

     alternative?

Isn't it only confusing to newbies? It's not hard to learn and recognize.

Maybe. This is just precisely the way how it all begun in C/C++.

Actually, in D, static if creates its own scopes for declarations made inside the static if condition.
Mar 11 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
 On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for declarations made
 inside the static if condition.

No, it doesn't,

Yes it does.
 and it would be _way_ less useful if it did,

I don't think so.
 particularly with
 regards to struct and class definitions. Take this code, for instance,

 import std.stdio;

 static if(true)
      int var = 7;
 else
      string var = 12;

 void main()
 {
      int i = var;

      static if(is(typeof(var) == int))
          int j = 22;
      else
          float j;

      writeln(j);
 }

 It compiles just fine and prints 22. Both the static if at module-level and the
 one in the function declare variables which are used outside of the static if
 blocks. static if does _not_ create a new scope. And putting braces around the
 static if bodies has no effect on the scoping either.

 ...

What is the point? Your example code does not make any declaration inside the static if condition.
Mar 11 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/11/2013 11:06 PM, H. S. Teoh wrote:
 On Mon, Mar 11, 2013 at 10:31:53PM +0100, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
 On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for declarations
 made inside the static if condition.

No, it doesn't,

Yes it does.

Actually, it doesn't, scarily enough: import std.stdio; void main() { int[string] x; //float x; static if (is(typeof(x) S : T[U], T, U)) { writeln(S.stringof); writeln(T.stringof); writeln(U.stringof); } writeln(S.stringof); // <-- this compiles, and works!! } The last writeln will fail to compile if x's type is changed to float (as in the commented out line). Meaning that the definitions of S, T, U "leak" past the scope of the static if. Which makes the semantics of the code very unclear, because whether or not it even compiles depends on how the static if condition turns out. :-/ T

Wtf. :) void main() { int[string] x; static if (is(typeof(x) S : T[U], T, U)) { } pragma(msg, S, " ", T, " ", U); } I have checked again and the documentation actually does not specify this. It just contains suggestive examples.
Mar 11 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/11/2013 11:15 PM, monarch_dodra wrote:
 ...

 I think that's bug material. The "is" definition should end at the end
 of that block.

http://d.puremagic.com/issues/show_bug.cgi?id=9693
Mar 11 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests. Andrei
Mar 14 2013
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 11:38 AM, Andrei Alexandrescu wrote:
 On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests.

Uhm sorry for the repetition. Wrote this note in two quanta with a break between them :o). Andrei
Mar 14 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 11:50 AM, deadalnix wrote:
 On Thursday, 14 March 2013 at 15:38:53 UTC, Andrei Alexandrescu wrote:
 On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests. Andrei

The same argument can be made when talking about dynamic vs static typing.

And it has been made indeed. The question is on agreeing or not with specifics. The stereotypical argument in favor of dynamic typing goes as follows: Q: Does static typing detect all bugs? A: No. Q: Then unittests are necessary. A: Correct. Q: So if static typing is insufficient, why not rely on unittests alone to do all checking? It's also bothersome for some people to obey types, annotate stuff etc. A: There are still errors that can be better detected with static checking, and many dynamic programs that work by accident etc. Q: ... I agree or don't agree ...
 This is usualy much better to have the compiler smash your mistake right
 into your face than discovering with a unittest much latter.

I don't think so.
 I don't say that unittest are useless, but why rely on unittest when the
 machine can do the job for you ?

In both cases the machine does the work. My argument is that adding an additional layer of typing on top of templates caters to people who want to ship code that has literally zero testing. That's not a priority as far as I'm concerned. Andrei
Mar 14 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 12:54 PM, deadalnix wrote:
 On Thursday, 14 March 2013 at 16:48:29 UTC, Andrei Alexandrescu wrote:
 And it has been made indeed. The question is on agreeing or not with
 specifics. The stereotypical argument in favor of dynamic typing goes
 as follows:

 Q: Does static typing detect all bugs?

 A: No.

 Q: Then unittests are necessary.

 A: Correct.

 Q: So if static typing is insufficient, why not rely on unittests
 alone to do all checking? It's also bothersome for some people to obey
 types, annotate stuff etc.

 A: There are still errors that can be better detected with static
 checking, and many dynamic programs that work by accident etc.

I see we agree this is the same problem materialized in another form. I find it rather weird that you conclude different things when the problem is the same in the first place.

Very simple. Traditionally there's two crucial epochs known as compilation time and run time. (There's some minor distinctions like link time etc.) The whole notion of concepts and other type systems for templates is predicated on three crucial epochs: library compilation time, library user compilation time, and run time. The logic goes, someone writes a generic library and wants to distribute it to users. Users shouldn't ever see bugs caused by e.g. typos in the library. So the crowd that use meta-type systems is formed of library writers who want to distribute libraries without ever instantiating them. I don't think that's a good crowd to cater for. I've been surprised to figure how many people don't get this flow, or only have a vague image of it. Although meta-types are arguably "the right thing" to do, they're a lot less attractive once it's clear what scenarios they help. Andrei
Mar 14 2013
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
14-Mar-2013 21:07, Andrei Alexandrescu пишет:
 On 3/14/13 12:54 PM, deadalnix wrote:

 Q: So if static typing is insufficient, why not rely on unittests
 alone to do all checking? It's also bothersome for some people to obey
 types, annotate stuff etc.

 A: There are still errors that can be better detected with static
 checking, and many dynamic programs that work by accident etc.

I see we agree this is the same problem materialized in another form. I find it rather weird that you conclude different things when the problem is the same in the first place.

Very simple. Traditionally there's two crucial epochs known as compilation time and run time. (There's some minor distinctions like link time etc.) The whole notion of concepts and other type systems for templates is predicated on three crucial epochs: library compilation time, library user compilation time, and run time. The logic goes, someone writes a generic library and wants to distribute it to users. Users shouldn't ever see bugs caused by e.g. typos in the library. So the crowd that use meta-type systems is formed of library writers who want to distribute libraries without ever instantiating them. I don't think that's a good crowd to cater for. I've been surprised to figure how many people don't get this flow, or only have a vague image of it. Although meta-types are arguably "the right thing" to do, they're a lot less attractive once it's clear what scenarios they help.

Maybe we then should help people that routinely instantiate their templates to see if they compile. Say add a library artifact tryInstantiate: auto foo(...)(...); static assert(tryInstantiate!(foo, TypesForFirstArg!(...), TypesForSecond!(foo, ...),...); Inspired by the ubiquitously common foreach(type; TypeTuple!(A,B,C)){ ...} unit test pattern. -- Dmitry Olshansky
Mar 14 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 10:20 AM, Dmitry Olshansky wrote:
 Maybe we then should help people that routinely instantiate their templates to
 see if they compile.

We already have a tool to do this: dmd -cov test.d
Mar 14 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 08:46 PM, Walter Bright wrote:
 On 3/14/2013 10:20 AM, Dmitry Olshansky wrote:
 Maybe we then should help people that routinely instantiate their
 templates to
 see if they compile.

We already have a tool to do this: dmd -cov test.d

But it does not work. See this recent D.learn thread: http://forum.dlang.org/thread/wwjaeexnyaeqnqsqydte forum.dlang.org
Mar 14 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 12:51 PM, Timon Gehr wrote:
 On 03/14/2013 08:46 PM, Walter Bright wrote:
 On 3/14/2013 10:20 AM, Dmitry Olshansky wrote:
 Maybe we then should help people that routinely instantiate their
 templates to
 see if they compile.

We already have a tool to do this: dmd -cov test.d

But it does not work. See this recent D.learn thread: http://forum.dlang.org/thread/wwjaeexnyaeqnqsqydte forum.dlang.org

-cov works fine for templates containing executable code.
Mar 14 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 09:11 PM, Walter Bright wrote:
 On 3/14/2013 12:51 PM, Timon Gehr wrote:
 On 03/14/2013 08:46 PM, Walter Bright wrote:
 On 3/14/2013 10:20 AM, Dmitry Olshansky wrote:
 Maybe we then should help people that routinely instantiate their
 templates to
 see if they compile.

We already have a tool to do this: dmd -cov test.d

But it does not work. See this recent D.learn thread: http://forum.dlang.org/thread/wwjaeexnyaeqnqsqydte forum.dlang.org

-cov works fine for templates containing executable code.

Then it is not what Dmitry was asking for. Anyway -cov is near-useless for me because it does not support string mixins (execution attributed to wrong code line) and executable code coming from template mixins (sometimes counted, sometimes not).
Mar 14 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 2:01 PM, Timon Gehr wrote:
 Anyway -cov is near-useless for me
 because it does not support string mixins (execution attributed to wrong code
 line) and executable code coming from template mixins (sometimes counted,
 sometimes not).

Please file bugzilla entries for these.
Mar 14 2013
prev sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
14-Mar-2013 23:46, Walter Bright пишет:
 On 3/14/2013 10:20 AM, Dmitry Olshansky wrote:
 Maybe we then should help people that routinely instantiate their
 templates to
 see if they compile.

We already have a tool to do this: dmd -cov test.d

No it's not. It's I'm out of words to even begin to describe how it doesn't do what's needed in this case. To start 'dmd -cov test.d' doesn't instantiate all of templates (or generate code to do so) with the right sets of types auto-magically. -- Dmitry Olshansky
Mar 14 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 12:53 PM, Dmitry Olshansky wrote:
 No it's not.
 It's I'm out of words to even begin to describe how it doesn't do what's needed
 in this case. To start 'dmd -cov test.d' doesn't instantiate all of templates
 (or generate code to do so) with the right sets of types auto-magically.

It helps by showing which paths were run by the testing.
Mar 14 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
15-Mar-2013 00:12, Walter Bright пишет:
 On 3/14/2013 12:53 PM, Dmitry Olshansky wrote:
 No it's not.
 It's I'm out of words to even begin to describe how it doesn't do
 what's needed
 in this case. To start 'dmd -cov test.d' doesn't instantiate all of
 templates
 (or generate code to do so) with the right sets of types auto-magically.

It helps by showing which paths were run by the testing.

It doesn't show which types ended up in each of template instantiation. This is a critical piece of information. The way around that would be having a separate file per combination of type and run each with cov separately then use external tool to analyze and aggregate the logs. Far, far from 'having a tool to do this'. The aspect of running separate tests is even more frustrating as the fact compiler knows all of the relevant info already. -- Dmitry Olshansky
Mar 14 2013
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 12:53 PM, Dmitry Olshansky wrote:
 No it's not.
 It's I'm out of words to even begin to describe how it doesn't do what's needed
 in this case. To start 'dmd -cov test.d' doesn't instantiate all of templates
 (or generate code to do so) with the right sets of types auto-magically.

For the following program: ---------test.d------------- import core.stdc.stdio; public import std.whatever; int main() { printf("Success!\n"); return 0; } ---------------------------- Try compiling: dmd -cov test.d std\whatever -unittest and examine std-whatever.lst. We can do a lot, lot better before we need something better than -cov.
Mar 14 2013
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
15-Mar-2013 00:27, Walter Bright пишет:
 On 3/14/2013 12:53 PM, Dmitry Olshansky wrote:
 No it's not.
 It's I'm out of words to even begin to describe how it doesn't do
 what's needed
 in this case. To start 'dmd -cov test.d' doesn't instantiate all of
 templates
 (or generate code to do so) with the right sets of types auto-magically.

For the following program: ---------test.d------------- import core.stdc.stdio; public import std.whatever; int main() { printf("Success!\n"); return 0; } ---------------------------- Try compiling: dmd -cov test.d std\whatever -unittest and examine std-whatever.lst. We can do a lot, lot better before we need something better than -cov.

Point taken. That doesn't detract us from: a) fixing issues with -cov It counts time a LOC is executed. Would nice to add instantations counter (determined at compile time) as well so as to see if declarations are all covered. That + CTFE-only counted as 0. b) unifying template fuzzy testing in Phobos We have lots of these wheels reinvented across Phobos alone. c) prototyping other higher-level tools to aid debugging generic code -- Dmitry Olshansky
Mar 14 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 4:37 PM, Dmitry Olshansky wrote:
 Point taken. That doesn't detract us from:
 a) fixing issues with -cov

Yes please (are there bugzilla entries etc)?
 It counts time a LOC is executed. Would nice to add instantations
 counter (determined at compile time) as well so as to see if
 declarations are all covered. That + CTFE-only counted as 0.

Not getting this. Example?
 b) unifying template fuzzy testing in Phobos

 We have lots of these wheels reinvented across Phobos alone.

Like those dummy ranges in std.algorithm?
 c) prototyping other higher-level tools to aid debugging generic code

Yeppers! Andrei
Mar 14 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
15-Mar-2013 01:58, Andrei Alexandrescu пишет:
 On 3/14/13 4:37 PM, Dmitry Olshansky wrote:
 Point taken. That doesn't detract us from:
 a) fixing issues with -cov

Yes please (are there bugzilla entries etc)?

template powerup(T) //usable as template mixin too { //imagine more constraints static if(size_t.sizeof == 4) alias bleh = blah; else alias bleh = oldBlah; //... } Now first mixin template don't get counted at all (even code within). Then declarations are ignored and you'll never know which ones were ever looked at.
 It counts time a LOC is executed. Would nice to add instantations
 counter (determined at compile time) as well so as to see if
 declarations are all covered. That + CTFE-only counted as 0.

Not getting this. Example?

 b) unifying template fuzzy testing in Phobos

 We have lots of these wheels reinvented across Phobos alone.

Like those dummy ranges in std.algorithm?

Yes. We might as well provide a good hardy set of these as std.testing.mockup or smth like that.
 c) prototyping other higher-level tools to aid debugging generic code

Yeppers!

It seems like a good application for DSL + CTFE. Even if CTFE is too inefficient ATM for large tests a standalone tool could be prototyped with exactly same D code. Now that I'm saying it I'll probably prototype one just for fun :)
 Andrei

-- Dmitry Olshansky
Mar 14 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 11:36 PM, Dmitry Olshansky wrote:
 15-Mar-2013 01:58, Andrei Alexandrescu пишет:
 On 3/14/13 4:37 PM, Dmitry Olshansky wrote:
 Point taken. That doesn't detract us from:
 a) fixing issues with -cov

Yes please (are there bugzilla entries etc)?

template powerup(T) //usable as template mixin too { //imagine more constraints static if(size_t.sizeof == 4) alias bleh = blah; else alias bleh = oldBlah; //... } Now first mixin template don't get counted at all (even code within). Then declarations are ignored and you'll never know which ones were ever looked at.

-cov only counts executable lines. The above are not executable - I don't see any way to make them work with -cov.
Mar 14 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
15-Mar-2013 10:47, Walter Bright пишет:
 On 3/14/2013 11:36 PM, Dmitry Olshansky wrote:
 15-Mar-2013 01:58, Andrei Alexandrescu пишет:
 On 3/14/13 4:37 PM, Dmitry Olshansky wrote:
 Point taken. That doesn't detract us from:
 a) fixing issues with -cov

Yes please (are there bugzilla entries etc)?

template powerup(T) //usable as template mixin too { //imagine more constraints static if(size_t.sizeof == 4) alias bleh = blah; else alias bleh = oldBlah; //... } Now first mixin template don't get counted at all (even code within). Then declarations are ignored and you'll never know which ones were ever looked at.

-cov only counts executable lines. The above are not executable - I don't see any way to make them work with -cov.

The information can be trivially collected during semantic analysis of declarations. How to merge this compile-time info with run-time one as in -cov is a another question. I'd try outputting some table into object file (special section etc.) and then -cov would use it to mark non-executable code. -- Dmitry Olshansky
Mar 14 2013
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 1:27 PM, Walter Bright wrote:
 We can do a lot, lot better before we need something better than -cov.

A proposal to improve the use of -cov: http://d.puremagic.com/issues/show_bug.cgi?id=9726
Mar 15 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 3:53 PM, Dmitry Olshansky wrote:
 It's I'm out of words to even begin to describe how it doesn't do what's
 needed in this case. To start 'dmd -cov test.d' doesn't instantiate all
 of templates (or generate code to do so) with the right sets of types
 auto-magically.

You are well understood. What a coverage test does help with is show you there is code that has never been instantiated. Andrei
Mar 14 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 1:43 PM, Nick Sabalausky wrote:
 On Thu, 14 Mar 2013 11:38:52 -0400
 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>  wrote:

 On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests.

What the hell is this, a JS/Python forum all of a sudden? You're literally making the exact same argument as "We don't need no steenkin' static type checking."

No. Andrei
Mar 14 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 1:37 PM, deadalnix wrote:
 On Thursday, 14 March 2013 at 17:07:16 UTC, Andrei Alexandrescu wrote:
 Very simple. Traditionally there's two crucial epochs known as
 compilation time and run time. (There's some minor distinctions like
 link time etc.) The whole notion of concepts and other type systems
 for templates is predicated on three crucial epochs: library
 compilation time, library user compilation time, and run time. The
 logic goes, someone writes a generic library and wants to distribute
 it to users. Users shouldn't ever see bugs caused by e.g. typos in the
 library.

I'm not sure if you are thinking I'm really stupid here.

Being wrong doesn't make one stupid.
 So the crowd that use meta-type systems is formed of library writers
 who want to distribute libraries without ever instantiating them. I
 don't think that's a good crowd to cater for.

 I've been surprised to figure how many people don't get this flow, or
 only have a vague image of it. Although meta-types are arguably "the
 right thing" to do, they're a lot less attractive once it's clear what
 scenarios they help.

Let me demonstrate with an actual example :

 Yes I added the bar on purpose in some heavily templated code. You
 concentrate too much on theses people that want to ship code without
 using it. They'll do it anyway.

 And that make even more sense from the lib user perspective, as having
 the compiler vomit kilometers of internals of a lib is usually not
 helpful (this happen a lot with phobos).

Template constraints are D's solution to that issue. I agree it's not perfect, but I think dollar for dollar it's better than concepts. Andrei
Mar 14 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 10:25 PM, deadalnix wrote:
 On Thursday, 14 March 2013 at 17:53:42 UTC, Andrei Alexandrescu wrote:
 Template constraints are D's solution to that issue. I agree it's not perfect,
 but I think dollar for dollar it's better than concepts.

No they aren't, because it would only skip the top most lines and replace the error by something like impossible to find method blah. With something like concept, I'd have something like in case of eroneous template : file:line: Error: concept Blah don't have member blah.

D also allows you to build custom error messages.
Mar 14 2013
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 10:37 AM, deadalnix wrote:
 Let me demonstrate with an actual example :

 libd-llvm/libd/src/d/parser/ambiguous.d(126): Error: no property 'bar' for type
 'Lexer', did you mean 'r'?

This wouldn't have been detected under the proposed scheme, because it is a semantic error, not a syntactic one.
Mar 14 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 2:29 PM, Jonathan M Davis wrote:
 The main problem is not people who don't unit test their templates but the
 fact that it's pretty much impossible to cover every possible instantiation of
 a template, and so it can be pretty easy to miss stuff.

Concepts don't do that either. I do agree we could and should do a better job at testing templates against bare minimum structures that pass their constraints (e.g. test input range algorithms with true input range, which are indeed one-pass). Again, concepts won't help there either - it's not like we claim to support input ranges and then call .save against them. That's not a frequent bug. Andrei
Mar 14 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
15-Mar-2013 06:43, deadalnix пишет:
 On Thursday, 14 March 2013 at 23:52:59 UTC, Nick Sabalausky wrote:
 On Thu, 14 Mar 2013 17:54:52 -0400
 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:



 That implicitly does the equivalent of ".save" on a mere InputRange
 *twice*. The result, of course, is completely dependent on the input
 range in question.

Passing range by value is completely undefined, which is IMO a big weak spot of ranges.

What can be done in the mean time is stating somewhere prominent this: Given InputRanges a & b: 1. a = b; //now 'a' can only be *either* an alias of 'b' or 'a' is a copy of 'b' 2. a = move(b); //now a is the only copy (the only alias ;)) 3. a = b.save(); //now a is guaranteed to be a shallow copy By copy here it's implied that range preserves iteration state. The underlying values may be changed elsewhere. There could be some argument to make 1 always do 3 and trim it to 2 rules. But ehm, sorry, classes as ranges can't do that so we are stuck. If I had to choose I'd drop the current OOP support of D in favor of simplifying things (only half-joking) :) -- Dmitry Olshansky
Mar 15 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
15-Mar-2013 15:27, Dmitry Olshansky пишет:
 15-Mar-2013 06:43, deadalnix пишет:
 On Thursday, 14 March 2013 at 23:52:59 UTC, Nick Sabalausky wrote:
 On Thu, 14 Mar 2013 17:54:52 -0400
 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:



 That implicitly does the equivalent of ".save" on a mere InputRange
 *twice*. The result, of course, is completely dependent on the input
 range in question.

Passing range by value is completely undefined, which is IMO a big weak spot of ranges.

What can be done in the mean time is stating somewhere prominent this: Given InputRanges a & b:

Forward obviously.
 1. a = b; //now 'a' can only be *either* an alias of 'b' or 'a' is a
 copy of 'b'
 2. a = move(b); //now a is the only copy (the only alias ;))
 3. a = b.save(); //now a is guaranteed to be a shallow copy

 By copy here it's implied that range preserves iteration state. The
 underlying values may be changed elsewhere.

 There could be some argument to make 1 always do 3 and trim it to 2
 rules. But ehm, sorry, classes as ranges can't do that so we are stuck.

 If I had to choose I'd drop the current OOP support of D in favor of
 simplifying things (only half-joking) :)

-- Dmitry Olshansky
Mar 15 2013
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 1:07 PM, bearophile wrote:
 Andrei Alexandrescu:

 This is usualy much better to have the compiler smash your mistake right
 into your face than discovering with a unittest much latter.

I don't think so.

Why?

It's just an entirely different scenario. I can easily imagine a unittest failing to cover the entirety of possible flows in a function (particularly when exceptions get involved!). So clearly unittests define a spectrum of checking. In contrast, with typos in templates unittests are Boolean function. Either the thing compiles or it doesn't, no other way about it. Consider https://github.com/D-Programming-Language/phobos/pull/1205. I wrote unittests for the straight version and for pairwise summation, but not for Kahan. The code passed unittests, but clearly that wasn't enough. So I added the SList-based test to make sure the Kahan version works, and lo and behold I found typos in it that made it uncompilable, AND then run-time bugs that made it produce incorrect results. A concept system would have helped me there if my intent was to ship Kahan summation without ever testing it. That's not an intent we want to cater for!
 My argument is that adding an additional layer of typing on top of
 templates caters to people who want to ship code that has literally
 zero testing. That's not a priority as far as I'm concerned.

If those people want yo write zero unit tests, they will write zero unit tests in both cases. I have seen D code like that. Introducing some compiler tests isn't going to make that situation worse and it's able to give better&nicer error messages when you have just written a template and you have not yet written a unittest (assuming you aren't using Test-Driven-Development).

It has happened (very rarely) that pieces of generic code in Phobos had errors. I don't think those deserve help from the compiler. Andrei
Mar 14 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 1:48 PM, H. S. Teoh wrote:
 I don't agree. Phobos is a prime example. Does Phobos have unittests?
 Yes, and lots of them. Does it still have non-compilable template
 instantiations? Yes, because unittests can't cover all possibilities --
 there are too many possible combinations of template arguments. There
 are bound to be untested combinations which don't work but we're unaware
 of.

If you found a few, that would be great. I don't think you'll have an easy time. Andrei
Mar 14 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 2:07 PM, Dicebot wrote:
 On Thursday, 14 March 2013 at 17:51:23 UTC, Andrei Alexandrescu wrote:
 If you found a few, that would be great. I don't think you'll have an
 easy time.

 Andrei

In other comment I have mentioned a case I have fixed just 15 days ago: https://github.com/D-Programming-Language/phobos/pull/1182 100% line coverage, compile-time error for certain type parameter subset. Could have been found by compiler / clever-enough framework. That was easy.

1 < a few Andrei
Mar 14 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 3:04 PM, H. S. Teoh wrote:
 I found (and fixed!) a number of missed combinations in std.algorithm:
 transient ranges, joiner() not using .save on forward ranges, same bug
 in transposed(), transposed crashing on jagged range of ranges, etc..

I think you're right but only in part; there may be a bit of a confusion. There's pure semantic checking such as forgetting to use .save that can't be detected statically. Then there's code that e.g. should work for forward ranges but has only been tested with arrays. My question was referring to code that has sheer typos that are mechanically detected, which are present in code that has never ever been instantiated. I do recall we found a few, but I think that illustrates a problem with the process, not the language. Andrei
Mar 14 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 06:51 PM, Andrei Alexandrescu wrote:
 On 3/14/13 1:48 PM, H. S. Teoh wrote:
 I don't agree. Phobos is a prime example. Does Phobos have unittests?
 Yes, and lots of them. Does it still have non-compilable template
 instantiations? Yes, because unittests can't cover all possibilities --
 there are too many possible combinations of template arguments. There
 are bound to be untested combinations which don't work but we're unaware
 of.

If you found a few, that would be great. I don't think you'll have an easy time. Andrei

Challenge accepted. Clearly the Phobos developers do not instantiate their templates before shipping them. :o) The following breaks most of std.range, and most of std.algorithm could likely be broken too, but I am too lazy to investigate. import std.range, std.algorithm; struct TrollFace{ property string front()const{ return "troll"; } property string back()const{ return "face"; } property bool empty()const{ return true; } void popFront()const{ } void popBack()const{ } property inout(TrollFace) save()inout{ return this; } auto opIndex(size_t index){ return front; } property size_t length()inout{ return 0; } int* x; } struct TrollierFace{ TrollFace face; alias face this; disable this(this); property inout(TrollierFace) save()inout{ return inout(TrollierFace)(face); } } void main(){ immutable TrollFace a,b,c; a.retro(); a.stride(2); chain(a,b,c); roundRobin(a,b,c); a.radial(); a.radial(0); a.take(2); (immutable(TrollierFace)()).takeExactly(2); (immutable(TrollierFace)()).takeOne(); (immutable(TrollierFace)()).takeNone(); (immutable(TrollierFace)()).drop(2); (immutable(TrollierFace)()).dropExactly(0); (immutable(TrollierFace)()).dropOne(); (immutable(TrollierFace)()).repeat(); a.cycle(); a.zip(b); lockstep((immutable(TrollierFace)()),b); a.frontTransversal(); a.transversal(0); a.indexed([0]); a.chunks(5); a.filter!(a=>true); a.map!(a=>a); // ... (and so on) }
Mar 14 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 1:57 PM, Timon Gehr wrote:
 The following breaks most of std.range, and most of std.algorithm could likely
 be broken too, but I am too lazy to investigate.

Please file this with bugzilla.
Mar 14 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 10:37 PM, Walter Bright wrote:
 On 3/14/2013 1:57 PM, Timon Gehr wrote:
 The following breaks most of std.range, and most of std.algorithm
 could likely
 be broken too, but I am too lazy to investigate.

Please file this with bugzilla.

http://d.puremagic.com/issues/show_bug.cgi?id=9724
Mar 14 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 4:57 PM, Timon Gehr wrote:
 On 03/14/2013 06:51 PM, Andrei Alexandrescu wrote:
 On 3/14/13 1:48 PM, H. S. Teoh wrote:
 I don't agree. Phobos is a prime example. Does Phobos have unittests?
 Yes, and lots of them. Does it still have non-compilable template
 instantiations? Yes, because unittests can't cover all possibilities --
 there are too many possible combinations of template arguments. There
 are bound to be untested combinations which don't work but we're unaware
 of.

If you found a few, that would be great. I don't think you'll have an easy time. Andrei

Challenge accepted. Clearly the Phobos developers do not instantiate their templates before shipping them. :o) The following breaks most of std.range, and most of std.algorithm could likely be broken too, but I am too lazy to investigate.

Nice point. The problem is an immutable TrollFace should not qualify pass the range tests. This could happen if there was a similar bug in a concept definition. So your argument does not move the ball on concepts vs static if. Andrei
Mar 14 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 10:48 PM, Andrei Alexandrescu wrote:
 On 3/14/13 4:57 PM, Timon Gehr wrote:
 ...

 The following breaks most of std.range, and most of std.algorithm could
 likely be broken too, but I am too lazy to investigate.

Nice point. The problem is an immutable TrollFace should not qualify pass the range tests.

Yes, that is one valid analysis of the situation.
 This could happen if there was a similar bug in a
 concept definition.

Yes. In which case it would be detected while the code is written, which is the point.
 So your argument does not move the ball on concepts
 vs static if.
...

I'm not intending to move any balls here. The trade-offs are different.
Mar 14 2013
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 1:57 PM, Timon Gehr wrote:
 Challenge accepted. Clearly the Phobos developers do not instantiate their
 templates before shipping them. :o)

 The following breaks most of std.range, and most of std.algorithm could likely
 be broken too, but I am too lazy to investigate.

Compiling with -cov -unittest shows: std.range 86% covered "good" std.algorithm 96% covered "excellent"
Mar 14 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/15/2013 12:18 AM, monarch_dodra wrote:
 On Thursday, 14 March 2013 at 20:57:57 UTC, Timon Gehr wrote:
 ...

 Challenge accepted. Clearly the Phobos developers do not instantiate
 their templates before shipping them. :o)

 The following breaks most of std.range, and most of std.algorithm
 could likely be broken too, but I am too lazy to investigate.

All this breakage is just one and the same bug. ...

Even if you count all bugs of the same kind as one bug, there are at least two.
Mar 15 2013
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 9:54 AM, deadalnix wrote:
 I have other benefit, as the capability for the compiler to give understandable
 error message instead of a wall of template errors.

Syntactic error messages would be the same in either case.
Mar 14 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 06:48 PM, H. S. Teoh wrote:
 ...

 We could, of course, automatically generate a very large number of
 template argument combinations and check to see if they're instantiable.
 In fact, we could write unittests that loop over every combination of a
 given list of types and instantiate the template to be tested with them.
 This is well within D's metaprogramming capabilities.

 ...

But way behind state-of-the-art research in program validation.
Mar 14 2013
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 11:04 AM, H. S. Teoh wrote:
 But that was my point, if we had concepts, then the compiler could
 statically check the syntax of the template without needing to iterate
 over all combinations of types.

A syntax check is not a semantic check.
 Right now, we *have* to essentially check all combinations in unittests
 if we want to be sure that the template is instantiable in all cases.

You have to anyway. Consider functions. Just because the function passes syntactical and semantic checks does not at all mean it passes with all combinations of parameter values. We still need unittests, and while unittests also do not guarantee the function is correct in all cases, it is considered unprofessional to ship a function that was never called at runtime in any tests.
Mar 14 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 12:32 PM, bearophile wrote:
 Andrei Alexandrescu:

 I'm not sure about that. The way I see it, no code should be not
 delivered without being unittested. Ubiquitous unittesting is now
 mainstream. The way I see it, a type system on top of templates would
 only help people who don't write unittests.

This is an invalid argument. You can say the same thing for many (most?) tests done by the compiler.

No, this is different. Andrei
Mar 14 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 1:58 PM, Nick Sabalausky wrote:
 On Thu, 14 Mar 2013 12:48:28 -0400
 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>  wrote:
 On 3/14/13 11:50 AM, deadalnix wrote:
 This is usualy much better to have the compiler smash your mistake
 right into your face than discovering with a unittest much latter.

I don't think so.

On Thu, 14 Mar 2013 12:49:01 -0400 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:
 On 3/14/13 12:32 PM, bearophile wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler.

No, this is different.

Man: An argument is a connected series of statements intended to establish a proposition. Andrei: No it isn't. Man: Yes it is! It's not just contradiction. Andrei: Look, if I argue with you, I must take up a contrary position. Man: Yes, but that's not just saying 'No it isn't.' Andrei: Yes it is! Man: No it isn't! Andrei: Yes it is! Man: Argument is an intellectual process. Contradiction is just the automatic gainsaying of any statement the other person makes. (short pause) Andrei: No it isn't.

No. Andrei
Mar 14 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 1:15 PM, Dicebot wrote:
 On Thursday, 14 March 2013 at 17:09:41 UTC, Andrej Mitrovic wrote:
 On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler. Unit tests can't be sure to
 verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries. You use template constraints to limit the code paths, and you use unittests to verify semantics. Then there's also static assert(0).

Does Phobos pull request tester turns red on failed 100% coverage? (sarcasm intended)

Walter has measured coverage of Phobos unittests a couple of times, it's very high. But I agree it would be nice to have it as a target. Andrei
Mar 14 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 11:38 AM, Jonathan M Davis wrote:
 Though this is exactly a case where 100% unit test coverage doesn't mean much.
 All that means is that each path has been instantiated and run. It doesn't
 mean that it's covered enough possible instantiations to properly test the
 template.

I understand this. But my experience in the matter has been that if the tests cover 100% of the code paths, the incidence of undetected bugs in the code goes very, very low. So, I disagree with "doesn't mean much". Pedantically, it means little, but practically, it means a great deal. (Of course, for multithreading you'd be right - runtime testing is notoriously unproductive in finding concurrency mistakes.)
Mar 14 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 2:26 PM, bearophile wrote:
 Walter Bright:

 I understand this. But my experience in the matter has been that if the tests
 cover 100% of the code paths, the incidence of undetected bugs in the code
 goes very, very low.

This is not so much true for template-heavy code.

I don't believe that without further evidence.
 And 100% code coverage is not enough even for regular code,

I didn't say it was perfect. I said it is very effective, and doesn't leave much left. I have very positive experience with code I took the time to do coverage testing on, and so have others.
Mar 14 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 2:38 PM, Jonathan M Davis wrote:
 On Thursday, March 14, 2013 13:26:18 Andrei Alexandrescu wrote:
 Walter has measured coverage of Phobos unittests a couple of times, it's
 very high. But I agree it would be nice to have it as a target.

Though this is exactly a case where 100% unit test coverage doesn't mean much. All that means is that each path has been instantiated and run. It doesn't mean that it's covered enough possible instantiations to properly test the template.

Concepts won't help there either. Andrei
Mar 14 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 3:02 PM, H. S. Teoh wrote:
 Under a concepts system, this would be caught early because the compiler
 would detect a concept mismatch (Unqual!T != T) when analysing the
 template code.

How would that be different from simply adding a template constraint?
Mar 14 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 6:15 PM, Walter Bright wrote:
 On 3/14/2013 3:02 PM, H. S. Teoh wrote:
 Under a concepts system, this would be caught early because the compiler
 would detect a concept mismatch (Unqual!T != T) when analysing the
 template code.

How would that be different from simply adding a template constraint?

The difference is without the constraint there's no error. It's all about the default: by default (no constraints) everything is allowed. Andrei
Mar 14 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 3:20 PM, Andrei Alexandrescu wrote:
 On 3/14/13 6:15 PM, Walter Bright wrote:
 On 3/14/2013 3:02 PM, H. S. Teoh wrote:
 Under a concepts system, this would be caught early because the compiler
 would detect a concept mismatch (Unqual!T != T) when analysing the
 template code.

How would that be different from simply adding a template constraint?

The difference is without the constraint there's no error. It's all about the default: by default (no constraints) everything is allowed.

I meant how would a concept be better than a constraint for this example.
Mar 14 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/13 6:02 PM, H. S. Teoh wrote:
 On Thu, Mar 14, 2013 at 05:54:05PM -0400, Andrei Alexandrescu wrote:
 On 3/14/13 2:38 PM, Jonathan M Davis wrote:
 On Thursday, March 14, 2013 13:26:18 Andrei Alexandrescu wrote:
 Walter has measured coverage of Phobos unittests a couple of times,
 it's very high. But I agree it would be nice to have it as a target.

Though this is exactly a case where 100% unit test coverage doesn't mean much. All that means is that each path has been instantiated and run. It doesn't mean that it's covered enough possible instantiations to properly test the template.

Concepts won't help there either.

It does help. For example, if the code wrongly assumes mutability for a particular template type, then it may work for most test cases (frankly, I find const/immutable unittest coverage in Phobos very poor) but fail when some daring user passes const(T) instead of T to the template. For example, you may have accidentally written the equivalent of: auto func(T)(T t) { Unqual!T u = t; //<-- spot the bug ... } Under a concepts system, this would be caught early because the compiler would detect a concept mismatch (Unqual!T != T) when analysing the template code. Currently, though, if there is no unittest that tries instantiating the template with const(T), the bug goes undetected, because in all *tested* instantiations, Unqual!T == T.

Template constraints start from the most permissive end of the spectrum: by default there's no verification, and constraints add verification. With typeclasses it's the other way around: by default nothing is allowed, so code needs to add permissions explicitly. I agree that in that regard typeclasses are better than template constraints. Of course there are many other aspects to be considered when comparing the two. Andrei
Mar 14 2013
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
14-Mar-2013 22:13, H. S. Teoh пишет:
 On Thu, Mar 14, 2013 at 06:09:26PM +0100, Andrej Mitrovic wrote:
 On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler. Unit tests can't be sure to
 verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries.

I think you're missing the point. The point is that concepts allow the compiler to deduce template correctness *without* instantiating it with every possible combination of types. Right now, we *don't* have concepts, and therefore the only way to ensure template correctness is to iterate over the exponential number of combinations of template arguments.

And if you create a library tool to try out all sensible combinations would that work for this use case of concepts? In essence you transform concept to some specification and feed it into a CTFE-able generatopr function. Then take the code out and apply mixin it put into a unittest. Sounds easy (if only DMD doesn't run out of memory in the process). -- Dmitry Olshansky
Mar 14 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
14-Mar-2013 22:55, H. S. Teoh пишет:
 On Thu, Mar 14, 2013 at 10:20:04PM +0400, Dmitry Olshansky wrote:
 14-Mar-2013 22:13, H. S. Teoh пишет:
 On Thu, Mar 14, 2013 at 06:09:26PM +0100, Andrej Mitrovic wrote:
 On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler. Unit tests can't be sure to
 verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries.

I think you're missing the point. The point is that concepts allow the compiler to deduce template correctness *without* instantiating it with every possible combination of types. Right now, we *don't* have concepts, and therefore the only way to ensure template correctness is to iterate over the exponential number of combinations of template arguments.

And if you create a library tool to try out all sensible combinations would that work for this use case of concepts? In essence you transform concept to some specification and feed it into a CTFE-able generatopr function. Then take the code out and apply mixin it put into a unittest. Sounds easy (if only DMD doesn't run out of memory in the process).

It's certainly possible, I think. Is it worth pursuing? Maybe.

It is as this won't require arguing with Walter, Andrei et al. and the other wopuld either use it or not but you both ways you'd have hard data.
 Here's a
 first crack at it:

 We'd need some way of listing (or generating a list of) all
 representative template arguments, say for example, a listing that
 includes input range, forward range, bidirectional range, etc.. Then we
 need a way to generically generate non-trivial instances of these ranges
 (otherwise the unittest could only cover trivial instances, like empty
 input range, empty forward range, etc., so the template being tested
 will not be verified for non-empty ranges!). The result then will be
 used to instantiate the template and run it through a battery of tests.

 Of course, the ranges themselves have arguments, so you'd need some kind
 of listing of representative types: char, int, float, string, etc., and
 have a way of generating non-trivial instances of each of these types,
 then use them to instantiate the range with. Maybe for each type also
 test it for const(T), immutable(T), etc..

 Then you'd have to cover nested ranges, so you'd need a way to specify
 how deep you want to go (e.g., a recent forward range bug of using =
 instead of .save will only manifest itself if you had a nested range of
 forward ranges -- you couldn't catch that just by running through
 non-nested ranges).

 As you can see, this quickly explodes in exponential number of
 combinations. So ultimately, maybe we still have to resort to
 hand-picked "representative" types.

No - just use some language (DSL!) for the specification instead of generating type-strings. Basically exactly the same thing you'd put into a concept if it was langauge feature. You'd have a spec written in this language per each concept: input range of type X, an infinite range of type Y, an output range for E, etc. Spec states unit tests (and not only) for any type satisfying a concept. The concept (spec) itself is parametrize on types and/or other concepts. Then your tests are kind of monte carlo - pick random (large number) X of full spectrum (infinite on types, but finite on meta-types) of type combinations that this template supports and run the generated unit tests for these. That pick (following the spec) should cover all of the rules in the concept. The types themselves should include dummies generated based on the spec and some real world stuff (predefined).
 But we can do better than the current ad-hoc scheme of writing unittests
 for whatever combination just occurred to the code writer (which usually
 misses a lot of corner cases). We should have a std.unittest module that
 contains lists of all numeric types (byte, int, long, float, double,
 real, etc.) with their respective non-trivial instances, as well as
 representative range types: {arrays, struct ranges, class ranges} x
 {input, forward, bidirection, ...}, along with non-trivial instances of
 them. Then provide some generic testing functions that iterate over each
 of these lists, that user-written unittests can call to instantiate and
 test their templates with.

Exactly. But I'd call for more high-callibre module as in std.testing.spec.
 There can also be a way of adding custom types to the lists, that the
 generic functions can pick up and include in their combinations to test.

 But the important thing is to collect these type lists in a single
 place, so that we can, for example, test std.algorithm functions that
 expect input ranges with *all* ranges in the input range list, and be
 reasonably certain that if it all passes, the chances for any more bugs
 are very slim. (Otherwise, std.algorithm.joiner may have good coverage
 but std.algorithm.cartesianProduct may have poor coverage, and there's
 lots of missed reuse opportunities for the test ranges used by the
 unittests.)

That would be a huge step forward but it's like collecting sets of strings and use their concatenation to define a required set of strings. Instead you could use a formal grammar and define much broader kinds of sets with less "lines"/"rules" (like even regular grammar does). -- Dmitry Olshansky
Mar 14 2013
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 8:50 AM, deadalnix wrote:
 This is usualy much better to have the compiler smash your mistake right into
 your face than discovering with a unittest much latter.

I wish to point out that semantic checking would not be done at compile time, only syntax checking.
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 15, 2013 at 12:37:00AM +0400, Dmitry Olshansky wrote:
 15-Mar-2013 00:27, Walter Bright пишет:

For the following program:
---------test.d-------------
import core.stdc.stdio;
public import std.whatever;

int main()
{
     printf("Success!\n");
     return 0;
}
----------------------------

Try compiling:

     dmd -cov test.d std\whatever -unittest

and examine std-whatever.lst.

We can do a lot, lot better before we need something better than
-cov.

Point taken. That doesn't detract us from: a) fixing issues with -cov It counts time a LOC is executed. Would nice to add instantations counter (determined at compile time) as well so as to see if declarations are all covered. That + CTFE-only counted as 0. b) unifying template fuzzy testing in Phobos We have lots of these wheels reinvented across Phobos alone. c) prototyping other higher-level tools to aid debugging generic code

d) factor out useful test data/objects (e.g. ranges of particular types, with particular sets of data, etc.) into a common place so that they can be reused across unittests. T -- "Maybe" is a strange word. When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.
Mar 14 2013
prev sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 14 March 2013 at 20:46:11 UTC, H. S. Teoh wrote:
 b) unifying template fuzzy testing in Phobos
 
 We have lots of these wheels reinvented across Phobos alone.

By the way, is there any theoretical way to separate compilation errors due to failed constraints from errors due to errors in template body? I can't imagine one now, but if it is possible, some really cool unit test helper module can be written (In fact I almost started writing it when remembered about this requirement)
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 07:00:47PM +0100, Dicebot wrote:
 On Thursday, 14 March 2013 at 17:26:18 UTC, Andrei Alexandrescu
 wrote:
Walter has measured coverage of Phobos unittests a couple of times,
it's very high. But I agree it would be nice to have it as a target.

Andrei


Beware the fallacy that 100% line coverage of a template == 100% coverage of correctness in *every possible instantiation*. Just because template X has 100% line coverage for !(int,int) does not necessarily mean it will work for !(int,string), for example. Or !(int,const(int)). Or !(const(int),int). Or any number of subtle but sometimes important combinations.
 Sarcasm aside, this brought me to an idea for utilities for template
 fuzzy testing  to check some instantiation combinations. Which is much
 more useful than plain line coverage check in case of templates. I
 have submitted pull request only a few weeks ago that fixed std.traits
 bug where template has failed to instantiate for function types (but
 not other types) despite 100% line coverage by unit test. It could
 have been checked automagically.
 
 Not sure what usage interface may be though.

I've written code like this before, though it definitely can use some refinement: struct MySet(ElemType) { ... } unittest { void test(T)(T sampleArgs) { auto set = MySet!T(sampleArgs); assert( ... /* test for MySet behaviour here */); } void testNumArray(T, U...)() { T[] data = [1,2,3,4,5]; test(data); testNumArray!(U); } void testCharArray(T, U...)() { T[] data = "abc"; test(data); testCharArray!(U); } testNumArray!(byte, ubyte, int, uint, long, ulong)(); testCharArray!(char, wchar, dchar, const(char), const(wchar), const(dchar), immutable(char), immutable(wchar), immutable(dchar))(); // Coverage is still not really complete; we'd need to // add struct and class, and nested arrays, etc.. } The fact that D actually lets you do this, is quite awesome. T -- He who laughs last thinks slowest.
Mar 14 2013
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/14/2013 8:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is semantically
 correct is a huge pain.

I don't understand that sentiment. (You're also mistaken in that only syntactic correctness can be tested in an uninstantiated template, not semantic correctness.) It means you're willing to ship code that is syntactically correct, but is not necessarily semantically correct and is completely untested at runtime. This is not a best practice at all. Also, dmd's -cov coverage testing will check for you what parts of templates were instantiated and what parts never were.
Mar 14 2013
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
09-Mar-2013 05:19, Brad Anderson пишет:
 On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter wrote:
        See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


       Are they full of it? Has it caused the problems they mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy).

In fact I'd *love* for C++ to take the concepts-lite path. Why? Because then we can see how it works out for them and probably steal some ideas, of course, porting the to D's static if workhorse. C++14 is just around the corner if they are actually able to ship standards that fast (as they plan). And even if concepts is a failure... well, it's C++ - I couldn't care less :) -- Dmitry Olshansky
Mar 12 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 03/14/13 10:26, Don wrote:
 On Saturday, 9 March 2013 at 03:50:29 UTC, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter wrote:
      Are they full of it? Has it caused the problems they mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

I think the hard-to-analyze argument is a good one. I've created an enhancement for some analysis we could do without too much work: http://d.puremagic.com/issues/show_bug.cgi?id=9715 (I think my bug report shows a bigger problem with static if, than is reported in the paper; the problems arise only when you have two static ifs in the same scope).

The gain from such checks would be minimal. Eg "return x.toray;". artur
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 06:56:56PM +0100, Andrej Mitrovic wrote:
 On 3/14/13, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 But if we have to go that far, then it begs the original question:
 why not have the compiler do that for us?

But where do you draw the line? There could be an unlimited number of permutations of how a template is instantiated. This would blow up compilation time by an unknown factor. And I doubt this would be simple to implement too.

But that was my point, if we had concepts, then the compiler could statically check the syntax of the template without needing to iterate over all combinations of types. Right now, we *have* to essentially check all combinations in unittests if we want to be sure that the template is instantiable in all cases. T -- Your inconsistency is the only consistent thing about you! -- KD
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 01:51:23PM -0400, Andrei Alexandrescu wrote:
 On 3/14/13 1:48 PM, H. S. Teoh wrote:
I don't agree. Phobos is a prime example. Does Phobos have unittests?
Yes, and lots of them. Does it still have non-compilable template
instantiations? Yes, because unittests can't cover all possibilities --
there are too many possible combinations of template arguments. There
are bound to be untested combinations which don't work but we're unaware
of.

If you found a few, that would be great. I don't think you'll have an easy time.

It's easier than you think. I've stumbled across a few before. All you have to do is to start instantiating things with various combinations of const, immutable, class-based ranges instead of structs, etc., and all those little corner cases will start showing up. T -- Never wrestle a pig. You both get covered in mud, and the pig likes it.
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 10:20:04PM +0400, Dmitry Olshansky wrote:
 14-Mar-2013 22:13, H. S. Teoh пишет:
On Thu, Mar 14, 2013 at 06:09:26PM +0100, Andrej Mitrovic wrote:
On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
This is an invalid argument. You can say the same thing for many
(most?) tests done by the compiler. Unit tests can't be sure to
verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries.

I think you're missing the point. The point is that concepts allow the compiler to deduce template correctness *without* instantiating it with every possible combination of types. Right now, we *don't* have concepts, and therefore the only way to ensure template correctness is to iterate over the exponential number of combinations of template arguments.

And if you create a library tool to try out all sensible combinations would that work for this use case of concepts? In essence you transform concept to some specification and feed it into a CTFE-able generatopr function. Then take the code out and apply mixin it put into a unittest. Sounds easy (if only DMD doesn't run out of memory in the process).

It's certainly possible, I think. Is it worth pursuing? Maybe. Here's a first crack at it: We'd need some way of listing (or generating a list of) all representative template arguments, say for example, a listing that includes input range, forward range, bidirectional range, etc.. Then we need a way to generically generate non-trivial instances of these ranges (otherwise the unittest could only cover trivial instances, like empty input range, empty forward range, etc., so the template being tested will not be verified for non-empty ranges!). The result then will be used to instantiate the template and run it through a battery of tests. Of course, the ranges themselves have arguments, so you'd need some kind of listing of representative types: char, int, float, string, etc., and have a way of generating non-trivial instances of each of these types, then use them to instantiate the range with. Maybe for each type also test it for const(T), immutable(T), etc.. Then you'd have to cover nested ranges, so you'd need a way to specify how deep you want to go (e.g., a recent forward range bug of using = instead of .save will only manifest itself if you had a nested range of forward ranges -- you couldn't catch that just by running through non-nested ranges). As you can see, this quickly explodes in exponential number of combinations. So ultimately, maybe we still have to resort to hand-picked "representative" types. But we can do better than the current ad-hoc scheme of writing unittests for whatever combination just occurred to the code writer (which usually misses a lot of corner cases). We should have a std.unittest module that contains lists of all numeric types (byte, int, long, float, double, real, etc.) with their respective non-trivial instances, as well as representative range types: {arrays, struct ranges, class ranges} x {input, forward, bidirection, ...}, along with non-trivial instances of them. Then provide some generic testing functions that iterate over each of these lists, that user-written unittests can call to instantiate and test their templates with. There can also be a way of adding custom types to the lists, that the generic functions can pick up and include in their combinations to test. But the important thing is to collect these type lists in a single place, so that we can, for example, test std.algorithm functions that expect input ranges with *all* ranges in the input range list, and be reasonably certain that if it all passes, the chances for any more bugs are very slim. (Otherwise, std.algorithm.joiner may have good coverage but std.algorithm.cartesianProduct may have poor coverage, and there's lots of missed reuse opportunities for the test ranges used by the unittests.) T -- Trying to define yourself is like trying to bite your own teeth. -- Alan Watts
Mar 14 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 03/14/13 16:05, monarch_dodra wrote:
 On Thursday, 14 March 2013 at 11:04:59 UTC, Artur Skawina wrote:
 On 03/14/13 10:26, Don wrote:
 On Saturday, 9 March 2013 at 03:50:29 UTC, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter wrote:
      Are they full of it? Has it caused the problems they mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

I think the hard-to-analyze argument is a good one. I've created an enhancement for some analysis we could do without too much work: http://d.puremagic.com/issues/show_bug.cgi?id=9715 (I think my bug report shows a bigger problem with static if, than is reported in the paper; the problems arise only when you have two static ifs in the same scope).

The gain from such checks would be minimal. Eg "return x.toray;".

I've already found plenty of such bugs in phobos, and wouldn't be surprised if this was one of its bigger sources of bugs. Sure, phobos is template and static "super heavy", given it is more or less the D-STL, but still. If the compiler can statically determine that a template branch simply *can't* compile, then the code should be turned down.

"If'. Sure, it is sometimes able to do that, but often enough this is impossible without actually instantiating the template. And often the error will be trivial to fix (typo etc), so it doesn't really matter. What's left is just a small fraction of all possible errors - catching them is good, but the gain isn't really that large.
 Having to instantiate a template just to check to make sure it is semantically
correct is a huge pain.

Yes, but see above. I'm not saying it shouldn't be done - only that it isn't such a big deal as it is made out to be. For example I'd estimate that most (ie >50%) of my mistakes wouldn't get caught, and I'm not that special. :) artur
Mar 14 2013
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 08:49:11PM +0100, Timon Gehr wrote:
 On 03/14/2013 06:48 PM, H. S. Teoh wrote:
...

We could, of course, automatically generate a very large number of
template argument combinations and check to see if they're
instantiable.  In fact, we could write unittests that loop over every
combination of a given list of types and instantiate the template to
be tested with them.  This is well within D's metaprogramming
capabilities.

...

But way behind state-of-the-art research in program validation.

Yes, which was my point. T -- MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 08, 2013 at 07:50:26PM -0800, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter wrote:
      Are they full of it? Has it caused the problems they mention
in
D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

I didn't read the paper, but I have to say that static if in D has been extremely, extremely useful in my code. Now that I've become acquianted with it, I can't live without it. It's pretty much a necessity when writing heavily-templated code. But given C++'s broken template design, I can see why its value may not have been appreciated by some people. D may still have its warts, but in terms of being a "better C++", I think it has done a superb job, especially in the area of templates and compile-time mechanisms. Static if + CTFE + sane template syntax = readable template code = total win for D over C++. T -- Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".
Mar 08 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter 
wrote:
        See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

       Are they full of it? Has it caused the problems they 
 mention
 in
 D?

I think most of the point made in this document are moot. Still static if in D don't define many corner cases that are implementation defined. But that don't change much unless you really go into tricky code. Most static if "just work", so this is really positive at the end !
Mar 08 2013
prev sibling next sibling parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 09 Mar 2013 01:48:55 +0100
"DypthroposTheImposter" <mcbracket gmail.com> wrote:

         See the static_if paper here:
 
 http://isocpp.org/forums
 
 Under the post "constraints and static if" there is a link to a
 document about
 static_if
 
 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg
 
        Are they full of it? Has it caused the problems they mention
 in
 D?

Does that document exist somewhere in a the form of a real web page? Or at least *any* real document format?
Mar 08 2013
parent reply 1100110 <0b1100110 gmail.com> writes:
On 03/09/2013 01:33 AM, Nick Sabalausky wrote:
 On Sat, 9 Mar 2013 02:08:07 -0500
 Nick Sabalausky<SeeWebsiteToContactMe semitwist.com>  wrote:

 On Sat, 09 Mar 2013 01:48:55 +0100
 "DypthroposTheImposter"<mcbracket gmail.com>  wrote:

          See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

         Are they full of it? Has it caused the problems they mention
 in
 D?

Does that document exist somewhere in a the form of a real web page? Or at least *any* real document format?

To be clear, that's not a veiled attack on anything. I really *am* just simply asking if there's a link for that anywhere to a real file (html, pdf, text, wordperfect, gif, hell whatever.)

Mar 09 2013
parent 1100110 <0b1100110 gmail.com> writes:
On 03/09/2013 08:09 PM, Nick Sabalausky wrote:
 On Sat, 09 Mar 2013 12:28:37 -0600
 1100110<0b1100110 gmail.com>  wrote:

 On 03/09/2013 01:33 AM, Nick Sabalausky wrote:
 On Sat, 9 Mar 2013 02:08:07 -0500
 Nick Sabalausky<SeeWebsiteToContactMe semitwist.com>   wrote:

 On Sat, 09 Mar 2013 01:48:55 +0100
 "DypthroposTheImposter"<mcbracket gmail.com>   wrote:

           See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

          Are they full of it? Has it caused the problems they
 mention in
 D?

Does that document exist somewhere in a the form of a real web page? Or at least *any* real document format?

To be clear, that's not a veiled attack on anything. I really *am* just simply asking if there's a link for that anywhere to a real file (html, pdf, text, wordperfect, gif, hell whatever.)


Sure, please. If you could either post it here, or on the web, or email nick1 at semitwist dot com, or whatever works for you that'd be great. :)

http://1100110.in/static-if.pdf (Powered by vibe.d =P)
Mar 09 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 9 Mar 2013 02:08:07 -0500
Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> wrote:

 On Sat, 09 Mar 2013 01:48:55 +0100
 "DypthroposTheImposter" <mcbracket gmail.com> wrote:
 
         See the static_if paper here:
 
 http://isocpp.org/forums
 
 Under the post "constraints and static if" there is a link to a
 document about
 static_if
 
 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg
 
        Are they full of it? Has it caused the problems they mention
 in
 D?

Does that document exist somewhere in a the form of a real web page? Or at least *any* real document format?

To be clear, that's not a veiled attack on anything. I really *am* just simply asking if there's a link for that anywhere to a real file (html, pdf, text, wordperfect, gif, hell whatever.)
Mar 08 2013
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 9 March 2013 at 03:50:29 UTC, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, 
 DypthroposTheImposter wrote:
 Are they full of it? Has it caused the problems they mention 
 in D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third Guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

Since C++ is so deeply etched with C's previous limitations and problems, it also got the preprocessor, which when you think about it does the same thing (until you've actually used it); Now you've got preprocessor #ifdef's mixed with compile time execution determining what should and shouldn't be compiled, it is a very messy pile of crud. Even IF static_if gets working and accepted in C++, it's core requirement to be 100% backwards compatible with all previous code ensures it's growth will forever be hampered. Maybe if they could get their template system fixed (which will never happen) then static_if would work much better. God I hate C++.
Mar 08 2013
prev sibling next sibling parent "simendsjo" <simendsjo gmail.com> writes:
On Saturday, 9 March 2013 at 09:12:30 UTC, Jouko Koski wrote:
 "Walter Bright"  wrote:

 Many of the criticisms in the paper are addressed by our 
 positive experience with static if in D.

Sometimes I do find it confusing that { does or does not introduce a new scope in a very similar-looking contexts.

Is there more constructs than static if that doesn't create a scope?
Mar 09 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 9 March 2013 at 09:41:42 UTC, simendsjo wrote:
 On Saturday, 9 March 2013 at 09:12:30 UTC, Jouko Koski wrote:
 "Walter Bright"  wrote:

 Many of the criticisms in the paper are addressed by our 
 positive experience with static if in D.

Sometimes I do find it confusing that { does or does not introduce a new scope in a very similar-looking contexts.

Is there more constructs than static if that doesn't create a scope?

version, debug, release, const/immutable/inout/static/whatever{} .
Mar 09 2013
prev sibling next sibling parent "simendsjo" <simendsjo gmail.com> writes:
On Saturday, 9 March 2013 at 09:52:55 UTC, deadalnix wrote:
 On Saturday, 9 March 2013 at 09:41:42 UTC, simendsjo wrote:
 On Saturday, 9 March 2013 at 09:12:30 UTC, Jouko Koski wrote:
 "Walter Bright"  wrote:

 Many of the criticisms in the paper are addressed by our 
 positive experience with static if in D.

Sometimes I do find it confusing that { does or does not introduce a new scope in a very similar-looking contexts.

Is there more constructs than static if that doesn't create a scope?

version, debug, release, const/immutable/inout/static/whatever{} .

I see const++ as well as property as qualifiers and don't assume a new scope. Didn't think of version++ though :)
Mar 09 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 9 March 2013 at 09:41:42 UTC, simendsjo wrote:
 On Saturday, 9 March 2013 at 09:12:30 UTC, Jouko Koski wrote:
 "Walter Bright"  wrote:

 Many of the criticisms in the paper are addressed by our 
 positive experience with static if in D.

Sometimes I do find it confusing that { does or does not introduce a new scope in a very similar-looking contexts.

Is there more constructs than static if that doesn't create a scope?

"Labeled scopes" (ironically) don't create scopes. Eg: //---- some_label: { int a; //Code code code } a = 5; goto some_label; //---- That doesn't actually create a new scope, and that assignement is legal game. This is from the official documentation, so it is not a bug. I can't, for the life of me, understand why it is that way, in particular, since it deviates from C. I see it as a "never better, sometimes worst" approach. I've tried to ask about it before, but I best, the answer I got was "works as documented", but still have no idea on the why :/ ??? And since goto is "evil", I think very few people care, so getting any kind of activity about this is hard.
Mar 09 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/8/13 7:48 PM, DypthroposTheImposter wrote:
 See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


 Are they full of it? Has it caused the problems they mention
 in
 D?

Wow. That's quite out of character for Bjarne. I think it's quite a poor piece. Andrei
Mar 09 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/9/13 10:22 AM, monarch_dodra wrote:
 BTW, in regards to template constraints (not the rest), he does have a
 point. We have raised the exact same issues here on the boards more than
 once.

What was the problem for D again? Andrei
Mar 09 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/9/2013 8:22 AM, monarch_dodra wrote:
 Things can get evenmore hairy,when you are operating on 2 different types.

This is why complex expressions can be encapsulated as functions.
 One last thing to keep in mind is that having constraints allows hijacking,
 whereas concpets/static asserts resolve as an ambigus call.

I don't see where the hijacking comes in.
Mar 09 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/10/2013 9:05 AM, monarch_dodra wrote:
 Yes, but that doesn't solve the "root" issue of meaningfulness. Sure, instead
of
 having a 5 line constraint, it's only a single line, but are these any better?

 sort(R, Scheme)(...)
 if(isRandomAccessRangeWithComparableElementsAndAssignableElementsIfStableSchemeOrSwapableElementsOtherwise!R)


 or

 sort(...)
      if(meetsSortConstraints!R)

 Neither are really any better for the end user.

I don't think this issue is any different from selecting a name for any function that does something non-trivial. It's why we have functions - to encapsulate complexity.
 This is why I don't think constraints should be used at all for validating
 arguments. [concepts|static asserts] are much better, and when combined with
 static if, become incredibly powerful:

 sort(R, Scheme)(...)
 {
      static assert (isRandomAccessRange!T);
      static assert (is(typeof(r.front < r.front)));
      static if (Scheme == Stable)
          static assert (hasAssignableElements!T);
      else
          static assert (hasSwapableElements!T);

      //Code Code Code
 }

 Much clearer, and the diagnostics much better.

Whether it's clearer or not is all in how you choose to organize/write them. Also, the static assert model does not enter into overload selection, while constraints do.
 One last thing to keep in mind is that having constraints allows hijacking,
 whereas concpets/static asserts resolve as an ambigus call.

I don't see where the hijacking comes in.

The problem with contraints is that it merelly eliminates functions from the pool of overloads. If you attemp to call a function with invalid parameters, then you may end up accidentally calling something you didn't want to. Imagine: //---- module a; void do_it(R)(R r) if (isForwardRange!R) { //Do something to r } //---- module b; void do_it(T)(T t) { //Do something completely different } //---- import a, b; void main() { MyInputRange myInputRange; //Oops! I didn't realize it's only input: do_it(myInputRange); //meant to call a.do_it; } //---- With the current scheme of constraints, this will end up calling b.do_it, without any ambiguity. You may or may not consider that is "hijacking", but it is error prone.

That is not hijacking. Hijacking is when a template or function **from an unrelated scope** matches better and steals the call away. When templates/functions are in the same scope, it is just a usual overloading issue. It's not an undue burden on the programmer to pay attention to the overloads in the same scope. He's got to do that anyway.
Mar 10 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/11/2013 8:43 PM, deadalnix wrote:
 Yes, that is the idea. It seems really cool.

It's interfaces without the vtable[]. It's still solely based on type signatures. D constraints make pretty much anything that can be computed at compile time a testable gate.
Mar 11 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/11/2013 10:49 PM, deadalnix wrote:
 And this is very similar to our template constraint system and static if,
except
 we are meta here (ie, meta dynamic typing vs meta static typing).

The issue I have with it is it is only able to express concepts as types. Values are important, too, as they are also parameters to templates.
Mar 11 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/11/2013 11:17 PM, deadalnix wrote:
 Both definitively have advantages and drawbacks. Does the C++ team have any
plan
 on making concept work with values ?

I don't know.
 Concepts are for instance THE perfect match for all kind of range we have.

Not for infinite ranges, which depend on empty returning a compile time value.
Mar 11 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/12/2013 12:13 AM, deadalnix wrote:
 On Tuesday, 12 March 2013 at 06:34:50 UTC, Walter Bright wrote:
 Not for infinite ranges, which depend on empty returning a compile time value.

another symptom of that poor design choice than an actual issue with concepts.

Nevertheless, it shows a weakness of concepts in that concepts are unable to express ideas about values - only types.
Mar 12 2013
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/12/2013 1:14 AM, deadalnix wrote:
 On Tuesday, 12 March 2013 at 07:59:49 UTC, monarch_dodra wrote:
 On Tuesday, 12 March 2013 at 07:13:11 UTC, deadalnix wrote:
 On Tuesday, 12 March 2013 at 06:34:50 UTC, Walter Bright wrote:
 Not for infinite ranges, which depend on empty returning a compile time value.

It was already discussed int he past that this was a bad idea. I think that is another symptom of that poor design choice than an actual issue with concepts.

When was it discussed that this was a bad idea?


I don't think that thread conclusively determined it was a bad idea.
Mar 12 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 12, 2013 at 12:28:07PM -0400, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 16:02:24 +0100
 "TommiT" <tommitissari hotmail.com> wrote:
 
 On Tuesday, 12 March 2013 at 13:44:35 UTC, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 12:51:03 +0100
 "TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept.

I *strongly* disagree. A much as I love ranges (for example), their duckiness is the one thing I consider to be a huge mistake.

The problem with having to explicitl specify that a type implements a certain concept, is the resulting strong coupling between the concept definition and the type. This prevents "happy accidents" like the following from happening: Alice and Bob write libraries without knowing anything about each other or each other's code. Alice implements the following in her library: concept IntegerLike { ... } void foo(IntegerLike N)(N n) { } Bob implements the following in his library: struct SafeInt { ... } Later Bob realizes that Alice has written this cool function foo which accepts his type SafeInt as an argument because SafeInt just so happens to fulfill the requirements of the IntegerLike concept defined in Alice's library. Although, the majority of concepts should come from the standard library.

"Happy accidents" is nothing more than another way of saying "Shit fucked up, but by pure dumb luck there was no damage". It's an absolutely *terrible* thing to encourage and design for. You may as well just go dynamic all the way, a la ActionScript 2 or Python - it's all the same "let random things happen by accident and blindly hope it just happens to turn out correct" philosophy. Design-by-accident is an anti-pattern. To me more specific, the problem with duck typing is that it falsely assumes that name+signature uniquely defines semantics (which is clearly not a valid assumption). Avoiding accidental screwups under duck typing *is* feasible if there's only a few well-known duck types that are ever in play (ex: our entire list of available duck types is a handful of phobos-defined ranges and basically nothing else). But it does not scale: The likelihood of accidental fuckups is multiplied with each additional duck type in existence, with non-stdlib duck types carrying a greater "accidental fuck up" weight.

I see it from another perspective: I've had to deal with proprietary libraries that defined types that couldn't be used with a particular container type, just because the container type expects the item type to implement a particular interface, but it doesn't. But actually, it *does* have the requisite members to implement that interface; it just didn't *say* it implemented that interface. So there's the need for Yet Another Useless Java-style Wrapper Class just to work around this nonsense. Duck-typing solves this problem. Of course, full-out ducktyping has its own problems, like you said; but there needs to be a way of rewriting APIs such that you could say "type T doesn't implement interface I right now, but actually, if you rewrite T.A to T.X and T.B to T.Y, then T implements interface I just fine". Though with D, I suspect this may actually be possible via alias this: struct RewireInterface(T, Interface, Tuple!(string,string)... rewrites) { T t; alias t this; foreach (rewrite; rewrites) { alias rewrite[0] = rewrite[1]; } } OK, maybe not. But the foreach could be replace with a suitable recursive template so that the generated aliases are at the top-level in RewireInterface. Probably some other hack is needed to work around the need for Tuple in the compile-time parameters, which I'm pretty sure DMD rejects right now. But assuming all this can be worked around, you could do something like this: struct StraitJacketedProprietaryItem { int propX() { ... } int propY() { ... } } concept MyInterface { int myX(); int myY(); } alias NonStraitJacketedItem = RewireInterface!( StraitJacketedProprietaryItem, MyInterface, "myX", "propX", "myY", "propY" ); assert(NonStraitJacketedItem implements MyInterface); OK, lots of pseudo-code going on here, but you get the idea. T -- It is widely believed that reinventing the wheel is a waste of time; but I disagree: without wheel reinventers, we would be still be stuck with wooden horse-cart wheels.
Mar 12 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Tue, 12 Mar 2013 09:57:44 -0700
"H. S. Teoh" <hsteoh quickfur.ath.cx> wrote:

 On Tue, Mar 12, 2013 at 12:28:07PM -0400, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 16:02:24 +0100
 "TommiT" <tommitissari hotmail.com> wrote:
 
 On Tuesday, 12 March 2013 at 13:44:35 UTC, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 12:51:03 +0100
 "TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept.

I *strongly* disagree. A much as I love ranges (for example), their duckiness is the one thing I consider to be a huge mistake.

The problem with having to explicitl specify that a type implements a certain concept, is the resulting strong coupling between the concept definition and the type. This prevents "happy accidents" like the following from happening: Alice and Bob write libraries without knowing anything about each other or each other's code. Alice implements the following in her library: concept IntegerLike { ... } void foo(IntegerLike N)(N n) { } Bob implements the following in his library: struct SafeInt { ... } Later Bob realizes that Alice has written this cool function foo which accepts his type SafeInt as an argument because SafeInt just so happens to fulfill the requirements of the IntegerLike concept defined in Alice's library. Although, the majority of concepts should come from the standard library.

"Happy accidents" is nothing more than another way of saying "Shit fucked up, but by pure dumb luck there was no damage". It's an absolutely *terrible* thing to encourage and design for. You may as well just go dynamic all the way, a la ActionScript 2 or Python - it's all the same "let random things happen by accident and blindly hope it just happens to turn out correct" philosophy. Design-by-accident is an anti-pattern. To me more specific, the problem with duck typing is that it falsely assumes that name+signature uniquely defines semantics (which is clearly not a valid assumption). Avoiding accidental screwups under duck typing *is* feasible if there's only a few well-known duck types that are ever in play (ex: our entire list of available duck types is a handful of phobos-defined ranges and basically nothing else). But it does not scale: The likelihood of accidental fuckups is multiplied with each additional duck type in existence, with non-stdlib duck types carrying a greater "accidental fuck up" weight.

I see it from another perspective: I've had to deal with proprietary libraries that defined types that couldn't be used with a particular container type, just because the container type expects the item type to implement a particular interface, but it doesn't. But actually, it *does* have the requisite members to implement that interface; it just didn't *say* it implemented that interface. So there's the need for Yet Another Useless Java-style Wrapper Class just to work around this nonsense. Duck-typing solves this problem.

Duck-typing solves that problem at the cost of potentially introducing silent bugs. But who says it can only be solved that way? The problem is trivially solvable *without* the downsides of duck-typing. Just make the ducks explicit instead of implicit. All you need is something analogous to "cast": For example, an "(a|A)ssumeImplements" wrapper. Or maybe even just make it an extra feature of "cast": import std.typecons : assumeImplements, AssumeImplements; concept IBob { Some syntax to require "void bob()" } struct BobType : IBob { void bob() {...} } struct AliceType { void bob() {...} } // *Explicit* duck-typing alias AssumeImplements!(IBob, AliceType) AliceTypeIBob; void useBob(IBob ib) {...} // Or whatever syntax void main() { BobType b; useBob(b); // Ok AliceTypeIBob ab; useBob(ab); // Ok AliceType a; useBob(a); // Fails // Ok, *explicit* duck-typing useBob(assumeImplements!IBob(a)); // Maybe ok, semi-explicit duck-typing useBob(cast(IBob)a); }
 Of course, full-out ducktyping has its own problems, like you said;
 but there needs to be a way of rewriting APIs such that you could say
 "type T doesn't implement interface I right now, but actually, if you
 rewrite T.A to T.X and T.B to T.Y, then T implements interface I just
 fine". Though with D, I suspect this may actually be possible via
 alias this:
 
 	struct RewireInterface(T, Interface, Tuple!(string,string)...
 rewrites) {
 		T t;
 		alias t this;
 		foreach (rewrite; rewrites) {
 			alias rewrite[0] = rewrite[1];
 		}
 	}
 

Interesting.
Mar 12 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 16:59:41 UTC, H. S. Teoh wrote:
 On Tue, Mar 12, 2013 at 12:28:07PM -0400, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 16:02:24 +0100
 "TommiT" <tommitissari hotmail.com> wrote:
 
 On Tuesday, 12 March 2013 at 13:44:35 UTC, Nick Sabalausky 
 wrote:
 On Tue, 12 Mar 2013 12:51:03 +0100
 "TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept.

I *strongly* disagree. A much as I love ranges (for example), their duckiness is the one thing I consider to be a huge mistake.

The problem with having to explicitl specify that a type implements a certain concept, is the resulting strong coupling between the concept definition and the type. This prevents "happy accidents" like the following from happening: Alice and Bob write libraries without knowing anything about each other or each other's code. Alice implements the following in her library: concept IntegerLike { ... } void foo(IntegerLike N)(N n) { } Bob implements the following in his library: struct SafeInt { ... } Later Bob realizes that Alice has written this cool function foo which accepts his type SafeInt as an argument because SafeInt just so happens to fulfill the requirements of the IntegerLike concept defined in Alice's library. Although, the majority of concepts should come from the standard library.

"Happy accidents" is nothing more than another way of saying "Shit fucked up, but by pure dumb luck there was no damage". It's an absolutely *terrible* thing to encourage and design for. You may as well just go dynamic all the way, a la ActionScript 2 or Python - it's all the same "let random things happen by accident and blindly hope it just happens to turn out correct" philosophy. Design-by-accident is an anti-pattern. To me more specific, the problem with duck typing is that it falsely assumes that name+signature uniquely defines semantics (which is clearly not a valid assumption). Avoiding accidental screwups under duck typing *is* feasible if there's only a few well-known duck types that are ever in play (ex: our entire list of available duck types is a handful of phobos-defined ranges and basically nothing else). But it does not scale: The likelihood of accidental fuckups is multiplied with each additional duck type in existence, with non-stdlib duck types carrying a greater "accidental fuck up" weight.

I see it from another perspective: I've had to deal with proprietary libraries that defined types that couldn't be used with a particular container type, just because the container type expects the item type to implement a particular interface, but it doesn't. But actually, it *does* have the requisite members to implement that interface; it just didn't *say* it implemented that interface. So there's the need for Yet Another Useless Java-style Wrapper Class just to work around this nonsense. Duck-typing solves this problem. Of course, full-out ducktyping has its own problems, like you said; but there needs to be a way of rewriting APIs such that you could say "type T doesn't implement interface I right now, but actually, if you rewrite T.A to T.X and T.B to T.Y, then T implements interface I just fine". Though with D, I suspect this may actually be possible via alias this: struct RewireInterface(T, Interface, Tuple!(string,string)... rewrites) { T t; alias t this; foreach (rewrite; rewrites) { alias rewrite[0] = rewrite[1]; } } OK, maybe not. But the foreach could be replace with a suitable recursive template so that the generated aliases are at the top-level in RewireInterface. Probably some other hack is needed to work around the need for Tuple in the compile-time parameters, which I'm pretty sure DMD rejects right now. But assuming all this can be worked around, you could do something like this: struct StraitJacketedProprietaryItem { int propX() { ... } int propY() { ... } } concept MyInterface { int myX(); int myY(); } alias NonStraitJacketedItem = RewireInterface!( StraitJacketedProprietaryItem, MyInterface, "myX", "propX", "myY", "propY" ); assert(NonStraitJacketedItem implements MyInterface); OK, lots of pseudo-code going on here, but you get the idea. T

D current compile time capabilities already allow this kind of stuff. I don't see concept as a good idea to introduce into D right now, but definitively something to look at for the future.
Mar 13 2013
prev sibling next sibling parent d coder <dlang.coder gmail.com> writes:
--485b3970d5ce8dade804d77f0b4a
Content-Type: text/plain; charset=ISO-8859-1

Greetings

I believe the paper takes a contrived route to criticize "static if". It
takes some bad code examples which are not obvious use cases of "static if"
and then goes on to say that the resultant code is not good. I think the
code example to begin with was not good.

Regards
- Puneet

--485b3970d5ce8dade804d77f0b4a
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div>Greetings</div><div><br></div>I believe the paper takes a contrived ro=
ute to criticize &quot;static if&quot;. It takes some bad code examples whi=
ch are not obvious use cases of &quot;static if&quot; and then goes on to s=
ay that the resultant code is not good. I think the code example to begin w=
ith was not good.<div>

<br></div><div>Regards</div><div>- Puneet</div><div><br><div><br></div><div=
<br></div></div>

--485b3970d5ce8dade804d77f0b4a--
Mar 09 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 9 March 2013 at 14:09:39 UTC, Andrei Alexandrescu 
wrote:
 On 3/8/13 7:48 PM, DypthroposTheImposter wrote:
 See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


 Are they full of it? Has it caused the problems they mention
 in
 D?

Wow. That's quite out of character for Bjarne. I think it's quite a poor piece. Andrei

I think there is a bit of forced bashing in there, but the main point is that static if prevents eager semantic validation of templated code. In C++, if you write a semantically incorrect template, then the compiler can catch it. This is not possible once static ifs enter the picture. I know for a fact I've had the C++ compiler catch a fair amount of errors for me, whereas it takes actual intantiation for the D compiler to catch said errors (and I've seen a few such errors in phobos). I think the main point is not "is static if good or not": I think D has clearly demonstrated how powerful it can be. However, to the question of "is it the right move for C++, whith all of its heritage, to adopt static if?" As a C++ developper, honestly, I'm not sure it is. I think that's where the piece is comming from, in maybe a clumsy manner. C++ took a different road with its "horrible" template syntax, but it took that road. I think it is better to improve that road (with concepts, for example), then try to move the current paradigm. That's might point of view having mostly a "full C++" background, and having learned D. The bottom line, I think, is that it is an error to think of D as "just" improved C++, and that what might work for D might not be what is best for C++. It doesn't mean that static if (or other D constructs) are bad in and out of themselves. I wouldn't take this piece as a "direct attack" on D. ... BTW, in regards to template constraints (not the rest), he does have a point. We have raised the exact same issues here on the boards more than once.
Mar 09 2013
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 9 March 2013 at 14:49:36 UTC, d coder wrote:
 Greetings

 I believe the paper takes a contrived route to criticize 
 "static if". It takes some bad code examples which are not 
 obvious use cases of "static if" and then goes on to say that 
 the resultant code is not good. I think the code example to 
 begin with was not good.

Agreed. Just barely started reading it and it appears they're nit-picking about something they would have trouble with if it was scoped or not, but more importantly they aren't considering something we would do automatically. If you declare in one, you declare in the other, only difference may be a few details like storage types, removing some of the problems entirely; So he's attacking something that could be done in the preprocessor anyways; Or maybe he's attacking bad coding style but isn't expressly saying it? [quote] Conditional compilation, the selective inclusion of statements in a translation unit, is a conventional example. Consider a simple example of introducing some declarations, depending on whether the size of some type, T. static if (sizeof(T)==8) { void fun(); void gun(int); } else { void gun(); typedef tx int; } The semantics of the program are this: if sizeof(T)==8, the compiler will parse the statements in the “then” branch, and will tokenize and brace-match the declarations in the else branch. Those other declarations would be uninterpreted by the compiler. Note that unlike normal if statements, the braces enclosing the conditionally compiled statements do not introduce a new scope. Those declarations are declared into the scope enclosing the static if block. This difference makes code written using static if harder to read and understand—modulating between static and non-static ifs in a single block provides ample opportunities for confution and mistakes. The effect of this declaration is to conditionally modify the current scope with a set of new declarations. How can we know, later in the program, which version of gun we should use, or whether tx is defined or not? Any use of those declarations would also need to be wrapped. static if (sizeof(T)==8) gun(32); else gun(); static if (sizeof(T)==8) { long n = x; } static if (sizeof(T)!=8) { tx n = x; } Thus, the use of static_if for conditional compilation is viral. The impact of conditional parsing on program analysis tools is substantial. While the feature may be easily implemented as part of the translation process, program analysis tools have traditionally struggled with conditional declarations. The inclusion of multiple variants (via, e.g., preprocessor conditions) and simultaneous repersentation within a single program model is still an open problem in the source code analysis communities. Adopting static if will make analysis harder, not easier. [/quote] And I'm sure that using the preprocessor keeps things simple right? Geez let's take a C/C++ version of that... Preprocessor tokens may be off, but the point should get across... :P #ifdef X void fun(); void gun(int); #else void gun(); typedef tx int; #endif And #ifdef X gun(32); #else gun(); #endif #ifdef X long n = x; #endif #ifndef X tx n = x; #endif [quote] We have already heard suggestions of static_for and static_while. Can static_switch be far behind? C++ would become a low-level, unprincipled hackers’ favorite playground. In our opinion, if you want compile-time computation, look to constexpr, which does have a sane and typesafe underlying model. If we do not provide a static_for, hackers will simply make one out of static_if or fake equivalents. [/quote] C++ is just as low level as C, this statement is useless. Being against 'static_for' is kinda dumb since if you think about it, it just unrolls the loop ahead of time instead of optimization, other than that it shouldn't do anything odd. I'll agree not to add static_for only because it's not really needed. [quote] The semantics of static_if are to tokenize the branch not taken. If the condition is dependent, as it is in the statements above, then the compiler must not parse either branch. Both branches are tokenized since either one could contain compiler-specific extensions—or both, or neither. That won’t be known until both branches would have been fully parsed. <snip> Consider the real world impact of this design choice. The inability of the compiler to parse the branches of the compiler means that the library writer will need to instantiate every branch of the template just to ensure that the syntax is correct and that no spelling errors have been made. Today, this is done, to a large extent, by the compiler [/quote] In C++ you need to have EVERYTHING loaded (declarations, etc) loaded before you can compile anything, Unlike in D where all tokens effectively have one meaning as intended, so the whole template issues aren't an issue. Seems like they're just opening their own cans of worms :P [quote] The trailing if clause enforces a requirement that T must be convertible to the value_type of I. We most strongly agree that some mechanism is needed for constraining templates, this is particular syntax leaves much to be desired. It is particularly verbose, and leaves the entire body of the template unchecked. The body must only be tokenized because the static condition could guard the instantiation against compiler-specific extensions in the nested code. That fact would only be ascertainable after the entire body is parsed. [/quote] Deja-vu, until recently (C++11) when they changed 'auto' to accept any type didn't they have to be super verbose everywhere anyways? Verboseness shouldn't matter in templates so much as it's user code that needs to be clean. Microsoft core teams admit their STL they write and maintain is ugliest and basically illegible to anyone outside the team; Although template structure as C++ is and their STL doesn't help much. [quote] The static if feature might also be used to support overloading. Below is an implementation of advance. <snip> Because static if only allows for Boolean decisions, overloading on a set of overlapping constraints requires the programmer to write bounding predicates like those above (e.g., input iterator but not bidirectional, bidirectional but not random access, etc...). This model of overloading is brittle, error-prone, verbose, and defines a “closed world”. No other overloads may be considered without modifying the constraints on the existing declarations in order to ensure consistency. Declarations might be condensed using else clauses, but this is only cosmetic. [/quote] *gasp* Walter! Did you know static if only allows boolean decisions! My god our static if MUST is be error-prone and brittle, a 'closed world'! *Note sarcasm* I'll agree a modification for handling nested static if's or something could be nice, but it's not unmanageable if you keep it relatively small. Hell what am I talking about? People go above and beyond a language to do stuff I wouldn't even consider, like a full x86 emulator in JavaScript.. [quote] The use of static if might also be used to reorder data structures for tighter alignment, but this is a potentially dangerous idea that could lead to bugs that are exceptionally difficult to diagnose and fix. [/quote] Doesn't he mean the pre-processor? #define max(x,y) x > y ? x : y int a = 1, b = 2; z = max(a++, b++); struct X { #ifdef TIGHT int x; char y[100]; #else char y[100]; int x; #endif } The largest complaint he has is managing tokens and being able to figure out what is what; In short previous bad decisions on the language HE HIMSELF MADE are preventing potential growth of the language making static if in his mind, unmanageable, yet you can do anything with the preprocessor (well, no CTFE...).
Mar 09 2013
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.net> writes:
On Saturday, 9 March 2013 at 14:09:39 UTC, Andrei Alexandrescu 
wrote:
 Wow. That's quite out of character for Bjarne. I think it's 
 quite a poor piece.

I agree. I stopped reading at "The purpose of this paper is to examine the negative impact of the static if proposal [...]". Not "the impact", but "the *negative* impact". That doesn't exactly set the stage for a very nuanced discussion. Lars
Mar 09 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 9 March 2013 at 16:05:59 UTC, Andrei Alexandrescu 
wrote:
 On 3/9/13 10:22 AM, monarch_dodra wrote:
 BTW, in regards to template constraints (not the rest), he 
 does have a
 point. We have raised the exact same issues here on the boards 
 more than
 once.

What was the problem for D again? Andrei

"Problem" is a big word. But basically, the combination: "if your template type doesn't meet template constraints, where did it fail?" We don't have that, but concepts do. This is part of the: - Should we use constraints only for overloads or also to validate types? - Should we instead use static asserts to find out why the argument type is wrong? That said, concepts (afaik) don't handle overloads... ...which brings us to managing said overloads. Basically, right now, if you want overloads, you have to repeat the conditions in a: if (a && !b) ... if (b && !c) ... if (c) This is minor, but it does not scale very well, especially if "a", "b" and "c" are complicated. In algorithm, some of our constraints for sort/find can be 5 lines long. At this point, can we still say that they are readable tools for users, or an implementation tool for dispatch? Things can get evenmore hairy,when you are operating on 2 different types. One last thing to keep in mind is that having constraints allows hijacking, whereas concpets/static asserts resolve as an ambigus call. ---- Not a breaking issue or anything, just more of an anoyance. I wanted to point out that we ourselves have already had talks about the points raised in said article. Regardless, that was not the main point that I was trying to get accross. My main point was simply that what works for D might not be best for C++.
Mar 09 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 9 March 2013 at 15:22:55 UTC, monarch_dodra wrote:
 On Saturday, 9 March 2013 at 14:09:39 UTC, Andrei Alexandrescu 
 wrote:
 On 3/8/13 7:48 PM, DypthroposTheImposter wrote:
 See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to 
 a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


 Are they full of it? Has it caused the problems they mention
 in
 D?

Wow. That's quite out of character for Bjarne. I think it's quite a poor piece. Andrei

I think there is a bit of forced bashing in there, but the main point is that static if prevents eager semantic validation of templated code. In C++, if you write a semantically incorrect template, then the compiler can catch it. This is not possible once static ifs enter the picture. I know for a fact I've had the C++ compiler catch a fair amount of errors for me, whereas it takes actual intantiation for the D compiler to catch said errors (and I've seen a few such errors in phobos). I think the main point is not "is static if good or not": I think D has clearly demonstrated how powerful it can be. However, to the question of "is it the right move for C++, whith all of its heritage, to adopt static if?" As a C++ developper, honestly, I'm not sure it is. I think that's where the piece is comming from, in maybe a clumsy manner. C++ took a different road with its "horrible" template syntax, but it took that road. I think it is better to improve that road (with concepts, for example), then try to move the current paradigm. That's might point of view having mostly a "full C++" background, and having learned D. The bottom line, I think, is that it is an error to think of D as "just" improved C++, and that what might work for D might not be what is best for C++. It doesn't mean that static if (or other D constructs) are bad in and out of themselves. I wouldn't take this piece as a "direct attack" on D. ... BTW, in regards to template constraints (not the rest), he does have a point. We have raised the exact same issues here on the boards more than once.

The more I think of it, the more this whole duck typing for templates is probably a bad solution because we lack tool to express « meta types ».
Mar 09 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 9 March 2013 at 17:51:31 UTC, Ali Çehreli wrote:
 On 03/09/2013 03:15 AM, Artur Skawina wrote:

   - static-if not creating scopes /is/ confusing, but what

     alternative?

I am surprised that << and >> are never mentioned: static_if >> void foo(); << Problem solved. ;) Ali

static if(condition) « void foo(); » Let's do it with style ;)
Mar 09 2013
prev sibling next sibling parent =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim gmail.com> writes:
--bcaec54ee030eeaea304d781d970
Content-Type: text/plain; charset=UTF-8

Note that there will be a teleconference Tuesday with one important point:
 "Discuss whether to continue work on static if, or to focus work on
concepts lite."
See:
https://groups.google.com/a/isocpp.org/forum/#!topic/concepts/AMVFwQGgS3c

I'm pointing that in case Alexandrescu and Walter didn't know and want to
defend their paper.

Joel Lamotte

--bcaec54ee030eeaea304d781d970
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Note that there will be a teleconference Tuesday with one =
important point:<div>=C2=A0&quot;<span style=3D"font-family:arial,sans-seri=
f;font-size:12.727272033691406px;line-height:16.988636016845703px">Discuss =
whether to continue work on static if, or to focus work on concepts lite.&q=
uot;</span></div>
<div style><span style=3D"font-family:arial,sans-serif;font-size:12.7272720=
33691406px;line-height:16.988636016845703px">See:=C2=A0</span><a href=3D"ht=
tps://groups.google.com/a/isocpp.org/forum/#!topic/concepts/AMVFwQGgS3c">ht=
tps://groups.google.com/a/isocpp.org/forum/#!topic/concepts/AMVFwQGgS3c</a>=
</div>
<div style><br></div><div style><span style=3D"font-family:arial,sans-serif=
;font-size:12.727272033691406px;line-height:16.988636016845703px">I&#39;m p=
ointing that in case Alexandrescu and Walter didn&#39;t know and want to de=
fend their paper.</span></div>
<div style><span style=3D"font-family:arial,sans-serif;font-size:12.7272720=
33691406px;line-height:16.988636016845703px"><br></span></div><div style><s=
pan style=3D"font-family:arial,sans-serif;font-size:12.727272033691406px;li=
ne-height:16.988636016845703px">Joel Lamotte</span></div>
<div style><span style=3D"font-family:arial,sans-serif;font-size:12.7272720=
33691406px;line-height:16.988636016845703px"><br></span></div></div>

--bcaec54ee030eeaea304d781d970--
Mar 09 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 9 March 2013 at 18:23:29 UTC, 1100110 wrote:
 I love how the second set show up in two different styles on my 
 computer.

This is not different style, this is different chars. << >> != « » .
Mar 09 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/09/2013 01:48 AM, DypthroposTheImposter wrote:
         See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


        Are they full of it?

Maybe. The paper is full of typos.
 Has it caused the problems they mention in D?

All of the non-C++ specific ones that are not made up to make the paper longer. Eg: 0. Templates + static if are an ad-hoc abstraction mechanism. 1. Declaration-site template body type checking becomes undecidable. 2. Constraint-based overloading needs manual work in order to express specialization relations. In D there also exist other problems that wouldn't occur in C++ in that form: static if(!is(typeof(x))) enum y = 1; static if(!is(typeof(y))) enum z = 2; static if(!is(typeof(z))) enum x = 3; The above currently does not have any defined behaviour. If the three are distributed to mutually importing modules, which constants get defined may depend on the order the modules are passed to DMD on the command line. (It is solvable, but so far few people have shown interest.)
Mar 09 2013
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Saturday, 9 March 2013 at 16:22:43 UTC, monarch_dodra wrote:
 ...which brings us to managing said overloads. Basically, right 
 now, if you want overloads, you have to repeat the conditions 
 in a:

 if (a && !b)
 ...
 if (b && !c)
 ...
 if (c)

 This is minor, but it does not scale very well, especially if 
 "a", "b" and "c" are complicated. In algorithm, some of our 
 constraints for sort/find can be 5 lines long. At this point, 
 can we still say that they are readable tools for users, or an 
 implementation tool for dispatch?

I agree this is a problem. sort didn't have constraints for a long time. I added them not long ago, but if I'm being perfectly honest, I'm not 100% convinced I've done it correctly. It's incredibly difficult to examine a non-trivial function to see what the correct constraints are. btw, you have a bug :-) If the arguments match constraints a and c, but not b then the call will be ambiguous on the first and third. Another problem with constraints is that if you want to add a specialisation, you can't do it without changing the existing functions, e.g. void foo(R)(R r) if (isInputRange!R) If I want to add a better version for random access ranges, I cannot just add: void foo(R)(R r) if (isRandomAccessRange!R) I also have to modify the original: void foo(R)(R r) if (isInputRange!R && !isRandomAccessRange!R) I suppose a better solution to this problem would involve someway of specifying that random access ranges are a subtype of input ranges, and the overload resolution would recognise that the random access range version is preferable to the more general version when available. I can't see a way to do this in general with constraints.
Mar 09 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 09 Mar 2013 12:28:37 -0600
1100110 <0b1100110 gmail.com> wrote:

 On 03/09/2013 01:33 AM, Nick Sabalausky wrote:
 On Sat, 9 Mar 2013 02:08:07 -0500
 Nick Sabalausky<SeeWebsiteToContactMe semitwist.com>  wrote:

 On Sat, 09 Mar 2013 01:48:55 +0100
 "DypthroposTheImposter"<mcbracket gmail.com>  wrote:

          See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

         Are they full of it? Has it caused the problems they
 mention in
 D?

Does that document exist somewhere in a the form of a real web page? Or at least *any* real document format?

To be clear, that's not a veiled attack on anything. I really *am* just simply asking if there's a link for that anywhere to a real file (html, pdf, text, wordperfect, gif, hell whatever.)


Sure, please. If you could either post it here, or on the web, or email nick1 at semitwist dot com, or whatever works for you that'd be great. :)
Mar 09 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sun, 10 Mar 2013 00:20:34 -0600
1100110 <0b1100110 gmail.com> wrote:
 
 http://1100110.in/static-if.pdf
 
 (Powered by vibe.d  =P)

Cool, thanks :)
Mar 10 2013
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Sunday, 10 March 2013 at 02:35:28 UTC, Walter Bright wrote:
 On 3/9/2013 8:22 AM, monarch_dodra wrote:
 Things can get evenmore hairy,when you are operating on 2 
 different types.

This is why complex expressions can be encapsulated as functions.
 One last thing to keep in mind is that having constraints 
 allows hijacking, whereas concpets/static asserts resolve as 
 an ambigus call.

I don't see where the hijacking comes in.

From the bad examples I think he was meaning declaring new functions in the static_if that might not be in the other tree; But proper use of static if doesn't cause those problems.
Mar 10 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 10 March 2013 at 02:35:28 UTC, Walter Bright wrote:
 On 3/9/2013 8:22 AM, monarch_dodra wrote:
 Things can get evenmore hairy,when you are operating on 2 
 different types.

This is why complex expressions can be encapsulated as functions.

Yes, but that doesn't solve the "root" issue of meaningfulness. Sure, instead of having a 5 line constraint, it's only a single line, but are these any better? sort(R, Scheme)(...) if(isRandomAccessRangeWithComparableElementsAndAssignableElementsIfStableSchemeOrSwapableElementsOtherwise!R) or sort(...) if(meetsSortConstraints!R) Neither are really any better for the end user. This is why I don't think constraints should be used at all for validating arguments. [concepts|static asserts] are much better, and when combined with static if, become incredibly powerful: sort(R, Scheme)(...) { static assert (isRandomAccessRange!T); static assert (is(typeof(r.front < r.front))); static if (Scheme == Stable) static assert (hasAssignableElements!T); else static assert (hasSwapableElements!T); //Code Code Code } Much clearer, and the diagnostics much better. That said, we can also look for a "middle ground" where the constraints validate the broad requirements (RA, comparable), and the asserts validate the more complex stuff.
 One last thing to keep in mind is that having constraints 
 allows hijacking,
 whereas concpets/static asserts resolve as an ambigus call.

I don't see where the hijacking comes in.

The problem with contraints is that it merelly eliminates functions from the pool of overloads. If you attemp to call a function with invalid parameters, then you may end up accidentally calling something you didn't want to. Imagine: //---- module a; void do_it(R)(R r) if (isForwardRange!R) { //Do something to r } //---- module b; void do_it(T)(T t) { //Do something completely different } //---- import a, b; void main() { MyInputRange myInputRange; //Oops! I didn't realize it's only input: do_it(myInputRange); //meant to call a.do_it; } //---- With the current scheme of constraints, this will end up calling b.do_it, without any ambiguity. You may or may not consider that is "hijacking", but it is error prone. NOW, if we had defined a.do_it with concepts/static asserts, the programmer would have been served with a "ambiguous call: a.do_it or b.do_it"? So the coder would have to be "alright, I want to explicitly call a.do_it". To which this time the compiler replies "Error: isForwardRange!MyInputRange is false". To which the programmer replies "I understand my error and see what I did wrong". -------------------------------------- I'm not saying template constraints are bad or anything, I think they are incredible tools for dispatching to specialized overloads. However, In regards to *validating* the input, I think concepts/static asserts, are both more robust implementation-wise, while being clearer for the end coder.
Mar 10 2013
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 10 March 2013 at 16:05:37 UTC, monarch_dodra wrote:
 I'm not saying template constraints are bad or anything, I 
 think they are incredible tools for dispatching to specialized 
 overloads.

 However, In regards to *validating* the input, I think 
 concepts/static asserts, are both more robust 
 implementation-wise, while being clearer for the end coder.

+1
Mar 10 2013
prev sibling next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter 
wrote:
        See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

       Are they full of it? Has it caused the problems they 
 mention
 in
 D?

It is hard for me to say, they continued to bring up that they have better tools to achieve some of the items (constexsp) but don't give an example of what that code would look like. It seems like they aren't actually looking for serious discussion on the matter; "C++ would become a low-level, unprincipled, hackers’ favorite playground." as apposed to what it is now a low-level, unprincipled, playground no hacker would play in unless they had to? That combined with not wanting to include a "realtively simple-to-use new feature" really makes it hard to take the paper seriously. As for template constraints, we do have issues in D; monarch_dodra has been good to go over those. I'm glad we have them, but they are not without their faults.
Mar 10 2013
prev sibling next sibling parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Saturday, 9 March 2013 at 14:09:39 UTC, Andrei Alexandrescu 
wrote:
 On 3/8/13 7:48 PM, DypthroposTheImposter wrote:
 See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


 Are they full of it? Has it caused the problems they mention
 in
 D?

Wow. That's quite out of character for Bjarne. I think it's quite a poor piece. Andrei

Indeed, from the start, it doesn't seem to give a fair assessment of the value of the feature. As for rejecting your proposal, don't take it too personnally. In the contrary, the inclusion of static if would have been the single reason for C++ users not to migrate en masse to D. Think that there won't be a good solution for C++ before another 20 years. By the time it is proposed, this is a good opportunity for D to mature and conquer hearts.
Mar 10 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 10 March 2013 at 22:49:53 UTC, SomeDude wrote:
 On Saturday, 9 March 2013 at 14:09:39 UTC, Andrei Alexandrescu 
 wrote:
 On 3/8/13 7:48 PM, DypthroposTheImposter wrote:
 See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to 
 a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg


 Are they full of it? Has it caused the problems they mention
 in
 D?

Wow. That's quite out of character for Bjarne. I think it's quite a poor piece. Andrei

Indeed, from the start, it doesn't seem to give a fair assessment of the value of the feature. As for rejecting your proposal, don't take it too personnally. In the contrary, the inclusion of static if would have been the single reason for C++ users not to migrate en masse to D. Think that there won't be a good solution for C++ before another 20 years. By the time it is proposed, this is a good opportunity for D to mature and conquer hearts.

Concepts have some drawbacks, but are also supperior in many way to static if. This isn't a black and white situation.
Mar 10 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, March 09, 2013 01:48:55 DypthroposTheImposter wrote:
         See the static_if paper here:
 
 http://isocpp.org/forums
 
 Under the post "constraints and static if" there is a link to a
 document about
 static_if
 
 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3
 NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg
 
        Are they full of it? Has it caused the problems they mention
 in
 D?

I haven't read the paper, so I really don't know what problems they see with static if, and C++ _is_ a very different beast than D (particularly with regards to stuff done at compile time), but without statif if, C++ seems very crippled with regards to templates and conditional compilaton. The combination of template constraints and static ifs is _extremely_ powerful in D, and it works very well. C++ currently lacks anything of the sort, and until it does, it's templates will be very much inferior to D's. Maybe they can gain similar power through different mechanisms, but I'm surprised that anyone would think that static if was such a bad idea. It's working fantastically well for us, and I don't know how we'd get along without it. - Jonathan M Davis
Mar 10 2013
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 11 March 2013 at 02:39:47 UTC, Jonathan M Davis wrote:
 I haven't read the paper, so I really don't know what problems 
 they see with static if, and C++ _is_ a very different beast 
 than D (particularly with regards to stuff done at compile 
 time), but without statif if, C++ seems very crippled with 
 regards to templates and conditional compilaton. The 
 combination of template constraints and static ifs is 
 _extremely_ powerful in D, and it works very well. C++ 
 currently lacks anything of the sort, and until it does, it's 
 templates will be very much inferior to D's. Maybe they can 
 gain similar power through different mechanisms, but I'm 
 surprised that anyone would think that static if was such a bad 
 idea. It's working fantastically well for us, and I don't know 
 how we'd get along without it.

It basically comes down to syntactical analysis, being able to tell if code is written right (when blocks end as well), which goes with their templates and use of <>'s; Which I'm glad to see D isn't crippled in that way. The another part is how static if becomes 'viral' as you'd have to use 'static if' in every spot elsewhere in order to keep it in line; However the example shown is bad programming practice and; You can duplicate very easily using the preprocessor. A third part of it was how 'verbose' they would have to be to check constraints, but with how just before C++11 they were verbose everywhere, so why it is verbose in constraints as his problem I am not sure.
Mar 10 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for declarations made
 inside the static if condition.

No, it doesn't, and it would be _way_ less useful if it did, particularly with regards to struct and class definitions. Take this code, for instance, import std.stdio; static if(true)    int var = 7; else    string var = 12; void main() {    int i = var;    static if(is(typeof(var) == int))        int j = 22;    else        float j;    writeln(j); } It compiles just fine and prints 22. Both the static if at module-level and the one in the function declare variables which are used outside of the static if blocks. static if does _not_ create a new scope. And putting braces around the static if bodies has no effect on the scoping either. - Jonathan M Davis
Mar 11 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Mar 11, 2013 at 10:31:53PM +0100, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
Actually, in D, static if creates its own scopes for declarations
made inside the static if condition.

No, it doesn't,

Yes it does.

Actually, it doesn't, scarily enough: import std.stdio; void main() { int[string] x; //float x; static if (is(typeof(x) S : T[U], T, U)) { writeln(S.stringof); writeln(T.stringof); writeln(U.stringof); } writeln(S.stringof); // <-- this compiles, and works!! } The last writeln will fail to compile if x's type is changed to float (as in the commented out line). Meaning that the definitions of S, T, U "leak" past the scope of the static if. Which makes the semantics of the code very unclear, because whether or not it even compiles depends on how the static if condition turns out. :-/ T -- Trying to define yourself is like trying to bite your own teeth. -- Alan Watts
Mar 11 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 11 March 2013 at 21:31:53 UTC, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
 On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for 
 declarations made
 inside the static if condition.

No, it doesn't,

Yes it does.

No... It doesn't. He just showed you.
 and it would be _way_ less useful if it did,

I don't think so.

Half the code in phobos would be broken.
 particularly with
 regards to struct and class definitions. Take this code, for 
 instance,

 import std.stdio;

 static if(true)
     int var = 7;
 else
     string var = 12;

 void main()
 {
     int i = var;

     static if(is(typeof(var) == int))
         int j = 22;
     else
         float j;

     writeln(j);
 }

 It compiles just fine and prints 22. Both the static if at 
 module-level and the
 one in the function declare variables which are used outside 
 of the static if
 blocks. static if does _not_ create a new scope. And putting 
 braces around the
 static if bodies has no effect on the scoping either.

 ...

What is the point? Your example code does not make any declaration inside the static if condition.

What *are* you talking about??? I can count 4 declarations in 2 static ifs? What is your definition of "declaration" and "scope". There's a misunderstanding somewhere here. Can YOU show us an example where there is a declaration that is scoped?
Mar 11 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 11 March 2013 at 22:12:46 UTC, monarch_dodra wrote:
 On Monday, 11 March 2013 at 21:31:53 UTC, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
 On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for 
 declarations made
 inside the static if condition.

No, it doesn't,

Yes it does.

No... It doesn't. He just showed you. [...] There's a misunderstanding somewhere here. Can YOU show us an example where there is a declaration that is scoped?

OOhhhh!!! "Condition" Right.
Mar 11 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 11 March 2013 at 22:08:10 UTC, H. S. Teoh wrote:
 On Mon, Mar 11, 2013 at 10:31:53PM +0100, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
Actually, in D, static if creates its own scopes for 
declarations
made inside the static if condition.

No, it doesn't,

Yes it does.

Actually, it doesn't, scarily enough: import std.stdio; void main() { int[string] x; //float x; static if (is(typeof(x) S : T[U], T, U)) { writeln(S.stringof); writeln(T.stringof); writeln(U.stringof); } writeln(S.stringof); // <-- this compiles, and works!! } The last writeln will fail to compile if x's type is changed to float (as in the commented out line). Meaning that the definitions of S, T, U "leak" past the scope of the static if. Which makes the semantics of the code very unclear, because whether or not it even compiles depends on how the static if condition turns out. :-/ T

I think that's bug material. The "is" definition should end at the end of that block.
Mar 11 2013
prev sibling next sibling parent "ponce" <contact gam3sfrommars.fr> writes:
On Saturday, 9 March 2013 at 00:48:59 UTC, DypthroposTheImposter
wrote:
        See the static_if paper here:

 http://isocpp.org/forums

 Under the post "constraints and static if" there is a link to a
 document about
 static_if

 https://docs.google.com/viewer?a=v&pid=forums&srcid=MDIyMDc3NjUwMTczOTM0Mjk3NjABMDI2MzM3MjkxNDM4NDQ5MzE4NDcBLWVsS1Y4dFhtdDhKATUBaXNvY3BwLm9yZwF2Mg

       Are they full of it? Has it caused the problems they 
 mention
 in
 D?

What an unfair article. I guess someone is angry at D. I don't think C++11 is that good an upgrade. Concepts were delayed. Lambdas can't be templated, can't be recursive. constexpr is useless compared to CTFE. Move semantics are easy to use but much harder to really understand. I recently had to duplicate inline assembly code in C++. I would not have been forced to do it in D since (naked inline assembly + static if) can save a lot of lines. static if allow to get polymorphism at finer granularities.
Mar 11 2013
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 11 March 2013 at 21:31:53 UTC, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
 On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for 
 declarations made
 inside the static if condition.

No, it doesn't,

Yes it does.

No, it doesn't.
 and it would be _way_ less useful if it did,

I don't think so.

Oh? Examples inside the TDPL would break as the inner scopes would be hidden and thereby inaccessible. TDPL pg. 279 [quote] [code] template Select(bool cond, T1, T2) { static if (cond) { alias T1 Type; } else { alias T2 Type; } } unittest { alias Select!(false, int, string).Type MyType; static assert(is(MyType == string)); } [/code] [/quote] Plus it's part of the spec. TDPL pg. 69 [quote] Peeling Braces: There's a glaring oddity about the transmogrify example. See, the numeric type is introduced inside a pair of { and } braces. As such, it should be visible only locally inside that scope (and consequently invisible to the enclosing function), thus foiling our entire plan quite thoroughly. Such behavior would also render the promised static if statement practically useless. For that reason, the static if uses braces for [i]grouping[/i] but not for [i]scoping[/i]. As far as scope and visibility are concerned, static if peels the outermost braces away, if any (they are not required when you have only one controlled statement; out example above uses them only out of stylistic obsession). If you do want braces, just add another pair: [code] void main(){ static if (real.sizeof > double.sizeof) {{ auto maximorum = real.max; writefln("Really big numbers - up to %s!", maximorum); }} ... /* maximorum is invisible here */ ... } [/code] [/quote]
Mar 11 2013
prev sibling next sibling parent "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
On Monday, 11 March 2013 at 21:31:53 UTC, Timon Gehr wrote:
     static if(is(typeof(var) == int))
         int j = 22;

What is the point? Your example code does not make any declaration inside the static if condition.

I'm not sure what your definition of declaration is, but that looks like one to me, with instantiation of course.
Mar 11 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, March 11, 2013 23:12:45 monarch_dodra wrote:
 What *are* you talking about??? I can count 4 declarations in 2
 static ifs? What is your definition of "declaration" and "scope".
 
 There's a misunderstanding somewhere here. Can YOU show us an
 example where there is a declaration that is scoped?

Exactly. Every single line in those static ifs is a variable declaration, and not a one of them creates a new scope, or the code wouldn't compile. I don't understand how Timon can think that there are no declarations in that code. There's clearly a fundamental misunderstanding and/or miscommunication here. - Jonathan M Davis
Mar 11 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/12/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 There's clearly a fundamental misunderstanding

Clearly 10 people in here haven't read his sentence properly where he said "in the static if **condition**", and not the static if *block*.
Mar 11 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Mon, 11 Mar 2013 20:53:59 -0400
"Jonathan M Davis" <jmdavisProg gmx.com> wrote:

 On Monday, March 11, 2013 23:12:45 monarch_dodra wrote:
 What *are* you talking about??? I can count 4 declarations in 2
 static ifs? What is your definition of "declaration" and "scope".
 
 There's a misunderstanding somewhere here. Can YOU show us an
 example where there is a declaration that is scoped?

Exactly. Every single line in those static ifs is a variable declaration, and not a one of them creates a new scope, or the code wouldn't compile. I don't understand how Timon can think that there are no declarations in that code. There's clearly a fundamental misunderstanding and/or miscommunication here.

Timon was talking about declarations in the static if's *condition*, not the body.
Mar 11 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Mar 11, 2013 at 09:03:20PM -0400, Nick Sabalausky wrote:
 On Mon, 11 Mar 2013 20:53:59 -0400
 "Jonathan M Davis" <jmdavisProg gmx.com> wrote:
 
 On Monday, March 11, 2013 23:12:45 monarch_dodra wrote:
 What *are* you talking about??? I can count 4 declarations in 2
 static ifs? What is your definition of "declaration" and "scope".
 
 There's a misunderstanding somewhere here. Can YOU show us an
 example where there is a declaration that is scoped?

Exactly. Every single line in those static ifs is a variable declaration, and not a one of them creates a new scope, or the code wouldn't compile. I don't understand how Timon can think that there are no declarations in that code. There's clearly a fundamental misunderstanding and/or miscommunication here.

Timon was talking about declarations in the static if's *condition*, not the body.

Regardless, I have shown that even declarations in the condition leaks past the body of the static if. T -- Don't modify spaghetti code unless you can eat the consequences.
Mar 11 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 11 March 2013 at 22:42:26 UTC, Era Scarecrow wrote:
 On Monday, 11 March 2013 at 21:31:53 UTC, Timon Gehr wrote:
 On 03/11/2013 09:19 PM, Jonathan M Davis wrote:
 On Monday, March 11, 2013 20:14:07 Timon Gehr wrote:
 Actually, in D, static if creates its own scopes for 
 declarations made
 inside the static if condition.

No, it doesn't,

Yes it does.

No, it doesn't.
 and it would be _way_ less useful if it did,

I don't think so.

Oh? Examples inside the TDPL would break as the inner scopes would be hidden and thereby inaccessible.

Good, now check the meaning of condition.
Mar 11 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 00:54:18 UTC, Jonathan M Davis wrote:
 On Monday, March 11, 2013 23:12:45 monarch_dodra wrote:
 What *are* you talking about??? I can count 4 declarations in 2
 static ifs? What is your definition of "declaration" and 
 "scope".
 
 There's a misunderstanding somewhere here. Can YOU show us an
 example where there is a declaration that is scoped?

Exactly. Every single line in those static ifs is a variable declaration, and not a one of them creates a new scope, or the code wouldn't compile. I don't understand how Timon can think that there are no declarations in that code. There's clearly a fundamental misunderstanding and/or miscommunication here. - Jonathan M Davis

Yes, you totally missed the point where he was saying in *condition*
Mar 11 2013
prev sibling next sibling parent "so" <so so.so> writes:
On Saturday, 9 March 2013 at 14:09:39 UTC, Andrei Alexandrescu 
wrote:

 Wow. That's quite out of character for Bjarne. I think it's 
 quite a poor piece.

 Andrei

I simply didn't have the stomach to read it after the first paragraph. They have no idea what they are talking about. It is as if they never used templates more than writing one liners. Harder to read, understand, debug? I am just speechless.
Mar 11 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 9 March 2013 at 16:42:56 UTC, deadalnix wrote:
 On Saturday, 9 March 2013 at 15:22:55 UTC, monarch_dodra wrote:
 [..]
 BTW, in regards to template constraints (not the rest), he 
 does have a point. We have raised the exact same issues here 
 on the boards more than once.

The more I think of it, the more this whole duck typing for templates is probably a bad solution because we lack tool to express « meta types ».

I'm starting to think so too. On Saturday, 9 March 2013 at 18:46:23 UTC, Peter Alexander wrote:
 [..]
 I suppose a better solution to this problem would involve 
 someway of specifying that random access ranges are a subtype 
 of input ranges, and the overload resolution would recognise 
 that the random access range version is preferable to the more 
 general version when available.

I wonder how would these "polymorphic concepts" work exactly. The following is pseudo-code: concept A1 { void foo(); } concept A2 : A1 { // A2 extends A1 void bar(); } concept B1 { void fun(); } concept B2 : B1 { void gun(); } struct S1 implements A2 { void foo() { } void bar() { } } struct S2 implements B2 { void fun() { } void gun() { } } void dostuff(A1, B1)(A1 a, B1 b) { } // Overload-1 void dostuff(A2, B1)(A2 a, B1 b) { } // Overload-2 void main() { S1 s1; S2 s2; dostuff(s1, s2); // calls the more specialized Overload-2 } // But, if we add the following overload, then the above // function call dostuff(s1, s2) doesn't know whether to // call Overload-2 or, the equally specialized, Overload-3: void dostuff(A1, B2)(A1 a, B2 b) { } // Overload-3 // And, if we add yet another, more specialized, overload, // then the previous ambiguity goes away: void dostuff(A2, B2)(A2 a, B2 b) { }
Mar 11 2013
prev sibling next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 12 March 2013 at 01:00:58 UTC, Andrej Mitrovic wrote:
 On 3/12/13, Jonathan M Davis <jmdavisProg gmx.com> wrote:
 There's clearly a fundamental misunderstanding

Clearly 10 people in here haven't read his sentence properly where he said "in the static if **condition**", and not the static if *block*.

That maybe so, he clearly changed the subject. We did discovered a bug because of it.
Mar 11 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 On Saturday, 9 March 2013 at 16:42:56 UTC, deadalnix wrote:
 On Saturday, 9 March 2013 at 15:22:55 UTC, monarch_dodra wrote:
 [..]
 BTW, in regards to template constraints (not the rest), he 
 does have a point. We have raised the exact same issues here 
 on the boards more than once.

The more I think of it, the more this whole duck typing for templates is probably a bad solution because we lack tool to express « meta types ».

I'm starting to think so too. On Saturday, 9 March 2013 at 18:46:23 UTC, Peter Alexander wrote:
 [..]
 I suppose a better solution to this problem would involve 
 someway of specifying that random access ranges are a subtype 
 of input ranges, and the overload resolution would recognise 
 that the random access range version is preferable to the more 
 general version when available.

I wonder how would these "polymorphic concepts" work exactly. The following is pseudo-code: concept A1 { void foo(); } concept A2 : A1 { // A2 extends A1 void bar(); } concept B1 { void fun(); } concept B2 : B1 { void gun(); } struct S1 implements A2 { void foo() { } void bar() { } } struct S2 implements B2 { void fun() { } void gun() { } } void dostuff(A1, B1)(A1 a, B1 b) { } // Overload-1 void dostuff(A2, B1)(A2 a, B1 b) { } // Overload-2 void main() { S1 s1; S2 s2; dostuff(s1, s2); // calls the more specialized Overload-2 } // But, if we add the following overload, then the above // function call dostuff(s1, s2) doesn't know whether to // call Overload-2 or, the equally specialized, Overload-3: void dostuff(A1, B2)(A1 a, B2 b) { } // Overload-3 // And, if we add yet another, more specialized, overload, // then the previous ambiguity goes away: void dostuff(A2, B2)(A2 a, B2 b) { }

Yes, that is the idea. It seems really cool.
Mar 11 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 04:34:05 UTC, Walter Bright wrote:
 On 3/11/2013 8:43 PM, deadalnix wrote:
 Yes, that is the idea. It seems really cool.

It's interfaces without the vtable[]. It's still solely based on type signatures. D constraints make pretty much anything that can be computed at compile time a testable gate.

Yes, but that allow static checking. The argument is the same as for dynamic vs static typing. In PHP for instance, you can do thing like : if(is_string($foo)) { // handle the case for string } else { // Do something else } And this is very similar to our template constraint system and static if, except we are meta here (ie, meta dynamic typing vs meta static typing).
Mar 11 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 06:05:54 UTC, Walter Bright wrote:
 On 3/11/2013 10:49 PM, deadalnix wrote:
 And this is very similar to our template constraint system and 
 static if, except
 we are meta here (ie, meta dynamic typing vs meta static 
 typing).

The issue I have with it is it is only able to express concepts as types. Values are important, too, as they are also parameters to templates.

Both definitively have advantages and drawbacks. Does the C++ team have any plan on making concept work with values ? Concepts are for instance THE perfect match for all kind of range we have.
Mar 11 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/12/13, deadalnix <deadalnix gmail.com> wrote:
 Concepts are for instance THE perfect match for all kind of range
 we have.

I don't know about that. Consider that with template parameters and static if you can pick and choose which range type you will implement: struct Range(Store) { static if (hasLength!Store) { // implement length, make the range random-access } else { // make the range an input range } } How would you implement this with concepts if you have to put the list of implements at the struct header?
Mar 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 06:34:50 UTC, Walter Bright wrote:
 Not for infinite ranges, which depend on empty returning a 
 compile time value.

It was already discussed int he past that this was a bad idea. I think that is another symptom of that poor design choice than an actual issue with concepts.
Mar 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 07:10:36 UTC, Andrej Mitrovic wrote:
 On 3/12/13, deadalnix <deadalnix gmail.com> wrote:
 Concepts are for instance THE perfect match for all kind of 
 range
 we have.

I don't know about that. Consider that with template parameters and static if you can pick and choose which range type you will implement: struct Range(Store) { static if (hasLength!Store) { // implement length, make the range random-access } else { // make the range an input range } } How would you implement this with concepts if you have to put the list of implements at the struct header?

I was thinking about constraint. I don't think static if should go away in any way.
Mar 12 2013
prev sibling next sibling parent "anonymous" <anonymous example.com> writes:
By now, I'm suspecting that I'm missing the point entirely, but 
here it is.

The idea is this:
Given
     interface A {...}
     interface B : A {...}
     struct S {supposed to implement B}
use alias this to enable implicit conversions:
     S to Concept!(B, S)
     Concept!(B, S) to Concept!(A, S)
The number of alias this hops then decides which overload is 
taken.

No rights reserved.


import std.traits: BaseTypeTuple;

mixin template implements(Iface) {
      property inout(Concept!(Iface, typeof(this))) _concept()() 
inout {
         return typeof(return)(this);
     }
     alias _concept this;

     // ensure that the interface is implemented
     alias typeof(this) Self;
     private class _Tester : Iface {
         Self s;
         mixin ForwardInterface!(s, Iface);
     }
}

struct Concept(Iface, Impl) {
     Impl impl;
     mixin ForwardInterface!(impl, Iface);

     alias BaseTypeTuple!Iface B;
     static if(B.length == 1) {
          property inout(Concept!(B, typeof(impl))) _concept()() 
inout {
             return typeof(return)(impl);
         }
         alias _concept this;
     } else {
         // because multiple alias this aren't here yet
         static assert(B.length == 0);
     }
}

import std.traits: ParameterTypeTuple, ReturnType;
import std.string: format;

mixin template ForwardInterface(alias target, Iface) {
     mixin ForwardMembers!(target, Iface, __traits(allMembers, 
Iface));
}
mixin template ForwardMembers(alias target, Iface, memberNames 
...) {
     static if(memberNames.length > 0) {
         mixin ForwardOverloads!(target, memberNames[0],
             __traits(getOverloads, Iface, memberNames[0]));
         mixin ForwardMembers!(target, Iface, memberNames[1 .. $]);
     }
}
mixin template ForwardOverloads(
     alias target,
     string memberName,
     overloads ...
) {
     static if(overloads.length > 0) {
         alias overloads[0] o;
         mixin(format(
             q{
                 ReturnType!o %1$s(ParameterTypeTuple!o args) 
%2$-(%s %) {
                     target.%1$s(args);
                 }
             },
             memberName,
             [
                 (is(typeof(o) == immutable) ? "immutable" : ""),
                 (is(typeof(o) == const) ? "const" : ""),
                 (is(typeof(o) == shared) ? "shared" : "")
             ]
         ));
         mixin ForwardOverloads!(target, memberName, overloads[1 
.. $]);
     }
}

// example from 
http://forum.dlang.org/post/qqnwpprluchyaphvammf forum.dlang.org

interface A1 {void foo();}
interface A2 : A1 {void bar();}
interface B1 {void fun();}
interface B2 : B1 {void gun();}

struct S1 {
     mixin implements!A2;
     void foo() {}
     void bar() {}
}

struct S2 {
     mixin implements!B2;
     void fun() {}
     void gun() {}
}

int dostuff(X, Y)(Concept!(A1, X) a, Concept!(B1, Y) b) {return 
1;}
int dostuff(X, Y)(Concept!(A2, X) a, Concept!(B1, Y) b) {return 
2;}

import std.stdio;
void main() {
     S1 s1;
     S2 s2;
     writeln(dostuff(s1, s2)); // calls the more specialized 
Overload-2
}

// But, if we add the following overload, then the above
// function call dostuff(s1, s2) doesn't know whether to
// call Overload-2 or, the equally specialized, Overload-3:

int dostuff(X, Y)(Concept!(A1, X) a, Concept!(B2, Y) b) {return 
3;}

// And, if we add yet another, more specialized, overload,
// then the previous ambiguity goes away:

int dostuff(X, Y)(Concept!(A2, X) a, Concept!(B2, Y) b) {return 
4;}
Mar 12 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 12 March 2013 at 07:13:11 UTC, deadalnix wrote:
 On Tuesday, 12 March 2013 at 06:34:50 UTC, Walter Bright wrote:
 Not for infinite ranges, which depend on empty returning a 
 compile time value.

It was already discussed int he past that this was a bad idea. I think that is another symptom of that poor design choice than an actual issue with concepts.

When was it discussed that this was a bad idea? I'm not saying it isn't (I think it isn't), but I don't remember any such discussion. I'd love to read it.
Mar 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 07:59:49 UTC, monarch_dodra wrote:
 On Tuesday, 12 March 2013 at 07:13:11 UTC, deadalnix wrote:
 On Tuesday, 12 March 2013 at 06:34:50 UTC, Walter Bright wrote:
 Not for infinite ranges, which depend on empty returning a 
 compile time value.

It was already discussed int he past that this was a bad idea. I think that is another symptom of that poor design choice than an actual issue with concepts.

When was it discussed that this was a bad idea? I'm not saying it isn't (I think it isn't), but I don't remember any such discussion. I'd love to read it.

http://forum.dlang.org/thread/yjogdvimxeyxzrjoqzsr forum.dlang.org First answer is yours, BTW :D
Mar 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 09:35:51 UTC, Walter Bright wrote:
 On 3/12/2013 1:14 AM, deadalnix wrote:
 On Tuesday, 12 March 2013 at 07:59:49 UTC, monarch_dodra wrote:
 On Tuesday, 12 March 2013 at 07:13:11 UTC, deadalnix wrote:
 On Tuesday, 12 March 2013 at 06:34:50 UTC, Walter Bright 
 wrote:
 Not for infinite ranges, which depend on empty returning a 
 compile time value.

It was already discussed int he past that this was a bad idea. I think that is another symptom of that poor design choice than an actual issue with concepts.

When was it discussed that this was a bad idea?


I don't think that thread conclusively determined it was a bad idea.

The thread don't conclude anything. It nevertheless raises very good points.
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 04:34:05 UTC, Walter Bright wrote:
 It's interfaces without the vtable[].

 It's still solely based on type signatures. D constraints make 
 pretty much anything that can be computed at compile time a 
 testable gate.

Yeah, you're right. That kind of interface syntax doesn't really lend itself to specifying concepts. So, here's another attempt at a concept syntax (and functionality): concept AscendingInfiniteInputRange { // 'this' is an instance of a type which implements the // AscendingInfiniteInputRange concept given the // if-condition below is true: if( is(typeof(this.empty) : bool) && is(typeof(this.front)) && !is(typeof(this.front) == void) && is(typeof(this.popFront() == void) // testing a compile time evaluable value: && this.empty == false // static members can also be tested: && typeof(this).infinite == true && typeof(this).sortedAscending == true ) } // extending the AscendingInfiniteInputRange concept: concept AscendingInfiniteForwardRange : AscendingInfiniteInputRange { if (is(typeof(this.save) == typeof(this))) } // a concept of a 2-dimensional infinite ascending slope: concept InfiniteSlope : AscendingInfiniteForwardRange { // 'is' can be used to test if a type implements a concept: if (is(typeof(this.front) == AscendingInfiniteForwardRange)) }
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept. The fact that a type implements a concept should be implicit, i.e. the following (pseudo-code) should work: concept InputRange { if( is(typeof(this.empty) : bool) && is(typeof(this.front)) && is(typeof(this.popFront() == void) ) } struct MyRange { bool empty() { return false; } int front() { return 42; } void popFront() { } } void main() { static assert(is(MyRange == InputRange)); }
Mar 12 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Tue, 12 Mar 2013 12:51:03 +0100
"TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept.

I *strongly* disagree. A much as I love ranges (for example), their duckiness is the one thing I consider to be a huge mistake.
Mar 12 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 12, 2013 at 12:39:48PM +0100, TommiT wrote:
 On Tuesday, 12 March 2013 at 04:34:05 UTC, Walter Bright wrote:
It's interfaces without the vtable[].

It's still solely based on type signatures. D constraints make
pretty much anything that can be computed at compile time a
testable gate.

Yeah, you're right. That kind of interface syntax doesn't really lend itself to specifying concepts. So, here's another attempt at a concept syntax (and functionality): concept AscendingInfiniteInputRange { // 'this' is an instance of a type which implements the // AscendingInfiniteInputRange concept given the // if-condition below is true: if( is(typeof(this.empty) : bool) && is(typeof(this.front)) && !is(typeof(this.front) == void) && is(typeof(this.popFront() == void) // testing a compile time evaluable value: && this.empty == false // static members can also be tested: && typeof(this).infinite == true && typeof(this).sortedAscending == true ) }

How is this any different from the current isInputRange!R, isForwardRange!R, etc.? T -- Дерево держится корнями, а человек - друзьями.
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 14:16:15 UTC, H. S. Teoh wrote:
 On Tue, Mar 12, 2013 at 12:39:48PM +0100, TommiT wrote:
 On Tuesday, 12 March 2013 at 04:34:05 UTC, Walter Bright wrote:
It's interfaces without the vtable[].

It's still solely based on type signatures. D constraints make
pretty much anything that can be computed at compile time a
testable gate.

Yeah, you're right. That kind of interface syntax doesn't really lend itself to specifying concepts. So, here's another attempt at a concept syntax (and functionality): concept AscendingInfiniteInputRange { // 'this' is an instance of a type which implements the // AscendingInfiniteInputRange concept given the // if-condition below is true: if( is(typeof(this.empty) : bool) && is(typeof(this.front)) && !is(typeof(this.front) == void) && is(typeof(this.popFront() == void) // testing a compile time evaluable value: && this.empty == false // static members can also be tested: && typeof(this).infinite == true && typeof(this).sortedAscending == true ) }

How is this any different from the current isInputRange!R, isForwardRange!R, etc.? T

The difference is in function overload resolution. Polymorphic concept based template would know about the hierarchical nature of the concepts, say ForwardRange is a sub-concept of InputRange, and thus the function overload resolution would be able to choose the template which has the most derived/specialized concept parameter that still matches with the given template argument.
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 14:24:11 UTC, TommiT wrote:
 The difference is in function overload resolution. Polymorphic 
 concept based template would know about the hierarchical nature 
 of the concepts, say ForwardRange is a sub-concept of 
 InputRange, and thus the function overload resolution would be 
 able to choose the template which has the most 
 derived/specialized concept parameter that still matches with 
 the given template argument.

Example: void foo(R)(R) if (isInputRange!R) { } void foo(R)(R) if (isForwardRange!R) { } int[] arr; foo(arr); // ambiguity error // Polymorphic concept to the rescue: concept InputRange { // definition of the concept ... } // ForwardRange is an extension of InputRange concept ForwardRange : InputRange { ... } void bar(InputRange R)(R) { } void bar(ForwardRange R)(R) { } int[] arr; bar(arr); // calls the second one
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 13:44:35 UTC, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 12:51:03 +0100
 "TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept.

I *strongly* disagree. A much as I love ranges (for example), their duckiness is the one thing I consider to be a huge mistake.

The problem with having to explicitl specify that a type implements a certain concept, is the resulting strong coupling between the concept definition and the type. This prevents "happy accidents" like the following from happening: Alice and Bob write libraries without knowing anything about each other or each other's code. Alice implements the following in her library: concept IntegerLike { ... } void foo(IntegerLike N)(N n) { } Bob implements the following in his library: struct SafeInt { ... } Later Bob realizes that Alice has written this cool function foo which accepts his type SafeInt as an argument because SafeInt just so happens to fulfill the requirements of the IntegerLike concept defined in Alice's library. Although, the majority of concepts should come from the standard library.
Mar 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 14:16:15 UTC, H. S. Teoh wrote:
 On Tue, Mar 12, 2013 at 12:39:48PM +0100, TommiT wrote:
 On Tuesday, 12 March 2013 at 04:34:05 UTC, Walter Bright wrote:
It's interfaces without the vtable[].

It's still solely based on type signatures. D constraints make
pretty much anything that can be computed at compile time a
testable gate.

Yeah, you're right. That kind of interface syntax doesn't really lend itself to specifying concepts. So, here's another attempt at a concept syntax (and functionality): concept AscendingInfiniteInputRange { // 'this' is an instance of a type which implements the // AscendingInfiniteInputRange concept given the // if-condition below is true: if( is(typeof(this.empty) : bool) && is(typeof(this.front)) && !is(typeof(this.front) == void) && is(typeof(this.popFront() == void) // testing a compile time evaluable value: && this.empty == false // static members can also be tested: && typeof(this).infinite == true && typeof(this).sortedAscending == true ) }

How is this any different from the current isInputRange!R, isForwardRange!R, etc.? T

With the thing defined that way not that much. But consider : concept InputRange(T) { bool empty; T front; void popFront(); } Then you can : - Validate range in a static manner. - Validate template before they are instantiated. - Express intent. - Make overload rules easier to understand and more predictable when used. Definitively the idea it nice. I don't see it a replacement of static if as it doesn't handle values.
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 15:10:25 UTC, deadalnix wrote:
 On Tuesday, 12 March 2013 at 14:16:15 UTC, H. S. Teoh wrote:
 On Tue, Mar 12, 2013 at 12:39:48PM +0100, TommiT wrote:
 On Tuesday, 12 March 2013 at 04:34:05 UTC, Walter Bright 
 wrote:
It's interfaces without the vtable[].

It's still solely based on type signatures. D constraints 
make
pretty much anything that can be computed at compile time a
testable gate.

Yeah, you're right. That kind of interface syntax doesn't really lend itself to specifying concepts. So, here's another attempt at a concept syntax (and functionality): concept AscendingInfiniteInputRange { // 'this' is an instance of a type which implements the // AscendingInfiniteInputRange concept given the // if-condition below is true: if( is(typeof(this.empty) : bool) && is(typeof(this.front)) && !is(typeof(this.front) == void) && is(typeof(this.popFront() == void) // testing a compile time evaluable value: && this.empty == false // static members can also be tested: && typeof(this).infinite == true && typeof(this).sortedAscending == true ) }

How is this any different from the current isInputRange!R, isForwardRange!R, etc.? T

With the thing defined that way not that much. But consider : concept InputRange(T) { bool empty; T front; void popFront(); }

What if I write a type like the following: struct MyType { int _value; property bool empty() const { return true; } property ref const(int) front() const { return _value; } void popFront() const { } } Does MyType fulfill the requirements of your InputRange(T) concept? I don't think it does since its front returns by ref const(int) and InputRange(T)'s front returns by value.
Mar 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 12 March 2013 at 15:26:19 UTC, TommiT wrote:
 With the thing defined that way not that much. But consider :

 concept InputRange(T) {
    bool empty;
    T front;
    void popFront();
 }

What if I write a type like the following: struct MyType { int _value; property bool empty() const { return true; } property ref const(int) front() const { return _value; } void popFront() const { } } Does MyType fulfill the requirements of your InputRange(T) concept? I don't think it does since its front returns by ref const(int) and InputRange(T)'s front returns by value.

It doesn't because popFront is const and that don't make any sense. But more generally, I wrote that stuff quickly to demonstrate what it could look like and not to provide an accurate definition of InputRange.
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 15:37:01 UTC, deadalnix wrote:
 On Tuesday, 12 March 2013 at 15:26:19 UTC, TommiT wrote:
 With the thing defined that way not that much. But consider :

 concept InputRange(T) {
   bool empty;
   T front;
   void popFront();
 }

What if I write a type like the following: struct MyType { int _value; property bool empty() const { return true; } property ref const(int) front() const { return _value; } void popFront() const { } } Does MyType fulfill the requirements of your InputRange(T) concept? I don't think it does since its front returns by ref const(int) and InputRange(T)'s front returns by value.

It doesn't because popFront is const and that don't make any sense.

I didn't mean to make popFront const. My point was that InputRange concept requires that the front property returns a non-void type but it doesn't care whether or not it is returned by ref, const ref, or by value. I don't see how you could easily convey that kind of requirement in an interface-like syntax.
Mar 12 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Tue, 12 Mar 2013 16:02:24 +0100
"TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 13:44:35 UTC, Nick Sabalausky wrote:
 On Tue, 12 Mar 2013 12:51:03 +0100
 "TommiT" <tommitissari hotmail.com> wrote:

 On Tuesday, 12 March 2013 at 02:39:06 UTC, TommiT wrote:
 struct S1 implements A2 {
     void foo() { }
     void bar() { }
 }

That's not good. Types shouldn't have to explicitly say that they implement a concept.

I *strongly* disagree. A much as I love ranges (for example), their duckiness is the one thing I consider to be a huge mistake.

The problem with having to explicitl specify that a type implements a certain concept, is the resulting strong coupling between the concept definition and the type. This prevents "happy accidents" like the following from happening: Alice and Bob write libraries without knowing anything about each other or each other's code. Alice implements the following in her library: concept IntegerLike { ... } void foo(IntegerLike N)(N n) { } Bob implements the following in his library: struct SafeInt { ... } Later Bob realizes that Alice has written this cool function foo which accepts his type SafeInt as an argument because SafeInt just so happens to fulfill the requirements of the IntegerLike concept defined in Alice's library. Although, the majority of concepts should come from the standard library.

"Happy accidents" is nothing more than another way of saying "Shit fucked up, but by pure dumb luck there was no damage". It's an absolutely *terrible* thing to encourage and design for. You may as well just go dynamic all the way, a la ActionScript 2 or Python - it's all the same "let random things happen by accident and blindly hope it just happens to turn out correct" philosophy. Design-by-accident is an anti-pattern. To me more specific, the problem with duck typing is that it falsely assumes that name+signature uniquely defines semantics (which is clearly not a valid assumption). Avoiding accidental screwups under duck typing *is* feasible if there's only a few well-known duck types that are ever in play (ex: our entire list of available duck types is a handful of phobos-defined ranges and basically nothing else). But it does not scale: The likelihood of accidental fuckups is multiplied with each additional duck type in existence, with non-stdlib duck types carrying a greater "accidental fuck up" weight.
Mar 12 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Tuesday, 12 March 2013 at 16:28:14 UTC, Nick Sabalausky wrote:
 "Happy accidents" is nothing more than another way of saying 
 "Shit
 fucked up, but by pure dumb luck there was no damage". It's an
 absolutely *terrible* thing to encourage and design for. You 
 may as
 well just go dynamic all the way, a la ActionScript 2 or Python 
 - it's
 all the same "let random things happen by accident and blindly 
 hope it
 just happens to turn out correct" philosophy.

 Design-by-accident is an anti-pattern.

 To me more specific, the problem with duck typing is that it 
 falsely
 assumes that name+signature uniquely defines semantics (which is
 clearly not a valid assumption). Avoiding accidental screwups 
 under
 duck typing *is* feasible if there's only a few well-known duck 
 types
 that are ever in play (ex: our entire list of available duck 
 types is a
 handful of phobos-defined ranges and basically nothing else). 
 But it
 does not scale: The likelihood of accidental fuckups is 
 multiplied with
 each additional duck type in existence, with non-stdlib duck 
 types
 carrying a greater "accidental fuck up" weight.

I thought about this a bit more, and I agree with the fundamental content of what you said. The crux of the matter is that we can't specify new semantics with code. We can only specify new semantics through documentation. And compilers don't read documentations. But, I think a good way to alleviate this problem would be to allow programmers to specify that two different concepts are in fact the same exact concept. Then two unrelated libraries could be made interoperable with each other. Example: There are two unrelated libraries, LibA and LibB. Library LibA defines: 1) concept ConceptA { ... } 2) void functionA(ConceptA A)(A a) { ... } Library LibB defines: 1) concept ConceptB { ... } 2) void functionB(ConceptB B)(B b) { ... } The two concepts, ConceptA and ConceptB, specify the same exact concept (this can be verified only by reading their respective documentations). If the end user now creates a type which implements ConceptA: struct MyStruct implements ConceptA { ... } ...then the problem is that instances of MyStruct can't be passed to functionB. But, if the end-user has a way to say that ConceptA is a synonym to ConceptB, then he can make the two libraries interoperable with each other and with his own types. E.g: concept ConceptA = ConceptB; // make them synonymous struct MyStruct implements ConceptA { ... } MyStruct ms; functionB(ms); // OK If ConceptA and ConceptB have happened to use different function names for doing the same conceptual thing, then the end-user should also be able to specify which function names are synonymous with each other.
Mar 12 2013
prev sibling next sibling parent =?UTF-8?Q?Klaim_=2D_Jo=C3=ABl_Lamotte?= <mjklaim gmail.com> writes:
--047d7b339b1521e95704d7ca35a4
Content-Type: text/plain; charset=UTF-8

Just for complete information, the static_if feature isn't rejected but
discussion/effort on it is now delayed.
See minutes: http://isocpp.org/files/papers/N3576.pdf
My understanding is that focusing on concepts(-light) is a priority for
this working group now.

Walter was in the meeting so he got the details.

Joel Lamotte

--047d7b339b1521e95704d7ca35a4
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Just for complete information, the static_if feature isn&#=
39;t rejected but discussion/effort on it is now delayed.<div style>See min=
utes:=C2=A0<a href=3D"http://isocpp.org/files/papers/N3576.pdf">http://isoc=
pp.org/files/papers/N3576.pdf</a></div>
<div style>My understanding is that focusing on concepts(-light) is a prior=
ity for this working group now.</div><div style><br></div><div style>Walter=
 was in the meeting so he got the details.</div><div style><br></div><div s=
tyle>
Joel Lamotte</div><div style><br></div></div>

--047d7b339b1521e95704d7ca35a4--
Mar 13 2013
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
--047d7b678800187a3804d7cee915
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On 13 March 2013 08:29, Klaim - Jo=EBl Lamotte <mjklaim gmail.com> wrote:

 Just for complete information, the static_if feature isn't rejected but
 discussion/effort on it is now delayed.
 See minutes: http://isocpp.org/files/papers/N3576.pdf
 My understanding is that focusing on concepts(-light) is a priority for
 this working group now.

 Walter was in the meeting so he got the details.

confused about the difference. ;) --=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0'; --047d7b678800187a3804d7cee915 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On 1= 3 March 2013 08:29, Klaim - Jo=EBl Lamotte <span dir=3D"ltr">&lt;<a href=3D= "mailto:mjklaim gmail.com" target=3D"_blank">mjklaim gmail.com</a>&gt;</spa= n> wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><div dir=3D"ltr">Just for complete informati= on, the static_if feature isn&#39;t rejected but discussion/effort on it is= now delayed.<div> See minutes:=A0<a href=3D"http://isocpp.org/files/papers/N3576.pdf" target= =3D"_blank">http://isocpp.org/files/papers/N3576.pdf</a></div> <div>My understanding is that focusing on concepts(-light) is a priority fo= r this working group now.</div><div><br></div><div>Walter was in the meetin= g so he got the details.</div><div><br></div></div></blockquote></div> <br></div><div class=3D"gmail_extra">Looking at the minutes, that was Walte= r Brown, not Bright.=A0 Incase you got confused about the difference. ;)<br=
</div><div class=3D"gmail_extra"><br>-- <br>Iain Buclaw<br><br>*(p &lt; e =

</div></div> --047d7b678800187a3804d7cee915--
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 13 March 2013 at 14:06:33 UTC, Iain Buclaw wrote:
 On 13 March 2013 08:29, Klaim - Joël Lamotte 
 <mjklaim gmail.com> wrote:

 Just for complete information, the static_if feature isn't 
 rejected but
 discussion/effort on it is now delayed.
 See minutes: http://isocpp.org/files/papers/N3576.pdf
 My understanding is that focusing on concepts(-light) is a 
 priority for
 this working group now.

 Walter was in the meeting so he got the details.

Incase you got confused about the difference. ;)

Are you saying that Walter Brown isn't bright ? /me runaway
Mar 13 2013
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
--0015174c3b1c3d218c04d7d47ca8
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On 13 March 2013 14:12, deadalnix <deadalnix gmail.com> wrote:

 On Wednesday, 13 March 2013 at 14:06:33 UTC, Iain Buclaw wrote:

 On 13 March 2013 08:29, Klaim - Jo=EBl Lamotte <mjklaim gmail.com> wrote=


  Just for complete information, the static_if feature isn't rejected but
 discussion/effort on it is now delayed.
 See minutes: http://isocpp.org/files/**papers/N3576.pdf<http://isocpp.o=



 My understanding is that focusing on concepts(-light) is a priority for
 this working group now.

 Walter was in the meeting so he got the details.


  Looking at the minutes, that was Walter Brown, not Bright.  Incase you

confused about the difference. ;)

Are you saying that Walter Brown isn't bright ? /me runaway

He's neither Black, Blue, or Bubblegum flavour either. --=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0'; --0015174c3b1c3d218c04d7d47ca8 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">On 1= 3 March 2013 14:12, deadalnix <span dir=3D"ltr">&lt;<a href=3D"mailto:deada= lnix gmail.com" target=3D"_blank">deadalnix gmail.com</a>&gt;</span> wrote:= <br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-lef= t:1px #ccc solid;padding-left:1ex"> <div class=3D"im">On Wednesday, 13 March 2013 at 14:06:33 UTC, Iain Buclaw = wrote:<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l= eft:1px #ccc solid;padding-left:1ex"><div class=3D"im"> On 13 March 2013 08:29, Klaim - Jo=EBl Lamotte &lt;<a href=3D"mailto:mjklai= m gmail.com" target=3D"_blank">mjklaim gmail.com</a>&gt; wrote:<br> <br> </div><div><div class=3D"h5"><blockquote class=3D"gmail_quote" style=3D"mar= gin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> Just for complete information, the static_if feature isn&#39;t rejected but= <br> discussion/effort on it is now delayed.<br> See minutes: <a href=3D"http://isocpp.org/files/papers/N3576.pdf" target=3D= "_blank">http://isocpp.org/files/<u></u>papers/N3576.pdf</a><br> My understanding is that focusing on concepts(-light) is a priority for<br> this working group now.<br> <br> Walter was in the meeting so he got the details.<br> <br> <br> </blockquote></div></div><div class=3D"im"> Looking at the minutes, that was Walter Brown, not Bright. =A0Incase you go= t<br> confused about the difference. ;)<br> </div></blockquote> <br> Are you saying that Walter Brown isn&#39;t bright ?<br> <br> /me runaway<br> </blockquote></div><br></div><div class=3D"gmail_extra">He&#39;s neither Bl= ack, Blue, or Bubblegum flavour either.<br></div><div class=3D"gmail_extra"=
<br clear=3D"all"><br>-- <br>Iain Buclaw<br><br>*(p &lt; e ? p++ : p) =3D =

</div></div> --0015174c3b1c3d218c04d7d47ca8--
Mar 13 2013
prev sibling next sibling parent reply "Don" <turnyourkidsintocash nospam.com> writes:
On Saturday, 9 March 2013 at 03:50:29 UTC, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, 
 DypthroposTheImposter wrote:
      Are they full of it? Has it caused the problems they 
 mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

I think the hard-to-analyze argument is a good one. I've created an enhancement for some analysis we could do without too much work: http://d.puremagic.com/issues/show_bug.cgi?id=9715 (I think my bug report shows a bigger problem with static if, than is reported in the paper; the problems arise only when you have two static ifs in the same scope).
Mar 14 2013
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 02:54:17PM -0400, Andrei Alexandrescu wrote:
 On 3/14/13 2:07 PM, Dicebot wrote:
On Thursday, 14 March 2013 at 17:51:23 UTC, Andrei Alexandrescu wrote:
If you found a few, that would be great. I don't think you'll have
an easy time.

Andrei

In other comment I have mentioned a case I have fixed just 15 days ago: https://github.com/D-Programming-Language/phobos/pull/1182 100% line coverage, compile-time error for certain type parameter subset. Could have been found by compiler / clever-enough framework. That was easy.

1 < a few

I found (and fixed!) a number of missed combinations in std.algorithm: transient ranges, joiner() not using .save on forward ranges, same bug in transposed(), transposed crashing on jagged range of ranges, etc.. Given that some of this code is rather old before I touched them, I'm forced to believe that many more such bugs lurk in Phobos that nobody has found yet. Or they found it but just evaded it by rewriting some user code -- I've found myself doing that on several occasions, because I was trying to get my own code done and didn't want to spend another 4 hours' digression to find where the bug in Phobos is. Sometimes I don't even file bugs because it takes time to reduce the test case and it's distracting from the task at hand. So no, it's not just 1. They are there, and there are more than 1 of them, if you'd only look. I don't think denying this is helpful to improving Phobos' quality. T -- Without geometry, life would be pointless. -- VS
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 02:37:29PM -0700, Walter Bright wrote:
 On 3/14/2013 1:57 PM, Timon Gehr wrote:
The following breaks most of std.range, and most of std.algorithm could likely
be broken too, but I am too lazy to investigate.

Please file this with bugzilla.

I think it deserves several different bug reports, as they appear to be failing in different places. T -- Always remember that you are unique. Just like everybody else. -- despair.com
Mar 14 2013
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 14, 2013 15:18:56 Andrei Alexandrescu wrote:
 On 3/14/13 3:04 PM, H. S. Teoh wrote:
 I found (and fixed!) a number of missed combinations in std.algorithm:
 transient ranges, joiner() not using .save on forward ranges, same bug
 in transposed(), transposed crashing on jagged range of ranges, etc..

I think you're right but only in part; there may be a bit of a confusion. There's pure semantic checking such as forgetting to use .save that can't be detected statically. Then there's code that e.g. should work for forward ranges but has only been tested with arrays.

Those tend to be somewhat common, though we've been cutting down on them.
 My question was referring to code that has sheer typos that are
 mechanically detected, which are present in code that has never ever
 been instantiated. I do recall we found a few, but I think that
 illustrates a problem with the process, not the language.

Those tend to be _very_ rare. I wouldn't say that we've _never_ seen one In Phobos, but I sure don't remember one. And that's something that 100% code coverage catches easily. It's the semantic issues where it doesn't. - Jonathan M Davis
Mar 14 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 14 March 2013 at 11:04:59 UTC, Artur Skawina wrote:
 On 03/14/13 10:26, Don wrote:
 On Saturday, 9 March 2013 at 03:50:29 UTC, Walter Bright wrote:
 On 3/8/2013 5:19 PM, Brad Anderson wrote:
 On Saturday, 9 March 2013 at 00:48:59 UTC, 
 DypthroposTheImposter wrote:
      Are they full of it? Has it caused the problems they 
 mention
 in
 D?

Well, the two guys with an alternative proposal (concepts-lite) seem to hate static if (along with a third guy). There seems to be a lot of strawman arguments in this paper.

Many of the criticisms in the paper are addressed by our positive experience with static if in D.

I think the hard-to-analyze argument is a good one. I've created an enhancement for some analysis we could do without too much work: http://d.puremagic.com/issues/show_bug.cgi?id=9715 (I think my bug report shows a bigger problem with static if, than is reported in the paper; the problems arise only when you have two static ifs in the same scope).

The gain from such checks would be minimal. Eg "return x.toray;". artur

I've already found plenty of such bugs in phobos, and wouldn't be surprised if this was one of its bigger sources of bugs. Sure, phobos is template and static "super heavy", given it is more or less the D-STL, but still. If the compiler can statically determine that a template branch simply *can't* compile, then the code should be turned down. Having to instantiate a template just to check to make sure it is semantically correct is a huge pain.
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Artur Skawina:

 The gain from such checks would be minimal. Eg "return 
 x.toray;".

I think we have no statistics about how much gain that's going to give. And even small improvement are good to have, if they are automatic (done by the compiler instead of the programmer), and if they have no false positives. Once such checks are in place, it will be possible to add better checks and further improvements :-) So I think ER 9715 is a good idea. Bye, bearophile
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 15:38:53 UTC, Andrei Alexandrescu 
wrote:
 On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it 
 is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests. Andrei

The same argument can be made when talking about dynamic vs static typing. This is usualy much better to have the compiler smash your mistake right into your face than discovering with a unittest much latter. I don't say that unittest are useless, but why rely on unittest when the machine can do the job for you ?
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 I'm not sure about that. The way I see it, no code should be 
 not delivered without being unittested. Ubiquitous unittesting 
 is now mainstream. The way I see it, a type system on top of 
 templates would only help people who don't write unittests.

This is an invalid argument. You can say the same thing for many (most?) tests done by the compiler. Unit tests can't be sure to verify all code paths inside a function or template. But the tests done by the compiler discussed here are like a type system, that verifies all (or most) code paths at once. Bye, bearophile
Mar 14 2013
prev sibling next sibling parent "Sergei Nosov" <sergei.nosov gmail.com> writes:
 From 
http://herbsutter.com/2013/03/14/words-of-wisdom-bjarne-stroustrup/?utm_source=tf&utm_medium=t

Bjarne Stroustrup wrote the following a few minutes ago on the 
concepts mailing list:

"Let me take this opportunity to remind people that

* "being able to do something is not sufficient reason for doing 
it" and
* "being able to do every trick is not a feature but a bug"

For the latter, remember Dijkstra’s famous "Goto considered 
harmful" paper. The point was not that the "new features" (loop 
constructs) could do every goto trick better/simpler, but that 
some of those tricks should be avoided to simplify good 
programming.

Concepts and concepts lite are meant to make good generic 
programming simpler. They are not meant to be a drop-in 
substitute for every metaprogramming and macroprogramming trick. 
If you are an expert, and if in your expert opinion you and your 
users really need those tricks, you can still use them, but we 
need to make many (most) uses of templates easier to get right, 
so that they can become more mainstream. That where concepts and 
concept lite fits in.

Some of you may find this hard to believe, but "back then" there 
was quite serious opposition to function declarations because 
"they restricted the way functions could be used and the way 
separate compilation could be used" and also serious opposition 
to virtual functions "because pointers to functions are so much 
more flexible." I see concepts lite (and concepts) in the same 
light as goto/for, 
unchecked-function-arguments/function-declarations, 
pointers-to-functions/abstract-classes."
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 No, this is different.

Why? Bye, bearophile
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 16:48:29 UTC, Andrei Alexandrescu 
wrote:
 And it has been made indeed. The question is on agreeing or not 
 with specifics. The stereotypical argument in favor of dynamic 
 typing goes as follows:

 Q: Does static typing detect all bugs?

 A: No.

 Q: Then unittests are necessary.

 A: Correct.

 Q: So if static typing is insufficient, why not rely on 
 unittests alone to do all checking? It's also bothersome for 
 some people to obey types, annotate stuff etc.

 A: There are still errors that can be better detected with 
 static checking, and many dynamic programs that work by 
 accident etc.

I see we agree this is the same problem materialized in another form. I find it rather weird that you conclude different things when the problem is the same in the first place.
 I don't say that unittest are useless, but why rely on 
 unittest when the
 machine can do the job for you ?

In both cases the machine does the work. My argument is that adding an additional layer of typing on top of templates caters to people who want to ship code that has literally zero testing. That's not a priority as far as I'm concerned.

I have other benefit, as the capability for the compiler to give understandable error message instead of a wall of template errors. This is clearly not a priority anyway. We should stop building on foundation that aren't solid or everything will collapse.
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 This is usualy much better to have the compiler smash your 
 mistake right
 into your face than discovering with a unittest much latter.

I don't think so.

Why?
 My argument is that adding an additional layer of typing on top 
 of templates caters to people who want to ship code that has 
 literally zero testing. That's not a priority as far as I'm 
 concerned.

If those people want yo write zero unit tests, they will write zero unit tests in both cases. I have seen D code like that. Introducing some compiler tests isn't going to make that situation worse and it's able to give better&nicer error messages when you have just written a template and you have not yet written a unittest (assuming you aren't using Test-Driven-Development). A template unittest often doesn't cover all possible instantiations of a template. So some compiler tests that work on all possible instantiations can help. You can also look at the situation from the other way: assuming you are correct, what currently present compiler tests do you want to remove? Bye, bearophile
Mar 14 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler. Unit tests can't be sure to
 verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries. You use template constraints to limit the code paths, and you use unittests to verify semantics. Then there's also static assert(0).
Mar 14 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 14 March 2013 at 17:07:16 UTC, Andrei Alexandrescu 
wrote:
 Very simple. Traditionally there's two crucial epochs known as 
 compilation time and run time. (There's some minor distinctions 
 like link time etc.) The whole notion of concepts and other 
 type systems for templates is predicated on three crucial 
 epochs: library compilation time, library user compilation 
 time, and run time. The logic goes, someone writes a generic 
 library and wants to distribute it to users. Users shouldn't 
 ever see bugs caused by e.g. typos in the library.

 So the crowd that use meta-type systems is formed of library 
 writers who want to distribute libraries without ever 
 instantiating them. I don't think that's a good crowd to cater 
 for.

 I've been surprised to figure how many people don't get this 
 flow, or only have a vague image of it. Although meta-types are 
 arguably "the right thing" to do, they're a lot less attractive 
 once it's clear what scenarios they help.

It is the very same reasoning. Meta-library developers are humans and make mistakes. Forgetting to cover instantiating some corner case in this example. If this won't compile, this bug won't persist all the way down to the user of this library, exactly the one we care most for.
Mar 14 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 14 March 2013 at 17:09:41 UTC, Andrej Mitrovic wrote:
 On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
 This is an invalid argument. You can say the same thing for 
 many
 (most?) tests done by the compiler. Unit tests can't be sure to
 verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries. You use template constraints to limit the code paths, and you use unittests to verify semantics. Then there's also static assert(0).

Does Phobos pull request tester turns red on failed 100% coverage? (sarcasm intended)
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 17:07:16 UTC, Andrei Alexandrescu 
wrote:
 Very simple. Traditionally there's two crucial epochs known as 
 compilation time and run time. (There's some minor distinctions 
 like link time etc.) The whole notion of concepts and other 
 type systems for templates is predicated on three crucial 
 epochs: library compilation time, library user compilation 
 time, and run time. The logic goes, someone writes a generic 
 library and wants to distribute it to users. Users shouldn't 
 ever see bugs caused by e.g. typos in the library.

I'm not sure if you are thinking I'm really stupid here.
 So the crowd that use meta-type systems is formed of library 
 writers who want to distribute libraries without ever 
 instantiating them. I don't think that's a good crowd to cater 
 for.

 I've been surprised to figure how many people don't get this 
 flow, or only have a vague image of it. Although meta-types are 
 arguably "the right thing" to do, they're a lot less attractive 
 once it's clear what scenarios they help.

Let me demonstrate with an actual example : libd-llvm/libd/src/d/parser/ambiguous.d(126): Error: no property 'bar' for type 'Lexer', did you mean 'r'? libd-llvm/libd/src/d/parser/statement.d(392): Error: template instance d.parser.statement.parseStatement!(Lexer).parseStatement.parseDeclarationOrExpres ion!(__dgliteral27, Lexer) error instantiating libd-llvm/libd/src/d/parser/statement.d(406): instantiated from here: parseStatement!(Lexer) libd-llvm/libd/src/d/parser/expression.d(652): instantiated from here: parseBlock!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(208): instantiated from here: parsePrimaryExpression!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(83): ... (11 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/statement.d(406): Error: template instance d.parser.statement.parseStatement!(Lexer) error instantiating libd-llvm/libd/src/d/parser/expression.d(652): instantiated from here: parseBlock!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(208): instantiated from here: parsePrimaryExpression!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(83): instantiated from here: parseTemplateArguments!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(22): ... (10 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/expression.d(652): Error: template instance d.parser.statement.parseBlock!(Lexer) error instantiating libd-llvm/libd/src/d/parser/dtemplate.d(208): instantiated from here: parsePrimaryExpression!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(83): instantiated from here: parseTemplateArguments!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(22): instantiated from here: parseBuiltIdentifier!(Lexer) libd-llvm/libd/src/d/parser/type.d(56): ... (9 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(208): Error: template instance d.parser.expression.parsePrimaryExpression!(Lexer) error instantiating libd-llvm/libd/src/d/parser/identifier.d(83): instantiated from here: parseTemplateArguments!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(22): instantiated from here: parseBuiltIdentifier!(Lexer) libd-llvm/libd/src/d/parser/type.d(56): instantiated from here: parseIdentifier!(Lexer) libd-llvm/libd/src/d/parser/type.d(16): ... (8 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(83): Error: template instance d.parser.dtemplate.parseTemplateArguments!(Lexer) error instantiating libd-llvm/libd/src/d/parser/identifier.d(22): instantiated from here: parseBuiltIdentifier!(Lexer) libd-llvm/libd/src/d/parser/type.d(56): instantiated from here: parseIdentifier!(Lexer) libd-llvm/libd/src/d/parser/type.d(16): instantiated from here: parseBasicType!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(112): ... (7 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(22): Error: template instance d.parser.identifier.parseBuiltIdentifier!(Lexer) error instantiating libd-llvm/libd/src/d/parser/type.d(56): instantiated from here: parseIdentifier!(Lexer) libd-llvm/libd/src/d/parser/type.d(16): instantiated from here: parseBasicType!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(112): instantiated from here: parseType!(cast(ParseMode)0, Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(68): ... (6 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/type.d(56): Error: template instance d.parser.identifier.parseIdentifier!(Lexer) error instantiating libd-llvm/libd/src/d/parser/type.d(16): instantiated from here: parseBasicType!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(112): instantiated from here: parseType!(cast(ParseMode)0, Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(68): instantiated from here: parseTypeParameter!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(46): ... (5 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/type.d(16): Error: template instance d.parser.type.parseBasicType!(Lexer) error instantiating libd-llvm/libd/src/d/parser/dtemplate.d(112): instantiated from here: parseType!(cast(ParseMode)0, Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(68): instantiated from here: parseTypeParameter!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(46): instantiated from here: parseTemplateParameter!(Lexer) libd-llvm/libd/src/d/parser/dfunction.d(51): ... (4 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(112): Error: template instance d.parser.type.parseType!(cast(ParseMode)0, Lexer) error instantiating libd-llvm/libd/src/d/parser/dtemplate.d(68): instantiated from here: parseTypeParameter!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(46): instantiated from here: parseTemplateParameter!(Lexer) libd-llvm/libd/src/d/parser/dfunction.d(51): instantiated from here: parseTemplateParameters!(Lexer) libd-llvm/libd/src/d/parser/declaration.d(362): ... (3 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(68): Error: template instance d.parser.dtemplate.parseTypeParameter!(Lexer) error instantiating libd-llvm/libd/src/d/parser/dtemplate.d(46): instantiated from here: parseTemplateParameter!(Lexer) libd-llvm/libd/src/d/parser/dfunction.d(51): instantiated from here: parseTemplateParameters!(Lexer) libd-llvm/libd/src/d/parser/declaration.d(362): instantiated from here: parseFunction!(FunctionDeclaration, Lexer, string,Type) libd-llvm/libd/src/d/parser/declaration.d(70): ... (2 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(46): Error: template instance d.parser.dtemplate.parseTemplateParameter!(Lexer) error instantiating libd-llvm/libd/src/d/parser/dfunction.d(51): instantiated from here: parseTemplateParameters!(Lexer) libd-llvm/libd/src/d/parser/declaration.d(362): instantiated from here: parseFunction!(FunctionDeclaration, Lexer, string,Type) libd-llvm/libd/src/d/parser/declaration.d(70): instantiated from here: parseTypedDeclaration!(Lexer) libd-llvm/libd/src/d/parser/dmodule.d(40): ... (1 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/dfunction.d(51): Error: template instance d.parser.dtemplate.parseTemplateParameters!(Lexer) error instantiating libd-llvm/libd/src/d/parser/declaration.d(362): instantiated from here: parseFunction!(FunctionDeclaration, Lexer, string,Type) libd-llvm/libd/src/d/parser/declaration.d(70): instantiated from here: parseTypedDeclaration!(Lexer) libd-llvm/libd/src/d/parser/dmodule.d(40): instantiated from here: parseDeclaration!(Lexer) libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/declaration.d(362): Error: template instance d.parser.dfunction.parseFunction!(FunctionDeclaration, Lexer, string,Type) error instantiating libd-llvm/libd/src/d/parser/declaration.d(70): instantiated from here: parseTypedDeclaration!(Lexer) libd-llvm/libd/src/d/parser/dmodule.d(40): instantiated from here: parseDeclaration!(Lexer) libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/declaration.d(70): Error: template instance d.parser.declaration.parseTypedDeclaration!(Lexer) error instantiating libd-llvm/libd/src/d/parser/dmodule.d(40): instantiated from here: parseDeclaration!(Lexer) libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/dmodule.d(40): Error: template instance d.parser.declaration.parseDeclaration!(Lexer) error instantiating libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/base.d(14): Error: template instance d.parser.dmodule.parseModule!(Lexer) error instantiating src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) src/sdc/sdc.d(54): Error: template instance d.parser.base.parse!(Lexer) error instantiating libd-llvm/libd/src/d/parser/ambiguous.d(126): Error: no property 'bar' for type 'Lexer', did you mean 'r'? libd-llvm/libd/src/d/parser/statement.d(392): Error: template instance d.parser.statement.parseStatement!(Lexer).parseStatement.parseDeclarationOrExpres ion!(__dgliteral27, Lexer) error instantiating libd-llvm/libd/src/d/parser/statement.d(406): instantiated from here: parseStatement!(Lexer) libd-llvm/libd/src/d/parser/expression.d(652): instantiated from here: parseBlock!(Lexer) libd-llvm/libd/src/d/parser/dtemplate.d(208): instantiated from here: parsePrimaryExpression!(Lexer) libd-llvm/libd/src/d/parser/identifier.d(83): ... (11 instantiations, -v to show) ... libd-llvm/libd/src/d/parser/base.d(14): instantiated from here: parseModule!(Lexer) src/sdc/sdc.d(54): instantiated from here: parse!(Lexer) libd-llvm/libd/src/d/parser/statement.d(406): Error: template instance d.parser.statement.parseStatement!(Lexer) error instantiating make: *** [bin/sdc] Erreur 1 Yes I added the bar on purpose in some heavily templated code. You concentrate too much on theses people that want to ship code without using it. They'll do it anyway. And that make even more sense from the lib user perspective, as having the compiler vomit kilometers of internals of a lib is usually not helpful (this happen a lot with phobos).
Mar 14 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Thu, 14 Mar 2013 11:38:52 -0400
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests.

What the hell is this, a JS/Python forum all of a sudden? You're literally making the exact same argument as "We don't need no steenkin' static type checking." On Thu, 14 Mar 2013 13:07:16 -0400 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 
 Very simple. Traditionally there's two crucial epochs known as 
 compilation time and run time. (There's some minor distinctions like 
 link time etc.) The whole notion of concepts and other type systems
 for templates is predicated on three crucial epochs: library
 compilation time, library user compilation time, and run time. The
 logic goes, someone writes a generic library and wants to distribute
 it to users. Users shouldn't ever see bugs caused by e.g. typos in
 the library.
 
 So the crowd that use meta-type systems is formed of library writers
 who want to distribute libraries without ever instantiating them. I
 don't think that's a good crowd to cater for.
 
 I've been surprised to figure how many people don't get this flow, or 
 only have a vague image of it. Although meta-types are arguably "the 
 right thing" to do, they're a lot less attractive once it's clear
 what scenarios they help.
 

That's because the flow is completely wrong. Particularly so in the context of a static-typed language. Where do I start?: - The branch of the discussion you're replying in has nothing to do with meta-types and yet you seem to be arguing on the false dichotomy of "Introduce meta-types vs no static checks on templates without instantiation". Please check the link in Don's post a few replies up. - "...library writers who want to distribute libraries without ever instantiating them..." is a hyperbolic strawman. Do you really expect us to believe that you and other respectable coders, let alone ordinary coders, *never* miss an instantiation? Of course not, and we both know that. So don't insult us by trying to paint this out as some "it only helps/encourages the lazy" bullshit. - We're talking a static-typed language here. The philosophy that "it's better to catch a whole class of errors as early regardless of whether the code in question gets used than to delay the check until a point where it may or may not get caught" is already a given. We're not Python here.
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 12:48:28PM -0400, Andrei Alexandrescu wrote:
 On 3/14/13 11:50 AM, deadalnix wrote:
On Thursday, 14 March 2013 at 15:38:53 UTC, Andrei Alexandrescu wrote:
On 3/14/13 11:05 AM, monarch_dodra wrote:
Having to instantiate a template just to check to make sure it is
semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests.



I don't say that unittest are useless, but why rely on unittest when
the machine can do the job for you ?

In both cases the machine does the work. My argument is that adding an additional layer of typing on top of templates caters to people who want to ship code that has literally zero testing. That's not a priority as far as I'm concerned.

I don't agree. Phobos is a prime example. Does Phobos have unittests? Yes, and lots of them. Does it still have non-compilable template instantiations? Yes, because unittests can't cover all possibilities -- there are too many possible combinations of template arguments. There are bound to be untested combinations which don't work but we're unaware of. We could, of course, automatically generate a very large number of template argument combinations and check to see if they're instantiable. In fact, we could write unittests that loop over every combination of a given list of types and instantiate the template to be tested with them. This is well within D's metaprogramming capabilities. But if we have to go that far, then it begs the original question: why not have the compiler do that for us? The compiler is better poised to make certain deductions using the type system, semantic analysis, etc., so that it doesn't literally have to enumerate every possible combination of template instantiation arguments just to prove it has no uncompilable instantiations. While I don't think D in its current state is going to be able to do this in a full way, the argument of catering to people shipping code without testing is invalid IMO. T -- Life would be easier if I had the source code. -- YHL
Mar 14 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/14/13, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 But if we have to go that far, then it begs the original question: why
 not have the compiler do that for us?

But where do you draw the line? There could be an unlimited number of permutations of how a template is instantiated. This would blow up compilation time by an unknown factor. And I doubt this would be simple to implement too.
Mar 14 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Thu, 14 Mar 2013 12:48:28 -0400
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 3/14/13 11:50 AM, deadalnix wrote:
 This is usualy much better to have the compiler smash your mistake
 right into your face than discovering with a unittest much latter.

I don't think so.

On Thu, 14 Mar 2013 12:49:01 -0400 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 3/14/13 12:32 PM, bearophile wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler.

No, this is different.

Man: An argument is a connected series of statements intended to establish a proposition. Andrei: No it isn't. Man: Yes it is! It's not just contradiction. Andrei: Look, if I argue with you, I must take up a contrary position. Man: Yes, but that's not just saying 'No it isn't.' Andrei: Yes it is! Man: No it isn't! Andrei: Yes it is! Man: Argument is an intellectual process. Contradiction is just the automatic gainsaying of any statement the other person makes. (short pause) Andrei: No it isn't.
Mar 14 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Thu, 14 Mar 2013 13:50:33 -0400
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 On 3/14/13 1:43 PM, Nick Sabalausky wrote:
 On Thu, 14 Mar 2013 11:38:52 -0400
 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>  wrote:

 On 3/14/13 11:05 AM, monarch_dodra wrote:
 Having to instantiate a template just to check to make sure it is
 semantically correct is a huge pain.

I'm not sure about that. The way I see it, no code should be not delivered without being unittested. Ubiquitous unittesting is now mainstream. The way I see it, a type system on top of templates would only help people who don't write unittests.

What the hell is this, a JS/Python forum all of a sudden? You're literally making the exact same argument as "We don't need no steenkin' static type checking."

No.

Yes.
Mar 14 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 14 March 2013 at 17:26:18 UTC, Andrei Alexandrescu 
wrote:
 Walter has measured coverage of Phobos unittests a couple of 
 times, it's very high. But I agree it would be nice to have it 
 as a target.

 Andrei

Sarcasm aside, this brought me to an idea for utilities for template fuzzy testing to check some instantiation combinations. Which is much more useful than plain line coverage check in case of templates. I have submitted pull request only a few weeks ago that fixed std.traits bug where template has failed to instantiate for function types (but not other types) despite 100% line coverage by unit test. It could have been checked automagically. Not sure what usage interface may be though.
Mar 14 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
On Thursday, 14 March 2013 at 17:51:23 UTC, Andrei Alexandrescu 
wrote:
 If you found a few, that would be great. I don't think you'll 
 have an easy time.

 Andrei

In other comment I have mentioned a case I have fixed just 15 days ago: https://github.com/D-Programming-Language/phobos/pull/1182 100% line coverage, compile-time error for certain type parameter subset. Could have been found by compiler / clever-enough framework. That was easy.
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 06:09:26PM +0100, Andrej Mitrovic wrote:
 On 3/14/13, bearophile <bearophileHUGS lycos.com> wrote:
 This is an invalid argument. You can say the same thing for many
 (most?) tests done by the compiler. Unit tests can't be sure to
 verify all code paths inside a function or template.

No, it must do exactly that. If you have so many paths that you can't reasonably test all paths then your template or function is too complicated to begin with. The benefit here of D over C++ is that unit testing is cheap and doesn't require external libraries.

I think you're missing the point. The point is that concepts allow the compiler to deduce template correctness *without* instantiating it with every possible combination of types. Right now, we *don't* have concepts, and therefore the only way to ensure template correctness is to iterate over the exponential number of combinations of template arguments. But if we *had* concepts, then the compiler could reason about code correctness without needing to explicitly check every instantiation -- thus effectively covering all possible combinations, but without actually doing it. It's the difference between proving a boolean statement is tautologous by reducing it to true using known logic identities, vs. looping over every combination of variable assignments and checking that they all evaluate to true. T -- Кто везде - тот нигде.
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 A concept system would have helped me there if my intent was to 
 ship Kahan summation without ever testing it. That's not an 
 intent we want to cater for!

I think Issue 9715 isn't about Concepts. - - - - - Regarding the more general topic of Concepts (and their almost equivalent Typeclasses (http://dotat.at/tmp/p37-bernardy.pdf ) of the Rust language, or more powerful in Haskell), the argument you are proposing is exactly the same used by dynamic language proponents against static typing. A difference is that adding a static type system to Ruby causes much larger changes compared to adding typeclasses to Rust (Rust didn't have typeclasses since recently. Rust used to have templates similar to C++, with some restrictions). Haskell programmers have typeclasses, yet unit testing is done in Haskell, they have even invented a testing idea that was widely copied (QuickCheck). Types (like ones of Typeclasses and Concepts) help avoid catch some bugs and shape your style of coding, the unittests avoid the other bugs and shape your coding, and contract programming catches other bugs and they too shape the way you code, for the better. In the last Haskell version they have introduced a static type system at level of kinds, and it helps avoid some other bugs, or to catch them earlier. For a Haskell programmer the great and numerous advantages of Concepts/Typeclasses are not in discussion. I think Rust programmers are now learning to appreciate them. Bye, bearophile
Mar 14 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 14, 2013 13:26:18 Andrei Alexandrescu wrote:
 Walter has measured coverage of Phobos unittests a couple of times, it's
 very high. But I agree it would be nice to have it as a target.

Though this is exactly a case where 100% unit test coverage doesn't mean much. All that means is that each path has been instantiated and run. It doesn't mean that it's covered enough possible instantiations to properly test the template. For instance, a simple bug like making it so that hasLength!R ends up choosing a static if path which assumes random access wouldn't be caught unless you happened to test that template with a range which has length but doesn't have random access, and even with thorough testing, there's bound to be some particular genre of range that gets missed in the unit tests. But barring something that makes it impossible or unreasonable, we really should be shooting for 100% code coverage. assert(0) would a prime case where it's impossible (even std.datetime only had 98% or 99% code coverage the last time I checked, precisely because of assert(0)), and I'm sure that there are other cases, but we should be able to get close. - Jonathan M Davis
Mar 14 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 14, 2013 13:07:16 Andrei Alexandrescu wrote:
 Very simple. Traditionally there's two crucial epochs known as
 compilation time and run time. (There's some minor distinctions like
 link time etc.) The whole notion of concepts and other type systems for
 templates is predicated on three crucial epochs: library compilation
 time, library user compilation time, and run time. The logic goes,
 someone writes a generic library and wants to distribute it to users.
 Users shouldn't ever see bugs caused by e.g. typos in the library.
 
 So the crowd that use meta-type systems is formed of library writers who
 want to distribute libraries without ever instantiating them. I don't
 think that's a good crowd to cater for.
 
 I've been surprised to figure how many people don't get this flow, or
 only have a vague image of it. Although meta-types are arguably "the
 right thing" to do, they're a lot less attractive once it's clear what
 scenarios they help.

The main problem is not people who don't unit test their templates but the fact that it's pretty much impossible to cover every possible instantiation of a template, and so it can be pretty easy to miss stuff. Better unit testing will obviously cover more, and on the whole, I think that that's a fine solution, but it would also be nice if the compiler caught more. However, given that it's pretty much a given that the compiler won't catch the stuff that's actually going to be a problem (e.g. a type with weird characteristics due to alias this or whatnot ends up not working correctly with a template), I'm not sure that it the compiler really can be improved to help out in any meaningful way. In general, the more the compiler can catch for you at compile time, the better, but there are definite limits to that even with a very smart compiler (and the smarter the compiler, the more likely it is to be buggy). - Jonathan M Davis
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

 I understand this. But my experience in the matter has been 
 that if the tests cover 100% of the code paths, the incidence 
 of undetected bugs in the code goes very, very low.

This is not so much true for template-heavy code. And 100% code coverage is not enough even for regular code, that's why they have invented this for Java: http://dev.theladders.com/2013/02/mutation-testing-with-pit-a-step-beyond-normal-code-coverage/ Bye, bearophile
Mar 14 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
You are awesome.
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 10:26:54PM +0100, bearophile wrote:
[[...]
 And 100% code coverage is not enough even for regular code, that's why
 they have invented this for Java:
 
 http://dev.theladders.com/2013/02/mutation-testing-with-pit-a-step-beyond-normal-code-coverage/

We need this in D. I want this in D. :) Recently, while writing a new D module, the thought occurred to me that perhaps my unittests aren't enough. Sure, it's good to have tons of unittests, but how effective are they? Do they really fail when I think they should, or do they just silently pass anyway when a bug is introduced? This paper answered that question for me. :) I think maybe the dustmite code can be adapted to do mutation testing, esp. the part that identifies what can be deleted from the code? I'm not sure exactly how dustmite identifies declarations/statements to be deleted, but that could be a start on doing mutation testing. T -- Why can't you just be a nonconformist like everyone else? -- YHL
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 05:54:05PM -0400, Andrei Alexandrescu wrote:
 On 3/14/13 2:38 PM, Jonathan M Davis wrote:
On Thursday, March 14, 2013 13:26:18 Andrei Alexandrescu wrote:
Walter has measured coverage of Phobos unittests a couple of times,
it's very high. But I agree it would be nice to have it as a target.

Though this is exactly a case where 100% unit test coverage doesn't mean much. All that means is that each path has been instantiated and run. It doesn't mean that it's covered enough possible instantiations to properly test the template.

Concepts won't help there either.

It does help. For example, if the code wrongly assumes mutability for a particular template type, then it may work for most test cases (frankly, I find const/immutable unittest coverage in Phobos very poor) but fail when some daring user passes const(T) instead of T to the template. For example, you may have accidentally written the equivalent of: auto func(T)(T t) { Unqual!T u = t; // <-- spot the bug ... } Under a concepts system, this would be caught early because the compiler would detect a concept mismatch (Unqual!T != T) when analysing the template code. Currently, though, if there is no unittest that tries instantiating the template with const(T), the bug goes undetected, because in all *tested* instantiations, Unqual!T == T. T -- Famous last words: I wonder what will happen if I do *this*...
Mar 14 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 14, 2013 17:54:05 Andrei Alexandrescu wrote:
 On 3/14/13 2:38 PM, Jonathan M Davis wrote:
 On Thursday, March 14, 2013 13:26:18 Andrei Alexandrescu wrote:
 Walter has measured coverage of Phobos unittests a couple of times, it's
 very high. But I agree it would be nice to have it as a target.

Though this is exactly a case where 100% unit test coverage doesn't mean much. All that means is that each path has been instantiated and run. It doesn't mean that it's covered enough possible instantiations to properly test the template.

Concepts won't help there either.

Oh, they may not. My point was simply that while 100% code coverage is great, when you're dealing with templated functions, it's generally nowhere near enough (especially as the number of static ifs goes up), because there could easily be other template arguments which pass the template constraint but won't even compile with the template, let alone work correctly. For instance, while we've been getting better at it, it's generally been a weakness of std.range and std.algorithm that reference-type ranges aren't tested properly and don't work properly with various functions, and yet those same functions generally have good code coverage. Really, it just means that we need to be thorough in the number of template instantiations tested and not think that 100% code coverage is enough, but I can understand people wanting to find ways to get the compiler to catch some of that for them. - Jonathan M Davis
Mar 14 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 14, 2013 14:40:11 Walter Bright wrote:
 On 3/14/2013 2:26 PM, bearophile wrote:
 Walter Bright:
 I understand this. But my experience in the matter has been that if the
 tests cover 100% of the code paths, the incidence of undetected bugs in
 the code goes very, very low.

This is not so much true for template-heavy code.

I don't believe that without further evidence.

It's been fairly frequent that std.range and std.algorithm don't work correctly with reference type ranges. The only way to catch that is to test those functions with reference type ranges. 100% code coverage won't get you there. I fully agree that it's a big step in the right direction, but I don't think that it's been all that uncommon for there to be bugs in Phobos where some ranges work and some don't when the buggy function had high code coverage - it just was likely to be testing primarily with arrays and not enough with other range types. We've definitely been reducing the number of those types of bugs, but they were caught because people tried to instantiate them with types that the unit tests didn't test. - Jonathan M Davis
Mar 14 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, March 14, 2013 17:58:44 Andrei Alexandrescu wrote:
 b) unifying template fuzzy testing in Phobos
 
 We have lots of these wheels reinvented across Phobos alone.

Like those dummy ranges in std.algorithm?

I had improved versions of those that I was working on which were more flexible and thorough. I really should get back to sorting those out and submit them (IIRC, I was blocked by bugs which have now been fixed). - Jonathan M Davis
Mar 14 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 14, 2013 at 06:18:58PM -0400, Andrei Alexandrescu wrote:
 On 3/14/13 6:02 PM, H. S. Teoh wrote:
On Thu, Mar 14, 2013 at 05:54:05PM -0400, Andrei Alexandrescu wrote:
On 3/14/13 2:38 PM, Jonathan M Davis wrote:



Though this is exactly a case where 100% unit test coverage doesn't
mean much.  All that means is that each path has been instantiated
and run. It doesn't mean that it's covered enough possible
instantiations to properly test the template.

Concepts won't help there either.

It does help. For example, if the code wrongly assumes mutability for a particular template type, then it may work for most test cases (frankly, I find const/immutable unittest coverage in Phobos very poor) but fail when some daring user passes const(T) instead of T to the template. For example, you may have accidentally written the equivalent of: auto func(T)(T t) { Unqual!T u = t; //<-- spot the bug ... } Under a concepts system, this would be caught early because the compiler would detect a concept mismatch (Unqual!T != T) when analysing the template code. Currently, though, if there is no unittest that tries instantiating the template with const(T), the bug goes undetected, because in all *tested* instantiations, Unqual!T == T.

Template constraints start from the most permissive end of the spectrum: by default there's no verification, and constraints add verification. With typeclasses it's the other way around: by default nothing is allowed, so code needs to add permissions explicitly.

I like this way of looking at it. So basically, typeclasses force us to state all assumptions up-front, whereas template constraints leave room for oversight (forget to put isForwardRange!R in the constraints but use .save in the function body).
 I agree that in that regard typeclasses are better than template
 constraints. Of course there are many other aspects to be considered
 when comparing the two.

Yes, and I'm not saying that we should discard template constraints and adopt typeclasses wholesale. I can't say I'm totally sold on typeclasses either, because they do introduce their own tradeoffs. But neither should we dismiss the typeclasses approach so lightly. In fact, now that I think of it, templates in general suffer from this problem: when you write template X(T) { ... }, pretty much anything goes in the template body, even outright ridiculous things that won't compile for *any* template arguments. But more commonly, the template body may assume things about T that don't apply across all types T. You may assume that T is mutable, or that T has a certain member, etc.. What if templates were modified so that assumptions about T have to be stated up front? We don't necessarily have to introduce typeclasses as a separate thing, but we could have the compiler reject template bodies that try to access internals of T that aren't stated up front. E.g.: auto myFunc(T)(T t) { return t.fun(); // error: T wasn't stated to have a member named .fun } would produce a compile error, whereas: auto myFunc(T)(T t) if (hasMember!(T, "fun")) { return t.fun(); // OK: we stated that we expect T to have a .fun member } would be accepted. The stated assumptions can themselves be templates too, which are expanded by the compiler before checking the template body. (Presumably, hasMember will eventually expand to some compiler intrinsic that tells the compiler what assumptions are being made about T.) So we can still continue using things like isInputRange!T, etc., except that now the compiler will catch unstated assumptions. IOW, make signature constraints mandatory rather than optional. Arguably, signature constraints *should* be mandatory in properly-written generic code anyway, so this can only add value. And it will not break existing code if said code is properly-written. T -- The right half of the brain controls the left half of the body. This means that only left-handed people are in their right mind. -- Manoj Srivastava
Mar 14 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
H. S. Teoh:

 What if templates were modified so that assumptions about T 
 have to be
 stated up front? We don't necessarily have to introduce 
 typeclasses as a
 separate thing, but we could have the compiler reject template 
 bodies
 that try to access internals of T that aren't stated up front. 
 E.g.:

 	auto myFunc(T)(T t) {
 		return t.fun();	// error: T wasn't stated to have a member 
 named .fun
 	}

 would produce a compile error, whereas:

 	auto myFunc(T)(T t)
 		if (hasMember!(T, "fun"))
 	{
 		return t.fun();	// OK: we stated that we expect T to have a 
 .fun member
 	}

 would be accepted. The stated assumptions can themselves be 
 templates
 too, which are expanded by the compiler before checking the 
 template
 body. (Presumably, hasMember will eventually expand to some 
 compiler
 intrinsic that tells the compiler what assumptions are being 
 made about
 T.) So we can still continue using things like isInputRange!T, 
 etc.,
 except that now the compiler will catch unstated assumptions.

What's the difference between this and Concepts (lite)? :-) Bye, bearophile
Mar 14 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 14 March 2013 at 20:57:57 UTC, Timon Gehr wrote:
 On 03/14/2013 06:51 PM, Andrei Alexandrescu wrote:
 On 3/14/13 1:48 PM, H. S. Teoh wrote:
 I don't agree. Phobos is a prime example. Does Phobos have 
 unittests?
 Yes, and lots of them. Does it still have non-compilable 
 template
 instantiations? Yes, because unittests can't cover all 
 possibilities --
 there are too many possible combinations of template 
 arguments. There
 are bound to be untested combinations which don't work but 
 we're unaware
 of.

If you found a few, that would be great. I don't think you'll have an easy time. Andrei

Challenge accepted. Clearly the Phobos developers do not instantiate their templates before shipping them. :o) The following breaks most of std.range, and most of std.algorithm could likely be broken too, but I am too lazy to investigate.

All this breakage is just one and the same bug. These ranges, for some reason, are testing Unqual!Range, and then attempt to store an Unqual!Range, which makes no sense, since the passed type is not Unqual!Range, it's Range. Probably an old C++ habit, where you can cast away constness by copy. This is not the case in D. In any case, all of std.range (and some of algorithm) need to be stripped of this.
Mar 14 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Thu, 14 Mar 2013 15:57:59 -0700
"H. S. Teoh" <hsteoh quickfur.ath.cx> wrote:
 
 In fact, now that I think of it, templates in general suffer from this
 problem: when you write template X(T) { ... }, pretty much anything
 goes in the template body, even outright ridiculous things that won't
 compile for *any* template arguments. But more commonly, the template
 body may assume things about T that don't apply across all types T.
 You may assume that T is mutable, or that T has a certain member,
 etc..
 
 What if templates were modified so that assumptions about T have to be
 stated up front? We don't necessarily have to introduce typeclasses
 as a separate thing, but we could have the compiler reject template
 bodies that try to access internals of T that aren't stated up front.
 E.g.:
 

C#'s generics work that way. I always liked that. The only problem is that MS never bothered to provide a constraint for "can do arithmetic" (like they have for "can be compared", ie IComparable) so you can't do a basic thing like "a + b" generically.
Mar 14 2013
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Thu, 14 Mar 2013 17:54:52 -0400
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 it's not like we claim to support input ranges and
 then call .save against them.

Although this is getting OT, we do kind of do that in a way: It's very common for a range to be a struct rather than a class. In fact, std.range/algorithm has generally been considered to work better with struct ranges with class ranges being a secondary thought. And yet, due the the nature of structs, all it takes to effectively ".save" an InputRange (or at least attempt to) is this: struct MyInputRange {...} void foo(R)(R r) if(isInputRange!R) { auto s = r; } ... foo(MyInputRange()); That implicitly does the equivalent of ".save" on a mere InputRange *twice*. The result, of course, is completely dependent on the input range in question.
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 23:52:59 UTC, Nick Sabalausky wrote:
 On Thu, 14 Mar 2013 17:54:52 -0400
 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 it's not like we claim to support input ranges and
 then call .save against them.

Although this is getting OT, we do kind of do that in a way: It's very common for a range to be a struct rather than a class. In fact, std.range/algorithm has generally been considered to work better with struct ranges with class ranges being a secondary thought. And yet, due the the nature of structs, all it takes to effectively ".save" an InputRange (or at least attempt to) is this: struct MyInputRange {...} void foo(R)(R r) if(isInputRange!R) { auto s = r; } ... foo(MyInputRange()); That implicitly does the equivalent of ".save" on a mere InputRange *twice*. The result, of course, is completely dependent on the input range in question.

Passing range by value is completely undefined, which is IMO a big weak spot of ranges.
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 17:53:42 UTC, Andrei Alexandrescu 
wrote:
 On 3/14/13 1:37 PM, deadalnix wrote:
 On Thursday, 14 March 2013 at 17:07:16 UTC, Andrei 
 Alexandrescu wrote:
 Very simple. Traditionally there's two crucial epochs known as
 compilation time and run time. (There's some minor 
 distinctions like
 link time etc.) The whole notion of concepts and other type 
 systems
 for templates is predicated on three crucial epochs: library
 compilation time, library user compilation time, and run 
 time. The
 logic goes, someone writes a generic library and wants to 
 distribute
 it to users. Users shouldn't ever see bugs caused by e.g. 
 typos in the
 library.

I'm not sure if you are thinking I'm really stupid here.

Being wrong doesn't make one stupid.

I may be wrong, but certainly not because I don't make the difference between compile time and run time.
 Template constraints are D's solution to that issue. I agree 
 it's not perfect, but I think dollar for dollar it's better 
 than concepts.

No they aren't, because it would only skip the top most lines and replace the error by something like impossible to find method blah. With something like concept, I'd have something like in case of eroneous template : file:line: Error: concept Blah don't have member blah. Or in the case of unmatched constraint : file:line: Error: template Blah except a concept argument of meta-type Foo, Bar given. And in both cases you can avoid the dreaded wall of error.
Mar 14 2013
prev sibling next sibling parent "Don" <turnyourkidsintocash nospam.com> writes:
On Friday, 15 March 2013 at 06:51:15 UTC, Dmitry Olshansky wrote:
 15-Mar-2013 10:47, Walter Bright пишет:
 On 3/14/2013 11:36 PM, Dmitry Olshansky wrote:
 15-Mar-2013 01:58, Andrei Alexandrescu пишет:
 On 3/14/13 4:37 PM, Dmitry Olshansky wrote:
 Point taken. That doesn't detract us from:
 a) fixing issues with -cov

Yes please (are there bugzilla entries etc)?

template powerup(T) //usable as template mixin too { //imagine more constraints static if(size_t.sizeof == 4) alias bleh = blah; else alias bleh = oldBlah; //... } Now first mixin template don't get counted at all (even code within). Then declarations are ignored and you'll never know which ones were ever looked at.

-cov only counts executable lines. The above are not executable - I don't see any way to make them work with -cov.

The information can be trivially collected during semantic analysis of declarations. How to merge this compile-time info with run-time one as in -cov is a another question. I'd try outputting some table into object file (special section etc.) and then -cov would use it to mark non-executable code.

We need to do something like this. Without some kind of "instantiation coverage", it's practically impossible to be confident that your D templates are correct. Actually I'm not certain that it needs to be the same file as -cov. I mean, you might want to check that you have 100% template instantiation coverage, before you do your runtime tests. It can be interesting to know that a line in a function template is instantiated 10 times, and run 3 times, whereas another line is run 857 times, but only instantiated once.
Mar 15 2013
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-03-12, 23:49, Hans Uhlig wrote:

 On 3/9/2013 10:10 AM, deadalnix wrote:
 On Saturday, 9 March 2013 at 17:51:31 UTC, Ali =C3=87ehreli wrote:
 On 03/09/2013 03:15 AM, Artur Skawina wrote:

   - static-if not creating scopes /is/ confusing, but what

     alternative?

I am surprised that << and >> are never mentioned: static_if >> void foo(); << Problem solved. ;) Ali

static if(condition) =C2=AB void foo(); =C2=BB Let's do it with style ;)

So now I am going to need a unicode keyboard or a massive list of =

 unicode code points.

Or we could make the language latex-aware, and use \guillemotleft and \guillemotright. That would also solve the problem of operators =E2=88=83= , =E2=88=9A, =E2=8A=82, =E2=88=A9, =E2=88=99, =E2=A8=AF, and the like. I kid, of course. But it might be worth having a look at Fortress for their representational and editable forms, as well as the wealth of overloadable operators. -- = Simen
Mar 20 2013