www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Package permission and symbol resolution

reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
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?
Apr 22 2014
next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
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
Apr 22 2014
prev sibling next sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
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! :)
Apr 22 2014
prev sibling next sibling parent Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
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.
Apr 22 2014
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
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
Apr 23 2014