Re: More bugs...

2012-05-02 Thread Steven Schveighoffer

On Tue, 01 May 2012 22:11:18 -0400, Mehrdad  wrote:


More problems... similar, but this time related to templates.

  struct Filter(R) { this(R) { } }
  template filter(R) { alias Filter!(R).__ctor filter; }
  void main() { filter([1, 2, 3]); }

Error: template linq.filter(R) is not a function template


It's an annoying limitation.  IFTI specifically *only* works with  
functions.  Not aliases, not types, not anything else.  Functions only.


-Steve


Re: More bugs...

2012-05-02 Thread Artur Skawina
On 05/02/12 04:11, Mehrdad wrote:
> More problems... similar, but this time related to templates.
> 
>  struct Filter(R) { this(R) { } }
>  template filter(R) { alias Filter!(R).__ctor filter; }
>  void main() { filter([1, 2, 3]); }
> 
> Error: template linq.filter(R) is not a function template
> 
> 
> Why?

Because it isn't? Where would 'R' come from in your example?...

   auto filter(R)(R r) { return Filter!R(r); }


artur


Re: More bugs...

2012-05-02 Thread Timon Gehr

On 05/02/2012 04:14 AM, Mehrdad wrote:

Yes, that non-global issue was the exact issue I was referring to. It
drives me nuts whenever I try to give in and use templates.


Regarding your "fix":
Is it *really* intended that user should say
arr.filter((typeof(some_random_expression) x) => x < y);
instead of
arr.filter(x => x < y);
?

I think it's pretty obvious why that doesn't really work in practice...


I agree that it should be fixed, but it is technically not a bug in the 
implementation.


Re: More bugs...

2012-05-01 Thread Mehrdad
Yes, that non-global issue was the exact issue I was referring to. It drives 
me nuts whenever I try to give in and use templates.



Regarding your "fix":
Is it *really* intended that user should say
  arr.filter((typeof(some_random_expression) x) => x < y);
instead of
  arr.filter(x => x < y);
?

I think it's pretty obvious why that doesn't really work in practice... 



Re: More bugs...

2012-05-01 Thread Mehrdad

More problems... similar, but this time related to templates.

 struct Filter(R) { this(R) { } }
 template filter(R) { alias Filter!(R).__ctor filter; }
 void main() { filter([1, 2, 3]); }

Error: template linq.filter(R) is not a function template


Why?


Re: More bugs...

2012-05-01 Thread Mehrdad

Yeah I just posted it yesterday.
http://d.puremagic.com/issues/show_bug.cgi?id=8009

"Robert Clipsham"  wrote in message news:jnoi6g$1f79$1...@digitalmars.com... 


On 01/05/2012 02:00, Mehrdad wrote:

Some ICE for y'all.

void filter(R)(scope bool delegate(ref BAD!R) func) { }
void main() { filter(r => r); }


Is this in bugzilla? It can't get fixed if no one knows about it! (Make 
sure to give it the ice keyword once you've submitted so it gets bumped 
to the top of the queue!)


--
Robert
http://octarineparrot.com/


Re: More bugs...

2012-05-01 Thread Timon Gehr

On 05/01/2012 01:20 PM, Mehrdad wrote:

