blm768 / BulletD

An unfinished D binding for the Bullet Physics Engine
Boost Software License 1.0
11 stars 2 forks source link

Constructor aliasing fails #2

Open blm768 opened 11 years ago

blm768 commented 11 years ago

Mixing in multiple constructors and aliasing them together makes DMD complain that the constructors are not accessible.

vuaru commented 10 years ago

I found a hilariously old thread about this: http://forum.dlang.org/thread/fv7r3g$3ub$1@digitalmars.com

Seems the problem is this: http://dlang.org/struct.html#StructLiteral

If a struct has a member function named opCall, then struct literals for that struct are not possible.

... Actually, after reading a bit more I came across this: http://dlang.org/operatoroverloading.html#FunctionCall

To avoid the limitation, you need to also declare constructor so that it takes priority over opCall in Type(...) syntax.

Which you seem to do. Huh, weird.

Anyway, changing the test.d to not use struct literals makes at least btVector3 work. btQuaternion still complains:

Error: struct btQuaternion does not overload ()

quaternion.d's mixin(joinOverloads!.. doesn't actually mixin anything?

blm768 commented 10 years ago

I had replaced all of the constructors with static opCall because I was having issues overloading them, so currently there shouldn't be any true constructors for those structs. As for joinOverloads, you're right about it not mixing anything in; I never finished implementing it.

At this point, I think that D might not be ready to create a binding like this using only compile-time code generation. The bindings may need to move to using an external generator. I've started working on an interface description language using the Pegged parser generator; I can generate the C++ and D sides of the bindings from that, which means that I won't need to use any mixins. That should sidestep the overloading issues with the constructors.

On 09/23/13 05:24, vuaru wrote:

I found a hilariously old thread about this: http://forum.dlang.org/thread/fv7r3g$3ub$1@digitalmars.com http://forum.dlang.org/thread/fv7r3g%243ub%241@digitalmars.com

Seems the problem is this: http://dlang.org/struct.html#StructLiteral

If a struct has a member function named opCall, then struct
literals for that struct are not possible.

... Actually, after reading a bit more I came across this: http://dlang.org/operatoroverloading.html#FunctionCall

To avoid the limitation, you need to also declare constructor so
that it takes priority over opCall in Type(...) syntax.

Which you seem to do. Huh, weird.

Anyway, changing the test.d to not use struct literals makes at least btVector3 work. btQuaternion still complains:

Error: struct btQuaternion does not overload ()

quaternion.d's mixin(joinOverloads!.. doesn't actually mixin anything?

— Reply to this email directly or view it on GitHub https://github.com/blm768/BulletD/issues/2#issuecomment-24915947.

vuaru commented 10 years ago

I had replaced all of the constructors with static opCall because I was having issues overloading them, so currently there shouldn't be any true constructors for those structs.

Oh so you do have only opCalls defined, and no constructors. Then it makes sense that they cannot be used as struct literals in test.d, since that's what the link explicitly states.

It's a limitation, sure, but if that's the only problem left..

blm768 commented 10 years ago

On 09/23/13 12:35, vuaru wrote:

Oh so you do have only opCalls defined, and no constructors. Then it makes sense that they cannot be used as struct literals in test.d, since that's what the link explicitly states.

It's a limitation, sure, but if that's the only problem left..

— Reply to this email directly or view it on GitHub https://github.com/blm768/BulletD/issues/2#issuecomment-24947626.

The problem is that I'm not sure how to get around that particular issue. If I define constructors, it looks like they'll be used instead of static opCall, but trying to overload the constructors has just given me issues so far. If I throw in dummy constructors, the compiler starts complaining that the static method cppNew is not accessible. I'll play with it a bit more, but I'm not optimistic that I can actually get a stable solution.

vuaru commented 10 years ago

trying to overload the constructors has just given me issues so far.

What were these issues specifically?

blm768 commented 10 years ago

On 09/24/13 08:03, vuaru wrote:

trying to overload the constructors has just given me issues so far.

What were these issues specifically?

I can't remember exactly what error messages DMD gave me, but I remember that DMD choked on this particular style of code:

struct SomeBindingClass { //...

 mixin constructor!() _c0;
 alias _c0.__ctor __ctor;
 mixin constructor!(int) _c1;
 alias _c1.__ctor __ctor;

}

The constructors have to be aliased together for overloading to work on them, but there seems to be no way to refer to the constructor other than through the __ctor identifier. However, DMD doesn't seem to accept that as a callable constructor because it wasn't defined using the "this() {}" syntax outside of the mixin. As far as I can tell, the only way around the issue is to convert the constructor mixin to a string mixin, but then it doesn't have access to typeof(this) unless I pass it as an explicit parameter, which I'm trying to avoid if at all possible.

vuaru commented 10 years ago

If I understand correctly, then you're saying you can't use the template mixins to insert multiple overloading contructors?

Either that is no longer the case or I'm misunderstanding, because I just tried the following simplified example which compiles:

import std.stdio;

void main()
{
    writeln(Tree(4).apple);
    writeln(Tree(4,3).apple);
    writeln(Tree(4,3,2).apple);
}

struct Tree
{
    int apple;

    mixin test;
}

mixin template test()
{
    this(int i) { apple = i; }
    this(int i, int j) { apple = i+j; }
    this(int i, int j, int k) { apple = i+j+k; }
}

(Note: I'm interested in making a simplified version of the wished-for functionality so I can ask the newsgroups for help.)

blm768 commented 10 years ago

It works when all of the overloaded constructors are in the same template instance. However, this shouldn't compile:

|import std.stdio;

void main() { writeln(Tree(4).apple); writeln(Tree(4,3).apple); writeln(Tree(4,3,2).apple); }

struct Tree { int apple;

 mixin constructor!(int);
 mixin constructor!(int, int);
 mixin constructor!(int, int, int);

}

mixin template constructor(Args) { this(Args) {/* some code here*/} } |

That example is much closer to the actual structure of the binding code.

On 09/24/13 11:56, vuaru wrote:

If I understand correctly, then you're saying you can't use the template mixins to insert multiple overloading contructors?

Either that is no longer the case or I'm misunderstanding, because I just tried the following simplified example which compiles:

|import std.stdio;

void main() { writeln(Tree(4).apple); writeln(Tree(4,3).apple); writeln(Tree(4,3,2).apple); }

struct Tree { int apple;

 mixin test;

}

mixin template test() { this(int i) { apple = i; } this(int i, int j) { apple = i+j; } this(int i, int j, int k) { apple = i+j+k; } } |

— Reply to this email directly or view it on GitHub https://github.com/blm768/BulletD/issues/2#issuecomment-25032582.

vuaru commented 10 years ago

It does compile, assuming you meant

mixin template constructor(Args ...)

(Where does one find documentation about these kind of language features anyway?)

blm768 commented 10 years ago

With the current DMD release, the code just chokes with an assertion error. Have you tested it with a development build?

vuaru commented 10 years ago

You're right it does (in fact it gives an abnormal program termination) with DMD 2.063.2.

But it does compile with a fairly recent git HEAD (which I was using because that was required for bulletD anyway).

So to me it seems that the problem has been solved in DMD, just not yet released officially.

blm768 commented 10 years ago

Interesting... Based on DMD's behavior when normal methods are mixed in, I didn't expect DMD to allow constructors from different mixins to automatically overload with each other. I suppose that it makes sense because constructors have much more specific semantics than arbitrary methods do, so overloading is less likely to cause issues.