www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Polymorphism? Passing arguments

reply Martin <martin mab-on.net> writes:
I have a interface
`interface Node {...}`

and some classes implementing Node:
```
class Text : Node {...}
class Element : Node {...}
```
and a function like this:
`public void setRelation(ref Node parent , ref Node child) {...}`

if i do this it works:
```
Node root = new Element("root");
Node text = new Text("blah");
setRelation(root ,  text);
```

but this does not:
```
Node root = new Element("root");
setRelation(root , new Text("blah"));
```
Error: function Nodes.setRelation (ref Node parent, ref Node 
child) is not callable using argument types (Node, Text)
Why is this? Text implements Node. This is how i do it in other Languages - How can would be this possible in D?
Nov 03 2017
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 4 November 2017 at 01:22:05 UTC, Martin wrote:
 `public void setRelation(ref Node parent , ref Node child)
Why are these ref? A lot of people coming from C++ use ref in places you shouldn't use it in D. Remember, in D, a class object is implicitly ref, so doing `ref Object` is more like `Object**` or `Object&&` - often more direction than you need and want. Just taking ref away from both of those will likely fix your problems.
 setRelation(root , new Text("blah"));
In this case, it definitely will. An explicit ref in D must refer to a variable name, not just an object. Since `new Text()` has no variable name, it cannot be ref.
 Why is this? Text implements Node. This is how i do it in other 
 Languages - How can would be this possible in D?
But, even if it were legal to do what you're trying on ref semantics, this would still be broken polymorphism! Consider the following: Text text = new Text(); Node n = text; // legal, Text implements Node n = new Element(); // also legal, Element impls Node too buuuut: Text text = new Text(); Node* n = &text; // subtly different than above... *n = new Element(); // ...because this would be bad news // what is text now? If the compiler allowed that pointer (or the ref, same deal), you would have overwritten a Text object with an Element, breaking the type system. This is also the reason why a Text[] will not cast to a Node[], even though an individual Text is a Node.
Nov 03 2017
parent reply Martin <martin mab-on.net> writes:
Thank you for the answer

On Saturday, 4 November 2017 at 01:35:41 UTC, Adam D. Ruppe wrote:
 Why are these ref?
 Just taking ref away from both of those will likely fix your 
 problems.
because without it i get the error "Program exited with code -11" The thing is, somwhere deeper in `setRelation` i call two functions: ``` public void addChild(ref Node child) { this.children ~= &child; } public void setParent(ref Node parent) { this.parent = &parent; } ```
Nov 03 2017
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, November 04, 2017 01:52:06 Martin via Digitalmars-d-learn 
wrote:
 Thank you for the answer

 On Saturday, 4 November 2017 at 01:35:41 UTC, Adam D. Ruppe wrote:
 Why are these ref?
 Just taking ref away from both of those will likely fix your
 problems.
because without it i get the error "Program exited with code -11" The thing is, somwhere deeper in `setRelation` i call two functions: ``` public void addChild(ref Node child) { this.children ~= &child; } public void setParent(ref Node parent) { this.parent = &parent; } ```
They do not live on the stack like they do in C++ (for that, you'd use a struct, which has no inheritance). Class references are basically pointers. Taking the address of a class reference is taking the address of the variable on the stack. If T is a class, then T foo = getSomeT(); T* bar = &foo; in D would be more or less equivalent to this in C++: T* foo = getSomeT(); T** bar = &foo; By making the parameter ref, you are then getting the address of the class reference in the caller, whereas without it, you're getting the address of the class reference of the callee, and that then goes away when the function exits - which is why things blow up on you. But they'll blow up the same way once the variable in the class reference that you passed in goes out of scope, and you try to use the addresses that you stored. If you ever use & with a class in D, you're almost certainly doing something wrong. If typeof(this.parent) is Node, then setParent should be able to just accept the Node without ref and assign it to this.parent, and this.parent is then going to be pointing to the same object that the Node you passed to setParent was pointing to. There should be no need for pointers or &. I would suggest that you read this online book: http://ddili.org/ders/d.en/index.html It should help you with all of the basic stuff in D like this. If you want to know about classes specifically, then you can skip straight to the chapter on classes: http://ddili.org/ders/d.en/class.html but I expect that you'll benefit from reading the whole thing. - Jonathan M Davis
Nov 03 2017
parent Martin <martin mab-on.net> writes:
ok, thanks you very much for the information.
Nov 03 2017
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, November 04, 2017 01:22:05 Martin via Digitalmars-d-learn 
wrote:
 I have a interface
 `interface Node {...}`

 and some classes implementing Node:
 ```
 class Text : Node {...}
 class Element : Node {...}
 ```
 and a function like this:
 `public void setRelation(ref Node parent , ref Node child) {...}`

 if i do this it works:
 ```
 Node root = new Element("root");
 Node text = new Text("blah");
 setRelation(root ,  text);
 ```

 but this does not:
 ```
 Node root = new Element("root");
 setRelation(root , new Text("blah"));
 ```

Error: function Nodes.setRelation (ref Node parent, ref Node
child) is not callable using argument types (Node, Text)
Why is this? Text implements Node. This is how i do it in other Languages - How can would be this possible in D?
The problem really doesn't have anything to do with the types involved. It has to do with ref. ref only accepts lvalues, not rvalues. So, you can't pass it the result of new or the result of any function that returns by value. The first example works, because you're passing variables, which are lvalues. So, if you remove ref from parent and child, then you won't have any problems like this, and unless you're planning on altering which objects parent and child refer to, there's really no reason to have them be marked with ref. - Jonathan M Davis
Nov 03 2017