I guess the problem is with type deduction, but the trouble is that half
the reason why type deduction is useful is in the case of lambdas. They
become effectively useless if you have to type out their entire
signature, since you could then just make them a separate function (or
just use a mixin instead, to create a closure... which I've done before).

This isn't really an 'enhancement', since the error message is clearly a
bug. So I filed them both as bugs.

http://d.puremagic.com/issues/show_bug.cgi?id=8009
http://d.puremagic.com/issues/show_bug.cgi?id=8010

The other bug I was referring to was something along the lines of the
compiler telling me, "I can't really handle closures as template
parameters very well (something about 'local variable' or whatever), so
I'll just give you an obscure error every now and then".
It only happened when it was inside another function, and some
conditions were satisfied. (I don't remember the exact message, but when
I searched it, I saw it had been already reported before...)



Probably you mean this one:

struct S{
int x;
auto foo(alias a)(){return a(x);}
}

void main(){
auto s = S(2);
int y = 3;
writeln(s.foo!(x=>x+y)());
}

Error: template instance foo!(__lambda2) cannot use local 
'__lambda2(__T1)' as parameter to non-global template foo(alias a)


This is an arbitrary restriction and should be fixed. The 'this' pointer 
for 'foo' could be passed in a reserved slot at the beginning of the 
context for 'main'.





Oh and thanks for the alternative, it's a good workaround to know. :)

The trouble is that while it solves the bug I posted, it's still not
solving my (actual) problem.
The actual problem was that I wanted to do something along the lines of:

private import std.range;
auto filter(R, F)(R r, F f) { /*return a filtered range*/ }
void main() { [1, 2, 3].filter(x => x < 3); }



private import std.range;
auto filter(R, F)(R r, F f) { /*return a filtered range*/ }
void main() { [1, 2, 3].filter((int x) => x < 3); }


Re: More bugs...

2012-05-01 Thread Robert Clipsham

On 01/05/2012 02:00, Mehrdad wrote:

Some ICE for y'all.

void filter(R)(scope bool delegate(ref BAD!R) func) { }
void main() { filter(r => r); }


Is this in bugzilla? It can't get fixed if no one knows about it! (Make 
sure to give it the ice keyword once you've submitted so it gets bumped 
to the top of the queue!)


--
Robert
http://octarineparrot.com/


Re: More bugs...

2012-05-01 Thread Mehrdad
I guess the problem is with type deduction, but the trouble is that half the 
reason why type deduction is useful is in the case of lambdas. They become 
effectively useless if you have to type out their entire signature, since 
you could then just make them a separate function (or just use a mixin 
instead, to create a closure... which I've done before).


This isn't really an 'enhancement', since the error message is clearly a 
bug. So I filed them both as bugs.


http://d.puremagic.com/issues/show_bug.cgi?id=8009
http://d.puremagic.com/issues/show_bug.cgi?id=8010

The other bug I was referring to was something along the lines of the 
compiler telling me, "I can't really handle closures as template parameters 
very well (something about 'local variable' or whatever), so I'll just give 
you an obscure error every now and then".
It only happened when it was inside another function, and some conditions 
were satisfied. (I don't remember the exact message, but when I searched it, 
I saw it had been already reported before...)



Oh and thanks for the alternative, it's a good workaround to know. :)

The trouble is that while it solves the bug I posted, it's still not solving 
my (actual) problem.

The actual problem was that I wanted to do something along the lines of:

private import std.range;
auto filter(R, F)(R r, F f) { /*return a filtered range*/ }
void main() { [1, 2, 3].filter(x => x < 3); }

but I resorted to 'delegates' because this didn't work.
However, when I did so, I decided to use a delegate anyway, while using 
'scope' on the delegate and its parameter to avoid a heap allocation, but 
that didn't work either...
so I just filed the bug report with a case that had less type inference. But 
the trouble is that the caller needing to say "delegate" is *already* too 
much typing, so the rest don't really help. :\



On 05/01/2012 04:02 AM, Mehrdad wrote:

Wha..?!

I can't believe delegates work so poorly in D...


It is not the delegates, it is the type deduction algorithm for implicit
function template instantiation. The issue is that the parameters do not
cross-talk, which means R is not known during matching: How to detect
the argument type from bool delegate(ElementType!R) alone if R is not
known? The obvious solution would be to use an actual inference
algorithm that uses information that can be gained from other parameters
as well as information already known from the current parameter.

You might want to file an enhancement request, because this exact thing
seems to trip up many programmers. (i.e. it would be a lot more
intuitive and convenient if it worked.)



they're practically
unusable unless you're passing them as template parameters (which brings
on its own set of bugs)...


I haven't encountered those so far.



