www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - One case of careless opDispatch :)

reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
As a practical habit, once I stumble upon a very tricky error, I usually 
share the valuable knowledge of "when you do this ... and get that ... 
it's probably because ... "
Damn, sometimes they can even become cool quizzes...
So to warn those oblivious to the dangers of opDispatch, here is my the 
yesterday nightmare, the striped down code below.

import std.algorithm;
import std.array;

class Widget {
     string _name;
     Widget[] _children;
     this(in string name){
         _name = name.idup;
     }
     Widget opDispatch(string nm)(){
         auto r = find!((Widget c){ return c._name == nm; })(_children);
         return r.front();
     }
}

void main(){
     Widget g = new Widget("G");
     Widget warr[] = [new Widget("W"),g];
     find(warr,g);
}

produces:

Error    1    Error: template std.algorithm.startsWith(alias pred = "a 
== b",Range,Ranges...) if (isInputRange!(Range) && Ranges.length > 0 && 
is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0].front)))) 
startsWith(alias pred = "a == b",Range,Ranges...) if 
(isInputRange!(Range) && Ranges.length > 0 && 
is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0].front)))) 
matches more than one template declaration, 
C:\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d(1892):startsWith(alias 
pred = "a == b",Range,Ranges...) if (isInputRange!(Range) && 
Ranges.length > 0 && 
is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0].front)))) 
and 
C:\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d(1980):startsWith(alias 
pred = "a == b",Range,Elements...) if (isInputRange!(Range) && 
Elements.length > 0 && 
is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0]))))    
C:\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d    1488

The tricky part is that *any* class with unconstrained (or loosely 
constrained) opDispatch is also a Range, and at least a bidirectional 
one, since it "provides" all the primitives: front, popFront etc.
In fact such classes could penetrate almost any attempts at C++ 
trait-like stuff  and should be avoided.

The moral: unconstrainted opDispatch == TROUBLE.
Hope that helps!

P.S. Strangely enough, that problem haven't showed up until update to 
2.047 release, so it's probably detonated by some changes to Phobos. I 
guess better sooner than later.

-- 
Dmitry Olshansky
Jul 15 2010
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 15 Jul 2010 15:34:23 -0400, Dmitry Olshansky  
<dmitry.olsh gmail.com> wrote:

 As a practical habit, once I stumble upon a very tricky error, I usually  
 share the valuable knowledge of "when you do this ... and get that ...  
 it's probably because ... "
 Damn, sometimes they can even become cool quizzes...
 So to warn those oblivious to the dangers of opDispatch, here is my the  
 yesterday nightmare, the striped down code below.

 import std.algorithm;
 import std.array;

 class Widget {
      string _name;
      Widget[] _children;
      this(in string name){
          _name = name.idup;
      }
      Widget opDispatch(string nm)(){
          auto r = find!((Widget c){ return c._name == nm; })(_children);
          return r.front();
      }
 }

 void main(){
      Widget g = new Widget("G");
      Widget warr[] = [new Widget("W"),g];
      find(warr,g);
 }

 produces:

 Error    1    Error: template std.algorithm.startsWith(alias pred = "a  
 == b",Range,Ranges...) if (isInputRange!(Range) && Ranges.length > 0 &&  
 is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0].front))))  
 startsWith(alias pred = "a == b",Range,Ranges...) if  
 (isInputRange!(Range) && Ranges.length > 0 &&  
 is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0].front))))  
 matches more than one template declaration,  
 C:\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d(1892):startsWith(alias  
 pred = "a == b",Range,Ranges...) if (isInputRange!(Range) &&  
 Ranges.length > 0 &&  
 is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0].front))))  
 and  
 C:\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d(1980):startsWith(alias  
 pred = "a == b",Range,Elements...) if (isInputRange!(Range) &&  
 Elements.length > 0 &&  
 is(typeof(binaryFun!(pred)(doesThisStart.front,withOneOfThese[0]))))     
 C:\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d    1488

 The tricky part is that *any* class with unconstrained (or loosely  
 constrained) opDispatch is also a Range, and at least a bidirectional  
 one, since it "provides" all the primitives: front, popFront etc.
 In fact such classes could penetrate almost any attempts at C++  
 trait-like stuff  and should be avoided.

 The moral: unconstrainted opDispatch == TROUBLE.
 Hope that helps!

 P.S. Strangely enough, that problem haven't showed up until update to  
 2.047 release, so it's probably detonated by some changes to Phobos. I  
 guess better sooner than later.

:) I've run into this before, with other compile-time tests such as isAssociativeArray. Often, the real bug is the tests themselves are too permissive.
Jul 15 2010
parent =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 15-07-2010 o 21:52:56 Robert Jacques <sandford jhu.edu> napisa=B3(a=
):

  I've run into this before, with other compile-time tests such as  =

 isAssociativeArray. Often, the real bug is the tests themselves are to=

 permissive.

Yes. I think isSomeRange should check that pop(Front|Back) returns void.= = opDispatch couldn't stand for a range interface just by mistake. Tomek
Jul 23 2010
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"Dmitry Olshansky" <dmitry.olsh gmail.com> wrote in message 
news:i1nns8$d4g$1 digitalmars.com...
 The tricky part is that *any* class with unconstrained (or loosely 
 constrained) opDispatch is also a Range, and at least a bidirectional one, 
 since it "provides" all the primitives: front, popFront etc.
 In fact such classes could penetrate almost any attempts at C++ trait-like 
 stuff  and should be avoided.

 The moral: unconstrainted opDispatch == TROUBLE.
 Hope that helps!

Duck typing == TROUBLE
Jul 15 2010