www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Alias this does not work with pointers?

reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
struct Bar_T; // opaque
alias Bar = Bar_T*;
void someFuncIWantWrapped(Bar* bar)
{
}
struct Foo
{
     Bar bar;
     alias bar this;
}
void someFunc(Foo* foo)
{
    someFuncIWantWrapped(foo);
}

gives
Error: function someFuncIWantWrapped (Bar_T** bar) is not 
callable using argument types Foo*

I feel like this should work.

Yes I realise that I can fix it by
void someFunc(Foo foo)
{
    someFuncIWantWrapped(&foo.bar);
}

but I'm generating this and  the name of bar changes and in 
generated from multiple code paths.

Should I report this as a bug?
Mar 09 2016
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, 10 March 2016 at 01:25:44 UTC, Nicholas Wilson wrote:
 struct Bar_T; // opaque
 alias Bar = Bar_T*;
 void someFuncIWantWrapped(Bar* bar)
 {
 }
 struct Foo
 {
     Bar bar;
     alias bar this;
 }
 void someFunc(Foo* foo)
 {
    someFuncIWantWrapped(foo);
 }

 gives
 Error: function someFuncIWantWrapped (Bar_T** bar) is not 
 callable using argument types Foo*

 I feel like this should work.

 Yes I realise that I can fix it by
 void someFunc(Foo foo)
 {
    someFuncIWantWrapped(&foo.bar);
 }

 but I'm generating this and  the name of bar changes and in 
 generated from multiple code paths.

 Should I report this as a bug?
I see no bugs here. Just because type T can be implicitly converted to type U doesn't mean that T* can be implicitly converted to U* - e.g. int* can't be safely converted to long* in the general case. There are some cases where it can be done in system code if the programmer knows what they're doing but not in safe code - and regardless, it's done by reinterpreting the bytes, not by the kind of conversion that alias this is doing. You're asking for the compiler to somehow take T* and convert it to a completely unrelated type U* just because the programmer has provided a way to convert T to U. But since that conversion is not done be reinterpreting the bytes, there's no way to do that even in system code, let alone implicitly in safe code. Regardless, Foo defined the alias this, not Foo*, so alias this isn't going to work with Foo*. Foo* may point to a Foo, but isn't a Foo, and it doesn't follow the same conversion rules. - Jonathan M Davis
Mar 09 2016
prev sibling parent Chris Wright <dhasenan gmail.com> writes:
alias this can do so much more, though.

For instance:

  struct Foo {
    int a;
    string b;
    alias a this;
  }
  void bar(int* p, size_t len) {
    for (int i = 0; i < len; i++) {
      p[i] = 0;
    }
  }
  bar(new Foo[2].ptr, 2);

Two fields. You don't want to overwrite a pointer, so you can't just turn 
it to an implicit cast.

Or another example:

  struct Foo {
    double s;
    int square() { return cast(int)(s * s); }
    alias square this;
  }

How do you convert a Foo* to an int*? Do you allocate space for it on the 
heap? But what if the Foo* points to a malloc'd section of memory? Or 
some other allocator? Or if it's on the heap and the function is marked 
 nogc? You could put it on the stack as an alternative, but then the 
pointer will be invalid when the function exits... What if it's sent off 
to a C function that stores it? Should the allocation be pinned by 
default? When would it be unpinned?

It's a silent, hidden allocation beyond the user's control. We would like 
it to be allocated like the Foo* was allocated, but that's not currently 
possible.

Instead of providing an implementation that occasionally works but 
typically causes a crash or an unavoidable inefficiency, it's just not 
there to trip people up.
Mar 09 2016