Seems like every time I try to escape a bug somehow, another one pops up 
:(




The situation is improving. Furthermore, there is a very large subset of
the language that is already very usable.

Another way to make your code compile:

private import std.range;
void filter(R,S)(R, bool delegate(S)) if(is(S==ElementType!R)){ }
void main() { [1, 2, 3].filter((int x) { return x < 3; }); } 



Re: More bugs...

2012-05-01 Thread Timon Gehr

On 05/01/2012 04:02 AM, Mehrdad wrote:

Wha..?!

I can't believe delegates work so poorly in D...


It is not the delegates, it is the type deduction algorithm for implicit 
function template instantiation. The issue is that the parameters do not 
cross-talk, which means R is not known during matching: How to detect 
the argument type from bool delegate(ElementType!R) alone if R is not 
known? The obvious solution would be to use an actual inference 
algorithm that uses information that can be gained from other parameters 
as well as information already known from the current parameter.


You might want to file an enhancement request, because this exact thing 
seems to trip up many programmers. (i.e. it would be a lot more 
intuitive and convenient if it worked.)




they're practically
unusable unless you're passing them as template parameters (which brings
on its own set of bugs)...


I haven't encountered those so far.



Seems like every time I try to escape a bug somehow, another one pops up :(



The situation is improving. Furthermore, there is a very large subset of 
the language that is already very usable.


Another way to make your code compile:

private import std.range;
void filter(R,S)(R, bool delegate(S)) if(is(S==ElementType!R)){ }
void main() { [1, 2, 3].filter((int x) { return x < 3; }); }


Re: More bugs...

2012-04-30 Thread Mehrdad

Wha..?!

I can't believe delegates work so poorly in D... they're practically 
unusable unless you're passing them as template parameters (which brings on 
its own set of bugs)...


Seems like every time I try to escape a bug somehow, another one pops up :(


"Timon Gehr"  wrote in message news:jnnfc6$2jve$2...@digitalmars.com...

On 05/01/2012 03:46 AM, Mehrdad wrote:

Is it just "weak", or is it outright wrong?


Unfortunately it is by design that it does not work afaik.


It's telling me "R" isn't a valid identifier...



That one is a diagnostics bug. 



Re: More bugs...

2012-04-30 Thread Timon Gehr

On 05/01/2012 03:46 AM, Mehrdad wrote:

Is it just "weak", or is it outright wrong?


Unfortunately it is by design that it does not work afaik.


It's telling me "R" isn't a valid identifier...



That one is a diagnostics bug.



Re: More bugs...

2012-04-30 Thread Mehrdad

Is it just "weak", or is it outright wrong?
It's telling me "R" isn't a valid identifier...


"Timon Gehr"  wrote in message news:jnnefl$2j69$1...@digitalmars.com... 


On 05/01/2012 03:09 AM, Mehrdad wrote:

Also, what exactly is wrong with this code?

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter(delegate bool(x) { return x < 3; }); }



The current type deduction strategy for IFTI is (imho) too weak.

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter!(int[])(delegate bool(x) { return x < 3; 
}); }


Re: More bugs...

2012-04-30 Thread Timon Gehr

On 05/01/2012 03:09 AM, Mehrdad wrote:

Also, what exactly is wrong with this code?

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter(delegate bool(x) { return x < 3; }); }



The current type deduction strategy for IFTI is (imho) too weak.

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter!(int[])(delegate bool(x) { return x < 3; 
}); }


Re: More bugs...

2012-04-30 Thread Mehrdad

Also, what exactly is wrong with this code?

private import std.range;
void filter(R)(R, bool delegate(ElementType!R)) { }
void main() { [1, 2, 3].filter(delegate bool(x) { return x < 3; }); }



Re: More bugs...

2012-04-30 Thread Mehrdad

Some ICE for y'all.

void filter(R)(scope bool delegate(ref BAD!R) func) { }
void main() { filter(r => r); }


Re: More bugs...

2012-04-29 Thread SomeDude

On Sunday, 29 April 2012 at 06:22:34 UTC, James Miller wrote:
D templates are analysed eagerly upon instantiation, whereas 
C++ templates are analysed lazily. This is not a bug, it is a 
feature.


Furthermore, eager analysis is necessary for other D features 
like CTFE and compile-time reflection.


Ah, I was  wondering about that. Thank you for confirming.
I will gladly ditch lazy template eval for something like CTFE.

Honestly, in C++ I would stay away from code like the above 
anyway, irrelevant of whether it compiles, seems too "magic-y" 
for my tastes. I don't like things not being explicit.




+1



Re: More bugs...

2012-04-28 Thread James Miller

On Saturday, 28 April 2012 at 09:36:55 UTC, Timon Gehr wrote:

On 04/28/2012 08:03 AM, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
   F > f() { return F >(); }
};

