Thread overview
Error: C++ base class needs at least one virtual function
Jul 27, 2019
Ethan
Jul 27, 2019
Ethan
Jul 28, 2019
Johan Engelen
Jul 28, 2019
Ethan
Jul 28, 2019
Ethan
July 27, 2019
I know how this is going to get in to a discussion about how virtual destructors are necessary, but in this case it's not and I know better than the compiler. tl;dr is "How do I make the compiler behave the way I want it to?"

This is going to be representative of code in my runtime. Every object I deal with will be a reference, so classes are a logical choice. They'll be stored in an immutable hashmap using a unique ID, they have type checking built in to the ID, and my reference retrieval object will do the type checking and casting.

And the only reason I'm using classes? Because struct inheritance is still considered a monumentally bad thing despite the solid use cases. I know the outright hacks around it, my DConf 2016 and 2017 talks went in to detail about it. But really, I don't want this code to employ such gross hacks for what should be something simple.

Notice I even enforce every method to be final in my derived class to emphasise that *I do not want nor need virtuals ever in this code*.

--------

extern(C++):

class Base
{
    int uniqueID;
}

class Derived : Base
{
final:
    @property UniqueID( int val ) { uniqueID= val; return uniqueID; }
    @property UniqueID() const { return uniqueID; }
}

int main( string[] args )
{
    Base obj = new Base;
    obj.Value = 42;

    import std.stdio : writeln;
    writeln( obj.Value );

    return 0;
}
July 27, 2019
On Saturday, 27 July 2019 at 19:58:05 UTC, Ethan wrote:
>     obj.Value = 42;

>     writeln( obj.Value );

(Yeah those are meant to say UniqueID)
July 28, 2019
On Saturday, 27 July 2019 at 19:58:05 UTC, Ethan wrote:
> I know how this is going to get in to a discussion about how virtual destructors are necessary, but in this case it's not and I know better than the compiler. tl;dr is "How do I make the compiler behave the way I want it to?"

Can I rephrase your point as this?
Normal D classes do not require their parent to have at least one virtual function, but extern(C++) classes do. Please remove this limitation from extern(C++) classes.

-Johan

July 28, 2019
On Sunday, 28 July 2019 at 09:27:56 UTC, Johan Engelen wrote:
> Can I rephrase your point as this?
> Normal D classes do not require their parent to have at least one virtual function, but extern(C++) classes do. Please remove this limitation from extern(C++) classes.
>
> -Johan

That's not accurate.

Normal D classes without a defined parent have Object as a parent, which defines 4 virtuals at last count. The "no virtuals" template in my code that static asserts when a virtual is detected specifically ignores Object and its virtuals (and also static asserts if a user overrides those virtuals).

If I said I wanted the limitation removed coming in, the obvious counterpoint is "But memory safety is thrown out the window without virtual destructors so we absolutely should enforce this." To which I'd have nothing except that I don't need it in my use case.

I'm not asking to remove the limitation. I'm asking for an option to disable the error because I have a valid use case for it and I know what I'm doing.
July 28, 2019
On Saturday, 27 July 2019 at 19:58:05 UTC, Ethan wrote:
> tl;dr is "How do I make the compiler behave the way I want it to?"

Write the code myself of course.

I've got a solution working locally.

And looking at the implementation that was already there... I'm not going to submit a pull request just yet. The code only checks for the existence of virtuals, it doesn't care if one of those virtuals is a destructor or not. This isn't good enough as I see it. So I'm going to think about how best to tackle that.

But hey, my code compiles and executes perfectly now that I have a solution.

There is *one* thing I'm going to get a pull request ready for however Compile this code using a Windows DMD:

----------

extern( C++ ) class SomeClass
{
    @property someString() const { return "Wahoo"; }
}

----------

Compiler output:
Internal Compiler Error: type `string` can not be mapped to C++

----------

This is a Windows only problem. Linux builds have no issue with slices of any kind. So that's one problem that I'm going to analyse and fix in another pull request. Probably requires the codegen to define a virtual Slice struct knowing how Windows works.

But what I'm interested in is that ICE.

So here's the thing with every ICE in cppmanglewin.d. Every single one of them is as the result of a user error. As near as I can tell, an ICE is raised because it wants compilation to just plain stop and go no further. It's not an unexpected state, it's a state it knows the user can input but compilation past that point is plain wrong as far as it's concerned.

And yet none of these ICE give the file and line number in the log.

"So just go through your extern( C++ ) objects and look for-" Yeah, nah, how about I get a file and line in the output that I can double click on in my IDE (it's Windows so of course I mean Visual Studio) and go straight to the problem. Massive time saver.

That change I've got there is quite self contained, so a pull request will be incoming for that.