FYI: Be careful with imports when using public:

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed Oct 11 12:08:41 UTC 2023


On Wednesday, October 11, 2023 5:34:50 AM MDT Salih Dincer via Digitalmars-d 
wrote:
> On Wednesday, 11 October 2023 at 05:31:33 UTC, Jonathan M Davis
>
> wrote:
> > The problem is not using the imports inside of the struct where
> > you have the public import (since whether imports are public or
> > not has no impact on the part of the code where they're
> > imported, just on other modules importing that code). The
> > problem is using them on the struct from within another module.
>
> I see! In this situation there are 2+1 (the first one doesn't
> count) solutions if I do not remember wrong:
>
> The first thing is not to use "public:" but still be careful.
> Because the imports may accidentally be in scope, as you
> mentioned.
>
> Other is "Renamed Imports", a local name for an import can be
> given. For example:
>
> ```d
>    public:
>
>       import std.range.primitives : wl = walkLength;
> ```

I wouldn't advise that, since I'm pretty sure that that results in having wl
as a public member of the type that it's in (or of the module that it's in
if you do it at at the module-level), and you presumably don't want to be
creating any extra public symbols like that. In general, simply making sure
that the import is before public: solves the issue without having to jump
through any hoops - or using public as an attribute rather than as a label
also solves the problem.

> Finally, use selective import again and define it inside the
> member function. For example:
>
> ```d
>    public:
>
>      size_t length() {
>        import std.range.primitives : walkLength;
>        return this.walkLength;
>      }
> ```

In general, it's advised to scope imports as tightly as possible to avoid
what they impact (as well as to make it clearer where they're used so that
you know where symbols come from and when you can remove the imports when
refactoring), but you do sometimes need them outside of functions (e.g. for
the return types), so while local imports help, they don't always solve the
problem.

Personally, I ran into this issue, because I just wanted to have the
necessary import to get the range primitives for arrays without having to
worry about where within the member functions I was using them, and it would
have been fine if I'd put the import before the public:, but I didn't, so I
ran into issues.

> Thank you very much for this information. There is a huge
> difference between "import" alone and "public import"!
>
> SDB at 79

Ultimately, what it comes down to is that if you use public:, you need to be
careful where you place imports in relation to it. You don't want to be
creating public imports by accident (and almost never want to create them on
purpose; package.d is the primary counter-example). Of course, you can
choose to just avoid public: to avoid the problem (in which case, presumably
you just use public as an attribute directly on the symbols), but the point
is that if you do use public:, you need to be careful where you put it. And
it's easy to forget that it impacts imports, since most of us don't do much
with public imports.

- Jonathan M Davis





More information about the Digitalmars-d mailing list