int main()
{
   F().f().f().f().f().f();  // etc.
   return 0;
}



D templates are analysed eagerly upon instantiation, whereas 
C++ templates are analysed lazily. This is not a bug, it is a 
feature.


Furthermore, eager analysis is necessary for other D features 
like CTFE and compile-time reflection. Honestly, in C++ I would 
stay away from code like the above anyway, irrelevant of whether 
it compiles, seems too "magic-y" for my tastes. I don't like 
things not being explicit.


--
James Miller


Re: More bugs...

2012-04-28 Thread Timon Gehr

On 04/28/2012 12:05 PM, Max Samukha wrote:

On Saturday, 28 April 2012 at 09:40:49 UTC, Timon Gehr wrote:

On 04/28/2012 09:46 AM, Max Samukha wrote:

On Saturday, 28 April 2012 at 06:03:54 UTC, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
F > f() { return F >(); }
};

int main()
{
F().f().f().f().f().f(); // etc.
return 0;
}



dmd is not smart enough


DMD behaves according to the language specification here.

That is not specified anywhere in the language specification.



"Semantic analysis is not done until instantiated."

On second thought, you are right, this is really badly phrased and does 
not say what it probably wants to. Anyway, the fact that templates are 
analysed fully eagerly upon instantiation is by design and the 
documentation should explicitly state that.





to avoid recursion by treating f as a
templated function. I am not sure whether it should,


Maybe, but that would be a strange special case.


That is arguable.


If we are talking about the same thing, then it probably is not. I 
thought you were proposing to automatically templatise the function iff 
there is recursion?



Non-templated functions are a special (degenerate) case of templated functions.


How to 'instantiate' a non-templated function? This would necessarily be 
a supported operation, if there actually was such a relation between the 
two concepts.



The way virtual functions work doesn't allow C++/D to fully implement that 
notion.


That implies that the notion does not have merit. In D it was left out 
by design. And even C++ does not consistently implement it for non-virtuals.



Mark f() 'virtual' in the C++ example and the code won't compile.


I know. Furthermore, add an invalid member function to the templated 
struct F and don't refer to it. There won't be any compile time error. 
(unless it is virtual, of course!)



Otherwise, C++ tries to be close to the ideal


IMAO, it fails to be close to the ideal.


and I would expect D be no worse.



Yah, and it really is not.

The other issue you brought up in this thread is certainly a real issue 
with the implementation though.


Re: More bugs...

2012-04-28 Thread Max Samukha

On Saturday, 28 April 2012 at 09:40:49 UTC, Timon Gehr wrote:

On 04/28/2012 09:46 AM, Max Samukha wrote:

On Saturday, 28 April 2012 at 06:03:54 UTC, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
  F > f() { return F >(); }
};

int main()
{
  F().f().f().f().f().f();  // etc.
  return 0;
}



dmd is not smart enough


DMD behaves according to the language specification here.

That is not specified anywhere in the language specification.




to avoid recursion by treating f as a
templated function. I am not sure whether it should,


Maybe, but that would be a strange special case.


That is arguable. Non-templated functions are a special 
(degenerate) case of templated functions. The way virtual 
functions work doesn't allow C++/D to fully implement that 
notion. Mark f() 'virtual' in the C++ example and the code won't 
compile. Otherwise, C++ tries to be close to the ideal and I 
would expect D be no worse.





but the following should certainly work:

struct F(T)
{
 auto f()() { return F!(F!T)(); }
}

void main()
{
 F!int().f().f().f();
}

Error: struct a.F(T) recursive template expansion for template
argument - why?



The checking for infinite recursion seems to be too 
conservative here. You could open a bug report.





Re: More bugs...

2012-04-28 Thread SomeDude

On Saturday, 28 April 2012 at 09:36:55 UTC, Timon Gehr wrote:

On 04/28/2012 08:03 AM, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
   F > f() { return F >(); }
};

int main()
{
   F().f().f().f().f().f();  // etc.
   return 0;
}



D templates are analysed eagerly upon instantiation, whereas 
C++ templates are analysed lazily. This is not a bug, it is a 
feature.


Having browsed several hundreds bug reports lately, I've seen a 
number of reports complaining that recursive templates 
instantiation failed. I've resisted the urge to comment that they 
were invalid. Although I do think they are invalid.


