Thread overview
Package permission and symbol resolution
Apr 22, 2014
Manu
Apr 22, 2014
John Colvin
Apr 22, 2014
Manu
Apr 22, 2014
Manu
Apr 24, 2014
Marco Leise
April 22, 2014
So I've restructured one of my projects which is a C library bindings, but also with some D-ification.

I separated it into 2 parts, the raw binding parts, and the api enhancements, the module structure looks like this:

The Raw C binding part:

pkg/c/module.d:

  pkg.c.module;

  struct ModuleStruct
  {
    package:
      int privateParts;
  }

  extern (C) void func(const(char)* pString);


And the wrapping layer; public import's the raw C bindings, which is meant to make the C API available too while adding some sugar for convenience.

pkg/module.d:

  pkg.module;

  public import pkg.c.module;

  void func(const(char)[] str)
  {
    pkg.c.module.func(str.toStringz);
  }

  void func2(ref ModuleStruct s)
  {
    s.privateParts += 10;
  }


I have a bunch of surprising problems.

1. Error: struct pkg.c.module.ModuleStruct member privateParts is not accessible

pkg.module can't access pkg.c.module.ModuleStruct.privateParts. Isn't that what 'package' protection is for? My sugar wrapping module needs to be able to access the private bits of the raw binding module, which I don't want to pollute with sugar directly (since it would ideally be generated by a generator and reflect only a pure C binding).

2. In client code, when I call for instance, func("string".ptr), which
has 2 overloads: 'extern (C) void func(const(char)*)' and 'void
func(const(char)[])', it doesn't seem to resolve the function
correctly:

Error: pkg.module.func at pkg\module.d(14) conflicts with
pkg.c.module.func at pkg\c\module.d
Error: function pkg.module.func (const(char)[] str) is not callable
using argument types (immutable(char)*)

Obviously, the other overload (pkg.c.module.func) can receive
immutable(char)* though, but it just ignores it rather than choosing
to call the appropriate overload.
What's really weird, is if I pass a string instead: func("string"[]),
it picks the other incorrect overload.

Error: cannot implicitly convert expression (func("string"[])) of type
const(char)[] to const(char)*


I've changed lots of random things, but I can't seem to resolve this cleanly.
What have I missed? It must be something simple.
This must be a common problem. I would imagine basically anyone who
wants to add sugar to a C binding would do it this way to avoid
polluting of the raw binding code?
Is there an alternative recommended practise?
April 22, 2014
On Tuesday, 22 April 2014 at 08:07:32 UTC, Manu via Digitalmars-d wrote:
> So I've restructured one of my projects which is a C library bindings,
> but also with some D-ification.
>
> I separated it into 2 parts, the raw binding parts, and the api
> enhancements, the module structure looks like this:
>
> The Raw C binding part:
>
> pkg/c/module.d:
>
>   pkg.c.module;
>
>   struct ModuleStruct
>   {
>     package:
>       int privateParts;
>   }
>
>   extern (C) void func(const(char)* pString);
>
>
> And the wrapping layer; public import's the raw C bindings, which is
> meant to make the C API available too while adding some sugar for
> convenience.
>
> pkg/module.d:
>
>   pkg.module;
>
>   public import pkg.c.module;
>
>   void func(const(char)[] str)
>   {
>     pkg.c.module.func(str.toStringz);
>   }
>
>   void func2(ref ModuleStruct s)
>   {
>     s.privateParts += 10;
>   }
>
>
> I have a bunch of surprising problems.
>
> 1. Error: struct pkg.c.module.ModuleStruct member privateParts is not accessible
>
> pkg.module can't access pkg.c.module.ModuleStruct.privateParts. Isn't
> that what 'package' protection is for?

package protection allows access from the current package and subpackages (pkg.c.* in this case), but not to anyone further up the tree (pkg.someModule).

It would be nice one could write `protected(packageName)` to have better control over this.


