Re: cas and interfaces

2018-12-27 Thread Johan Engelen via Digitalmars-d-learn
On Thursday, 27 December 2018 at 12:07:48 UTC, Rene Zwanenburg 
wrote:
On Tuesday, 25 December 2018 at 22:07:07 UTC, Johannes Loher 
wrote:
Thanks a lot for the info, that clarifies things a bit. But it 
still leaves the question, why it works correctly when 
inheriting from an abstract class instead of implementing an 
interface... Any idea about why that?


Unlike interfaces, base class references don't need adjustment.


Yeah. You shouldn't need to know these details but if you are 
interested, the details are here: 
https://dlang.org/spec/abi.html#classes (it's meant for tech 
reference, not for explanation. If you need more explanation, go 
search for vtables, multiple inheritance, etc.).


-Johan



Re: cas and interfaces

2018-12-27 Thread Rene Zwanenburg via Digitalmars-d-learn
On Tuesday, 25 December 2018 at 22:07:07 UTC, Johannes Loher 
wrote:
Thanks a lot for the info, that clarifies things a bit. But it 
still leaves the question, why it works correctly when 
inheriting from an abstract class instead of implementing an 
interface... Any idea about why that?


Unlike interfaces, base class references don't need adjustment. 
You can see this in action by printing addresses:


https://run.dlang.io/is/m6icVr

import std.stdio;

interface I {}
class Base : I {}
class Derived : Base { }

void main()
{
auto derived = new Derived;
Base base = derived;
I i = derived;

writeln(cast(void*)derived);
writeln(cast(void*)base);
writeln(cast(void*)i);
}


7FC1F96EE000
7FC1F96EE000
7FC1F96EE010


Re: cas and interfaces

2018-12-25 Thread Johannes Loher via Digitalmars-d-learn

On Monday, 24 December 2018 at 11:23:32 UTC, Johan Engelen wrote:
On Sunday, 23 December 2018 at 14:07:04 UTC, Johannes Loher 
wrote:

[...]


The types of the 2nd and 3rd arguments of `cas` do not have to 
be the same, and aren't in your case. I think what's happening 
is that you are overwriting `testInterface` with a pointer to a 
TestClass which is not a valid TestInterface pointer. And then 
the program does something invalid because, well, you enter UB 
land.

Fixed by:
```
cas(, testInterface, cast(shared(TestInterface)) 
new shared TestClass).writeln;

```
Note the cast!

Whether this is a bug in `cas` or not, I don't know. The `cas` 
template checks whether the 3rd can be assigned to the 1st 
argument (`*here = writeThis;`) which indeed compiles _with_ an 
automatic conversion. But then the implementation of `cas` does 
not do any automatic conversions (casts to `void*`). Hence the 
problem you are seeing.


-Johan


Thanks a lot for the info, that clarifies things a bit. But it 
still leaves the question, why it works correctly when inheriting 
from an abstract class instead of implementing an interface... 
Any idea about why that?


Re: cas and interfaces

2018-12-24 Thread Johan Engelen via Digitalmars-d-learn

On Sunday, 23 December 2018 at 14:07:04 UTC, Johannes Loher wrote:
I recently played around with atomic operations. While doing 
so, I noticed a problem with the interaction of interfaces and 
cas. Consider the following program:


```
import core.atomic;
import std.stdio;

interface TestInterface
{
}

class TestClass : TestInterface
{
}

void main()
{
shared TestInterface testInterface = new shared TestClass;
cas(, testInterface, new shared 
TestClass).writeln;

writeln(typeid(testInterface));
}
```
(https://run.dlang.io/is/9P7PAb)


The types of the 2nd and 3rd arguments of `cas` do not have to be 
the same, and aren't in your case. I think what's happening is 
that you are overwriting `testInterface` with a pointer to a 
TestClass which is not a valid TestInterface pointer. And then 
the program does something invalid because, well, you enter UB 
land.

Fixed by:
```
cas(, testInterface, cast(shared(TestInterface)) 
new shared TestClass).writeln;

```
Note the cast!

Whether this is a bug in `cas` or not, I don't know. The `cas` 
template checks whether the 3rd can be assigned to the 1st 
argument (`*here = writeThis;`) which indeed compiles _with_ an 
automatic conversion. But then the implementation of `cas` does 
not do any automatic conversions (casts to `void*`). Hence the 
problem you are seeing.


-Johan





cas and interfaces

2018-12-23 Thread Johannes Loher via Digitalmars-d-learn
I recently played around with atomic operations. While doing so, 
I noticed a problem with the interaction of interfaces and cas. 
Consider the following program:


```
import core.atomic;
import std.stdio;

interface TestInterface
{
}

class TestClass : TestInterface
{
}

void main()
{
shared TestInterface testInterface = new shared TestClass;
cas(, testInterface, new shared 
TestClass).writeln;

writeln(typeid(testInterface));
}
```
(https://run.dlang.io/is/9P7PAb)

This program compiles successfully and outputs

```
true
Error: program killed by signal 11
```

i.e. a segmentation fault happens.

When replacing "interface" with "abstract class" 
(https://run.dlang.io/is/sFaO1k), everything works as expected 
and the program outputs


```
true
onlineapp.TestClass
```

Is this actually a bug or a fundamental limitation of cas and 
interfaces? Did I do anything wrong?