Re: More bugs...

2012-04-28 Thread Timon Gehr

On 04/28/2012 09:46 AM, Max Samukha wrote:

On Saturday, 28 April 2012 at 06:03:54 UTC, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
   F > f() { return F >(); }
};

int main()
{
   F().f().f().f().f().f();  // etc.
   return 0;
}



dmd is not smart enough


DMD behaves according to the language specification here.


to avoid recursion by treating f as a
templated function. I am not sure whether it should,


Maybe, but that would be a strange special case.


but the following should certainly work:

struct F(T)
{
  auto f()() { return F!(F!T)(); }
}

void main()
{
  F!int().f().f().f();
}

Error: struct a.F(T) recursive template expansion for template
argument - why?



The checking for infinite recursion seems to be too conservative here. 
You could open a bug report.


Re: More bugs...

2012-04-28 Thread Timon Gehr

On 04/28/2012 08:03 AM, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
F > f() { return F >(); }
};

int main()
{
F().f().f().f().f().f();  // etc.
return 0;
}



D templates are analysed eagerly upon instantiation, whereas C++ 
templates are analysed lazily. This is not a bug, it is a feature.


Re: More bugs...

2012-04-28 Thread Max Samukha

On Saturday, 28 April 2012 at 06:03:54 UTC, Mehrdad wrote:

You expected that to work?


Uhm, why not?

template
struct F
{
   F > f() { return F >(); }
};

int main()
{
   F().f().f().f().f().f();  // etc.
   return 0;
}



dmd is not smart enough to avoid recursion by treating f as a
templated function. I am not sure whether it should, but the
following should certainly work:

struct F(T)
{
 auto f()() { return F!(F!T)(); }
}

void main()
{
 F!int().f().f().f();
}

Error: struct a.F(T) recursive template expansion for template
argument - why?



Re: More bugs...

2012-04-27 Thread Mehrdad

You expected that to work?


Uhm, why not?

template
struct F
{
   F > f() { return F >(); }
};

int main()
{
   F().f().f().f().f().f();  // etc.
   return 0;
}




Try thinking about your code before mouthing off here.
Not trying to to be rude, but did you think about *your* reason before 
responding? 



Re: More bugs...

2012-04-27 Thread James Miller

