Thread overview
New __traits
Nov 25, 2015
BLM768
Nov 25, 2015
BLM768
Nov 25, 2015
Daniel Murphy
Nov 25, 2015
BLM768
Nov 25, 2015
BLM768
Nov 26, 2015
Daniel Murphy
Nov 26, 2015
BLM768
Nov 26, 2015
Jonathan M Davis
Nov 26, 2015
BLM768
Nov 28, 2015
BLM768
November 25, 2015
For a project I've been working on, I found that it would be helpful to have a way to determine whether a symbol represents a module or package. Since I couldn't find an easy way to do it, I forked DMD and made some tweaks. ;)

Anyway, I uncovered an interesting issue. According to my test program (https://gist.github.com/blm768/42f40aa5a0c49bb8bd16), these are the "types" of various packages/modules in Phobos:
std:
std.stdio: package, module
std.algorithm: package
std.digest: package

In other words, "std" isn't a package _or_ module, and std.stdio is both (even though it's just a single D source file). This doesn't seem quite right.

There could be an error in my patch to DMD, but I don't see where it could be because it's so simple. The code is at https://github.com/blm768/dmd/tree/new_traits if anyone wants to look over it.

If anyone can help me figure out what's going on, I'd greatly appreciate it.
November 25, 2015
On Wednesday, 25 November 2015 at 01:06:55 UTC, BLM768 wrote:
> In other words, "std" isn't a package _or_ module, and std.stdio is both (even though it's just a single D source file). This doesn't seem quite right.

I just confirmed that this also applies to other root packages, i.e. "core" or any root packages from third-party libraries.