The rest of your problems are, I think, explained here: http://dlang.org/hijack.html
April 22, 2014
On 22 April 2014 19:16, John Colvin via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Tuesday, 22 April 2014 at 08:07:32 UTC, Manu via Digitalmars-d wrote:
>>
>> So I've restructured one of my projects which is a C library bindings, but also with some D-ification.
>>
>> I separated it into 2 parts, the raw binding parts, and the api enhancements, the module structure looks like this:
>>
>> The Raw C binding part:
>>
>> pkg/c/module.d:
>>
>>   pkg.c.module;
>>
>>   struct ModuleStruct
>>   {
>>     package:
>>       int privateParts;
>>   }
>>
>>   extern (C) void func(const(char)* pString);
>>
>>
>> And the wrapping layer; public import's the raw C bindings, which is meant to make the C API available too while adding some sugar for convenience.
>>
>> pkg/module.d:
>>
>>   pkg.module;
>>
>>   public import pkg.c.module;
>>
>>   void func(const(char)[] str)
>>   {
>>     pkg.c.module.func(str.toStringz);
>>   }
>>
>>   void func2(ref ModuleStruct s)
>>   {
>>     s.privateParts += 10;
>>   }
>>
>>
>> I have a bunch of surprising problems.
>>
>> 1. Error: struct pkg.c.module.ModuleStruct member privateParts is not accessible
>>
>> pkg.module can't access pkg.c.module.ModuleStruct.privateParts. Isn't that what 'package' protection is for?
>
>
> package protection allows access from the current package and subpackages
> (pkg.c.* in this case), but not to anyone further up the tree
> (pkg.someModule).
>
> It would be nice one could write `protected(packageName)` to have better
> control over this.

Yeah, this seems like a problem, particularly since precisely what I'm
doing seems intuitive and desirable to me.
Are there other patterns to separate the sugar from the raw binding?
If the binding is generated, it can't coexist with the sugar or it'll
be overwritten each time.


> The rest of your problems are, I think, explained here: http://dlang.org/hijack.html

Ah ha!
"in order to overload functions from multiple modules together, an
alias statement is used to merge the overloads"

I've actually read this article before, but I forgot that detail. Cheers mate! :)
April 22, 2014
On 22 April 2014 21:00, Manu <turkeyman@gmail.com> wrote:
> On 22 April 2014 19:16, John Colvin via Digitalmars-d
>> The rest of your problems are, I think, explained here: http://dlang.org/hijack.html
>
> Ah ha!
> "in order to overload functions from multiple modules together, an
> alias statement is used to merge the overloads"
>
> I've actually read this article before, but I forgot that detail. Cheers mate! :)

Well, it worked in some cases...

How's this for a great error:
  Error: fuji.c.MFDebug.MFDebug_Warn at
D:\WinDev\fuji\dist\include\d2\fuji\c\MFDebug.d(38) conflicts with
fuji.c.MFDebug.MFDebug_Warn at
D:\WinDev\fuji\dist\include\d2\fuji\c\MFDebug.d(38)

Precisely the same symbol in precisely the same file are apparently in
conflict...
It seems it all gets confused when a file is imported via multiple
indirect means.

For instance:

B public imports A, B overloads some function in A and must make it
explicit using the rule you lank me to: alias finc = A.func;
If some client imports B, it is now working as expected; the overload
in A and B are both accessible.

But let's say there is also C which public imports A. C does not overload anything A, so there's no need for the alias trick.

Client imports B and C (but not A). It seems that now A via C is in conflict with A via B, even though B provides the alias to explicitly satisfy the anti-hijacking rule. The same function reachable via C stimulates the anti-hijacking error again even though it was addressed in B where the overload was specified.
April 24, 2014
Am Tue, 22 Apr 2014 18:07:21 +1000
schrieb Manu via Digitalmars-d <digitalmars-d@puremagic.com>:

>   extern (C) void func(const(char)* pString);

By the way: What about adding nothrow there?

-- 
Marco