On Saturday, 28 April 2012 at 04:45:59 UTC, Mehrdad wrote:
Okay, final exams are coming up again, and so are my bugs (I 
have no idea what the correlation is, don't ask...)
I guess I should post this on bugzilla, but oh well... I 
continued the thread instead.


Try compiling this (I did this on Windows, DMD 2.059):

void main() { Foo!(int[])([[1], [2]]); }
struct Foo(T) { auto foo() { Foo!(T[]) t; return t; } }


You expected that to work? Extra extra, infinite recursion is 
infinite! You are asking the compiler to instantiate Foo with the 
type int[], then use that type to instantiate Foo with int[][], 
which then instantiates Foo with type int[][][].


Try thinking about your code before mouthing off here. Would you 
fault C for causing a stack overflow in this case:


int rec(int a){
  return rec(a + 1);
}

I mean what did you expect, that the compiler could magically 
create infinite types? I can't even see where you might have gone 
wrong here, since the code is so simple. What I can see is that 
the constructor wouldn't work because there are no fields. I can 
see that you have some very strange ideas about templates, Foo(T) 
instantiates Foo(T[]), which is a different type, so it goes 
through and instantiates Foo(T[][]) which is, again, a different 
type.


Think before declaring D to have bugs.

--
James Miller


Re: More bugs...

2012-04-27 Thread Mehrdad
Okay, final exams are coming up again, and so are my bugs (I have no idea 
what the correlation is, don't ask...)
I guess I should post this on bugzilla, but oh well... I continued the 
thread instead.


Try compiling this (I did this on Windows, DMD 2.059):

void main() { Foo!(int[])([[1], [2]]); }
struct Foo(T) { auto foo() { Foo!(T[]) t; return t; } } 



Re: More bugs...

2012-04-27 Thread Mehrdad
Oh sorry, here's the previous thread... somehow it got detached because of 
the subject line change:
http://lists.puremagic.com/pipermail/digitalmars-d/2011-December/117172.html 



Re: More bugs found in OS code

2011-11-05 Thread bearophile
Adam D. Ruppe:

> I do a lot. The way I do it is the arguments are made
> available to the format, but it doesn't always need them
> at runtime.
> 
> string f = showNames ? "%1$s\t%2$d" : "%2$d";
> writefln(f, name, number);
> 
> Though I don't literally use writefln for most
> my code the same idea applies.

Python is strict here:


>>> "%d" % (1)
'1'
>>> "%d" % (1, 2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: not all arguments converted during string formatting


Even if you use that idiom, it has costs, measured in bugs. My experience tells 
me that a sloppy semantics, introduced or kept for a little convenience, always 
manages to find a way to bite your ass later. So I'd like more tidyness here.

You are allowed to write:

if (showNames)
writeln("%1$s\t%2$d", name, number);
else
writeln("%2$d", name);


There are also other solutions that don't compromise the already low safety of 
writeln, that is a dynamically typed isle in a statically typed language.

Bye,
bearophile


Re: More bugs found in OS code

2011-11-03 Thread bcs

On 11/02/2011 09:00 PM, Adam D. Ruppe wrote:

bearophile:

But how many times do you want to ignore some of the
arguments listed?


I do a lot. The way I do it is the arguments are made
available to the format, but it doesn't always need them
at runtime.

string f = showNames ? "%1$s\t%2$d" : "%2$d";
writefln(f, name, number);


Though I don't literally use writefln for most
my code the same idea applies.


If you use a literal format string, don't use indexed formatting and 
don't use all the args, I think it would be safe to call that a bug in 
most any case. Fail any one of those pre-conditions and you may have a 
point.


Re: More bugs found in OS code

2011-11-02 Thread Adam D. Ruppe
bearophile:
> But how many times do you want to ignore some of the 
> arguments listed? 

I do a lot. The way I do it is the arguments are made
available to the format, but it doesn't always need them
at runtime.

string f = showNames ? "%1$s\t%2$d" : "%2$d";
writefln(f, name, number);


Though I don't literally use writefln for most
my code the same idea applies.


Re: More bugs found in OS code

2011-11-02 Thread bearophile
Andrej Mitrovic:

> Personally I like using this for a sort of on/off switch:
> bool val;
> // ..
> val ^= 1;
> 
> Maybe that's just stupid but I'm kind of used to it, lol. :p

I use this, I think it's more explicit (but you have to state the variable name 
two times):

val = !val;

Bye,
bearophile


Re: More bugs found in OS code

2011-11-02 Thread bearophile
Adam D. Ruppe:

> bearophile wrote:
> > Currently this is not caught by D, it prints "12":
> > import std.stdio;
> > void main() {
> >writefln("%d%d", 1, 2, 3);
> > }
> 
> That's not really an error. You might change out the format
> string at runtime based on user preferences, perhaps for
> internationalization, or other reasons.

Right, the format string is in general a run-time value, so you can't always 
catch this situation at compile-time.

 But how many times do you want to ignore some of the arguments listed? Even if 
this happens (and I don't remember needing this), I think it's not common 
enough to justify so permissive semantics at run-time.

Recently Andrei A. has expressed some opinions on this topic, but I don't 
remember the bug report number.

Bye,
bearophile


Re: More bugs found in OS code

2011-11-02 Thread Andrej Mitrovic
Personally I like using this for a sort of on/off switch:
bool val;
// ..
val ^= 1;

Maybe that's just stupid but I'm kind of used to it, lol. :p


Re: More bugs found in OS code

2011-11-02 Thread Adam D. Ruppe
bearophile wrote:
> Currently this is not caught by D, it prints "12":
> import std.stdio;
> void main() {
>writefln("%d%d", 1, 2, 3);
> }

That's not really an error. You might change out the format
string at runtime based on user preferences, perhaps for
internationalization, or other reasons.


More bugs found in OS code

2011-11-02 Thread bearophile
The now usual article that advertises the PVS-Studio tool that shows plenty of 
(depressing) bugs found in already debugged source code of widely used C/C++ 
open source projects:

http://software.intel.com/en-us/articles/90-errors-in-open-source-projects/

There is a Reddit discussion too, but I find it useless:
http://www.reddit.com/r/programming/comments/lxjrb/examples_of_errors_detected_in_various_opensource/


In the Reddit discussion someone is free to list in D how many of the 91 bugs:
- Are not applicable or are not normally done in D;
- Are statically caught by D/DMD;
- Are always caught at runtime by DMD in non release mode;
- Are planned/discussed to be statically avoided or statically caught;
- Are planned/discussed to be always caught at runtime by DMD in non release 
mode.



Here I list and comment about some of the more interesting parts. Below I have 
divided the problems in 5 groups (I have not included all the bug groups shown 
in the article).

A]

Example 3. Fennec Media Project project. Complex expression.

uint32 CUnBitArrayOld::DecodeValueRiceUnsigned(uint32 k) 
{
  ...
  while (!(m_pBitArray[m_nCurrentBitIndex >> 5] &
Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {}
  ...
}

The error was found through the V567 diagnostic: Undefined behavior. The 
'm_nCurrentBitIndex' variable is modified while being used twice at single 
sequence point. MACLib unbitarrayold.cpp 78



Example 4. Miranda IM project. Complex expression.

short ezxml_internal_dtd(ezxml_root_t root,
  char *s, size_t len)
{
  ...
  while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
  ...
}

The error was found through the V567 diagnostic: Undefined behavior. The 's' 
variable is modified while being used twice between sequence points.msne zxml.c 
371



Currently DMD accepts this code:

x = x++;

Currently D is using the C semantics, this means the result of that line of 
code is undefined, this means you don't know what it will do once compiled by 
different D compilers or even with different optimization level on the same 
compiler. This means writing such code in C (and currently in D) is _always_ a 
bug (because a program with undefined semantics is often useless. There are 
other sources of undefined semantics, but the less there are, the better it 
is). I don't understand why C compilers don't refuse such code statically with 
an error. In my opinion this is not acceptable.

Two basic solutions for D:
1) Define exactly what that code does in D. Walter has expressed few times his 
desire for this solution.
2) Turn similar lines of code into compile-time errors (and maybe accept them 
forever if the -d switch is used, but I am not sure this is a good idea).

The first solution is good because it makes it simpler to port C code to D, it 
allows C/C++/Java programmers to use that code still. But such C code has 
undefined results, so I don't see a great advantage here (it's useful still to 
port Java code).

But lately I am slowly leaning toward the second solution, because even if D 
defines exactly the semantics of code like this, so it gives the same result on 
all D compilers:

(*(n = ++s + strspn(s, EZXML_WS)) && *n != '>')

I don't want to read similar code in D programs I have to debug or modify. Even 
if it's unambiguous for the D language, it's a bit too much hard for me to 
understand. Go language has chosen this second solution.

B]

