www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - RedBlackTree and myClass

reply AntonSotov <nepuvive rainmail.biz> writes:
import std.container.rbtree;

class myClass {
     string str;
}


int main()
{
     auto tree = new RedBlackTree!myClass;
     return 0;
}


Error: mutable method object.Object.opCmp is not callable using a 
inout object
Error: template instance std.functional.binaryFun!("a < b", "a", 
"b").binaryFun!(inout(myClass), myClass) error instantiating
/////////////////////////////////////////

How to use RedBlackTree of the objects of of its class?
Jan 03
next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Sunday, January 03, 2016 10:55:05 AntonSotov via Digitalmars-d-learn wrote:
 import std.container.rbtree;

 class myClass {
      string str;
 }


 int main()
 {
      auto tree = new RedBlackTree!myClass;
      return 0;
 }


 Error: mutable method object.Object.opCmp is not callable using a
 inout object
 Error: template instance std.functional.binaryFun!("a < b", "a",
 "b").binaryFun!(inout(myClass), myClass) error instantiating
 /////////////////////////////////////////

 How to use RedBlackTree of the objects of of its class?
You either have to define opCmp on your class so that it can be compared with the < operator, or you need to provide RedBlackTree's constructor a function to use to compare instead of using <. - Jonathan M Davis
Jan 03
prev sibling parent reply tsbockman <thomas.bockman gmail.com> writes:
On Sunday, 3 January 2016 at 10:55:05 UTC, AntonSotov wrote:
 import std.container.rbtree;

 class myClass {
     string str;
 }


 int main()
 {
     auto tree = new RedBlackTree!myClass;
     return 0;
 }


 Error: mutable method object.Object.opCmp is not callable using 
 a inout object
 Error: template instance std.functional.binaryFun!("a < b", 
 "a", "b").binaryFun!(inout(myClass), myClass) error 
 instantiating
 /////////////////////////////////////////

 How to use RedBlackTree of the objects of of its class?
Internally, `RedBlackTree` needs to be able to compare two instances of your class. It cannot do so because you haven't implemented the comparison operators: http://dlang.org/spec/operatoroverloading.html#eqcmp It's trying to use the default Object.opCmp() method, but can't because it doesn't accept constant inputs (`inout` is one of the many ways to mark something as constant in D: http://dlang.org/spec/const3.html). You wouldn't want it to use the default method anyway, since it doesn't understand the meaning of your class's data fields. class myClass { string str; override string toString() const { return "{myClass: " ~ str ~ "}"; } override size_t toHash() const { return hashOf(str); } override bool opEquals(Object that) const { return opEquals(cast(myClass) that); } bool opEquals(const myClass that) const { return this.str == that.str; } int opCmp(const myClass that) const { if(this.str < that.str) return -1; // less than if(this.str > that.str) return 1; // greater than return 0; // equal } } Note that all of the new methods are marked `const` on the right. This is to indicate that they do not mutate (change the value of) `this` instance when they are called. Similarly, the `const` in `const myClass that` is a promise by the method not to modify `that`. This use of `const` is required to make `RedBlackTree` work, because it is apparently marking things as `inout` somewhere. Constant values (of whatever sort) cannot be passed to a function unless that function promises not to modify them. It won't compile without the `toString()` either, because somewhere inside it wants to generate a `string` representation of a `myClass` instance, probably as part of an exception message. `toHash()` is not required to make your trivial example work, but it will be needed if you want to be able to use your class as the key type for associative arrays: http://dlang.org/spec/hash-map.html Anyway, it's not too hard if you understand what's going on, and all of the functions I added are good things to have anyway, because lots of generic code expects some or all of them. But, the error messages aren't all that helpful if you didn't already know most of that.
Jan 03
next sibling parent AntonSotov <nepuvive rainmail.biz> writes:
tsbockman,

Many thanks! Now I work for me
Jan 03
prev sibling parent reply Tobi G. <gruen_tobias web.de> writes:
On Sunday, 3 January 2016 at 14:49:59 UTC, tsbockman wrote:
 On Sunday, 3 January 2016 at 10:55:05 UTC, AntonSotov wrote:
 import std.container.rbtree;

 class myClass {
     string str;
 }


 int main()
 {
     auto tree = new RedBlackTree!myClass;
     return 0;
 }


 Error: mutable method object.Object.opCmp is not callable 
 using a inout object
 Error: template instance std.functional.binaryFun!("a < b", 
 "a", "b").binaryFun!(inout(myClass), myClass) error 
 instantiating
 /////////////////////////////////////////

 How to use RedBlackTree of the objects of of its class?
Anyway, it's not too hard if you understand what's going on, and all of the functions I added are good things to have anyway, because lots of generic code expects some or all of them. But, the error messages aren't all that helpful if you didn't already know most of that.
But as a beginner it is quite disappointing to write all of these functions to just get it work. Maybe i am a bad programmer, but i don't write and use the member functions above that often. I often use the 'less' in the template arguments to get such things as comparison done, and implement these functions only if i have to.. To get it work this should be enough: import std.container.rbtree; class myClass { string str; override string toString() const { return "{myClass: " ~ str ~ "}"; } } void main() { auto tree = new RedBlackTree!(myClass, "a.str < b.str"); } ~ togrue
Jan 03
parent reply tsbockman <thomas.bockman gmail.com> writes:
On Sunday, 3 January 2016 at 16:25:31 UTC, Tobi G. wrote:
 On Sunday, 3 January 2016 at 14:49:59 UTC, tsbockman wrote:
 Anyway, it's not too hard if you understand what's going on, 
 and all of the functions I added are good things to have 
 anyway, because lots of generic code expects some or all of 
 them. But, the error messages aren't all that helpful if you 
 didn't already know most of that.
But as a beginner it is quite disappointing to write all of these functions to just get it work. Maybe i am a bad programmer, but i don't write and use the member functions above that often. I often use the 'less' in the template arguments to get such things as comparison done, and implement these functions only if i have to.. To get it work this should be enough: import std.container.rbtree; class myClass { string str; override string toString() const { return "{myClass: " ~ str ~ "}"; } } void main() { auto tree = new RedBlackTree!(myClass, "a.str < b.str"); } ~ togrue
It just depends on what the class is for. If it's a private internal data structure which is only used a few places, then sure - just use the minimum code required to get the job done. But, if it's a part of the public API for a module and the class logically has a natural ordering, it's better to specify its behavior once in the class definition, rather than re-implement it everywhere that needs it. Obviously there isn't much point to creating a class that does nothing bug wrap `string`, so I tried to provide the generic solution which can be easily extended to do the right thing when the class is fleshed out to actually do whatever it is really supposed to do. And if you really just want a named `string` wrapper, why not do this? class myClass { string str; alias str this; }
Jan 03
parent Tobi G. <gruen_tobias web.de> writes:
On Sunday, 3 January 2016 at 16:44:35 UTC, tsbockman wrote:
 If it's a private internal data structure which is only used a 
 few places, then sure - just use the minimum code required to 
 get the job done.

 But, if it's a part of the public API for a module and the 
 class logically has a natural ordering, it's better to specify 
 its behavior once in the class definition, rather than 
 re-implement it everywhere that needs it.
Yes. I totally agree with you. In the public API of a module, it can make your life so much easier if it's reuseable in all useful ways.
Jan 03