November 25, 2015
On 25/11/2015 12:06 PM, BLM768 wrote:
> For a project I've been working on, I found that it would be helpful to
> have a way to determine whether a symbol represents a module or package.
> Since I couldn't find an easy way to do it, I forked DMD and made some
> tweaks. ;)
>
> Anyway, I uncovered an interesting issue. According to my test program
> (https://gist.github.com/blm768/42f40aa5a0c49bb8bd16), these are the
> "types" of various packages/modules in Phobos:
> std:
> std.stdio: package, module
> std.algorithm: package
> std.digest: package
>
> In other words, "std" isn't a package _or_ module, and std.stdio is both
> (even though it's just a single D source file). This doesn't seem quite
> right.
>
> There could be an error in my patch to DMD, but I don't see where it
> could be because it's so simple. The code is at
> https://github.com/blm768/dmd/tree/new_traits if anyone wants to look
> over it.
>
> If anyone can help me figure out what's going on, I'd greatly appreciate
> it.

What you're seeing is just an artifact of how dmd's internals work. 'std' is an 'import' (call Dsymbol.kind() for the category of symbol) and you'll have to resolve it to work out which module/package is being imported.  It's possible that this is a bug in the symbol resolution, and that it should have already been resolved to a package.

Keep in mind also that isPackage and isModule are RTTI functions, and since Module inherits from Package all modules will appear to be packages if that's all you check.
November 25, 2015
On Wednesday, 25 November 2015 at 15:39:17 UTC, Daniel Murphy wrote:
>
> What you're seeing is just an artifact of how dmd's internals work. 'std' is an 'import' (call Dsymbol.kind() for the category of symbol) and you'll have to resolve it to work out which module/package is being imported.  It's possible that this is a bug in the symbol resolution, and that it should have already been resolved to a package.
>
> Keep in mind also that isPackage and isModule are RTTI functions, and since Module inherits from Package all modules will appear to be packages if that's all you check.

That helps immensely! I'll play with that a bit.

As far as semantics go, if this were ever officially integrated into DMD, would it make sense for __traits(isModule, somePackage) to return false (unless it has a package.d) since the inheritance of Module from Package is basically a DMD implementation detail, or would it be better to just follow DMD's convention directly?

November 25, 2015
On Wednesday, 25 November 2015 at 15:39:17 UTC, Daniel Murphy wrote:
> What you're seeing is just an artifact of how dmd's internals work. 'std' is an 'import' (call Dsymbol.kind() for the category of symbol) and you'll have to resolve it to work out which module/package is being imported.  It's possible that this is a bug in the symbol resolution, and that it should have already been resolved to a package.

It seems that I can resolve the import by using "theImport.pkg", but I'm not sure if it's the "correct" way. It works in my tests, though. Is that the right way to do it, or is there a better method?


November 26, 2015
On 26/11/2015 9:33 AM, BLM768 wrote:
> On Wednesday, 25 November 2015 at 15:39:17 UTC, Daniel Murphy wrote:
>> What you're seeing is just an artifact of how dmd's internals work.
>> 'std' is an 'import' (call Dsymbol.kind() for the category of symbol)
>> and you'll have to resolve it to work out which module/package is
>> being imported.  It's possible that this is a bug in the symbol
>> resolution, and that it should have already been resolved to a package.
>
> It seems that I can resolve the import by using "theImport.pkg", but I'm
> not sure if it's the "correct" way. It works in my tests, though. Is
> that the right way to do it, or is there a better method?
>
>

Unfortunately I have no idea.  You'll have to have a look at what other code that resolves packages is doing.

If you can't find it it might be worth emailing Kenji Hara, since he knows everything.
November 26, 2015
On Thursday, 26 November 2015 at 02:20:43 UTC, Daniel Murphy wrote:
> Unfortunately I have no idea.  You'll have to have a look at what other code that resolves packages is doing.
>
> If you can't find it it might be worth emailing Kenji Hara, since he knows everything.

Well, expression.d seems to do it this way. It's also got a check for "pkg == null", so maybe I should include that. Currently my code would just swallow the issue and report that the argument isn't a package. Then again, I don't even know whether it's possible for my code to forward-reference an import; if not, pkg will never be null anyway. Maybe I'll just assert it or something...
November 26, 2015
On Thursday, 26 November 2015 at 17:47:00 UTC, BLM768 wrote:
> Then again, I don't even know whether it's possible for my code to forward-reference an import; if not, pkg will never be null anyway. Maybe I'll just assert it or something...

Yes, code can forward-reference an import. e.g. this code compiles just fine:

    void main()
    {
        writeln("Where's my import?");
    }

    import std.stdio;

Now, when the import is inside of a function, then it can't be forward-referenced, but that's in line with how variable declarations work.

- Jonathan M Davis
November 26, 2015
On Thursday, 26 November 2015 at 20:56:39 UTC, Jonathan M Davis wrote:
> Yes, code can forward-reference an import. e.g. this code compiles just fine:
>
>     void main()
>     {
>         writeln("Where's my import?");
>     }
>
>     import std.stdio;
>
> Now, when the import is inside of a function, then it can't be forward-referenced, but that's in line with how variable declarations work.
>
> - Jonathan M Davis

Oh, duh. I should have remembered that.

In any case, I my tests work when I forward-reference, too, so I'll probably just put an assert on it and call it good. I've got some unit tests on my code now, so it looks like it's almost time for my first PR.

I don't know if this is at all related to how top-level packages aren't resolving to Package objects by the time the __traits run, but while testing this code, I found what seems to be a bug related to __traits(allMembers). Specifically, this code produces an extremely strange output:

---
import std.stdio;

pragma(msg, __traits(allMembers, std));

void main() {}
---

It lists a bunch of symbols that most certainly _aren't_ direct ancestors of the "std" package: "object", "core", "std", "KeepTerminator", "GCC_IO", "HAS_GETDELIM", "FSChar", and a bunch of others.

That's a bug, right?
November 28, 2015
On Thursday, 26 November 2015 at 23:16:59 UTC, BLM768 wrote:
> [snip]
>
> It lists a bunch of symbols that most certainly _aren't_ direct ancestors of the "std" package: "object", "core", "std", "KeepTerminator", "GCC_IO", "HAS_GETDELIM", "FSChar", and a bunch of others.
>
> That's a bug, right?

I've tacked on a comment to the relevant issue (11595) with some info that may or may not help figure out what the problem is. I might play with it, too, but I'm only a junior-level CS student who has basically no familiarity with how DMD does symbol resolution, so I doubt that I'll be able to find exactly where the issue is.