Curretly D2 accepts the usage of & and | among booleans:


void main() {
bool a, b;
auto r1 = a & b;
static assert(is(typeof(r1) == bool));
auto r2 = a | b;
static assert(is(typeof(r2) == bool));
}


But I am not sure this is useful enough to justify the risks that gives.

Using booleans as integers is useful when I have to count them and in few other 
situations. But I don't remember the last time I've had to use bitwise 
or/bitwise and on boolean values, I think I have never had to do this. So maybe 
it's better to forbid this. The advantage of forbidding this operation is that 
it avoids several mistakes caused by operator precedence like (!x & y). 
Comments on this are welcome.

C]

Example 5. IPP Samples project. Priorities of ?: and | operations.

vm_file* vm_file_fopen(...)
{
  ...
  mds[3] = FILE_ATTRIBUTE_NORMAL |
   (islog == 0) ? 0 : FILE_FLAG_NO_BUFFERING;
  ...
}

The error was found through the V502 diagnostic: Perhaps the '?:' operator 
works in a different way than it was expected. The '?:' operator has a lower 
priority than the '|' operator. vm vm_file_win.c 393



Example 6. Newton Game Dynamics project. Priorities of ?: and * operations.

dgInt32 CalculateConvexShapeIntersection (...)
{
  ...
  den = dgFloat32 (1.0e-24f) *
(den > dgFloat32 (0.0f)) ?
  dgFloat32 (1.0f) : dgFloat32 (-1.0f);
  ...
}

The error was