Error when attempting to use non-public Library member is too opaque and could be more helpful

Hello, I think that the error given when attempting to use a non-public member from a library is not helpful and could do with some added help to the user.

This is probably only an issue for new-ish users, and long-time Swift developers will never run into this, but it's rather confusing for learners.

Let me give an example and my thinking as I went...

I am attempting improve my knowledge about testing and SPM. I created a new package with an executable target and product (both named 'SPMTesting'). I then created a .testTarget (named 'TheTests').

In the executable's main source file I created a basic class that I could write tests for (named 'Counter'.)

I created some tests in a file ('CounterTest') for the test target and referenced the Counter class in a test.

Cannot find 'Counter' in scope

OK - I probably need to make the executable target a dependency to the Test target... I do that.

Cannot find 'Counter' in scope

Hmm, maybe I need to explicitly import the executable module. I do that.

Cannot find 'Counter' in scope

Hmm, OK. Maybe I'm going about this all wrong, maybe you can't import an executable - I should probably be putting these types into a Library and import that instead.

So - I make a new Library target in the package, named 'Tools' (for a lack of imagination) and define the Counter() class in there instead. Then I make that library a dependency for the executable and the test target. Also I import Tools in both source files.

Compile:

Cannot find 'Counter' in scope

Why not? I even command-click the type name and it can take me to the definition. Why isn't it in scope?

About 15 mins later I suddenly remember about access control across files and that types and functions aren't public by default. I annotate the Counter class with public and it gives a different error

'Counter' initializer is inaccessible due to 'internal' protection level

Ah, a useful error message. This one gives me information that I can use to fix the issue. I add an initialiser to Counter with a public annotation and success - it compiles.

Perhaps most Swift devs would think "well, that's obvious, you should have known to make the types public - they default to private." But may I suggest that since (I assume) the compiler knows that the type exists, but is private, that the error is not as helpful as it could be.

Could the compiler not warn that the type exists, but is not available to the caller? Or would this be seen as a security problem, by exposing internal, private API details?

Thanks

2 Likes

This frequently bites me and it often takes me longer than I'd like to admit to realise what's going on :sweat_smile:

It would certainly help if the error message didn't just mentioned what's wrong but give some indication as to why.

2 Likes

FYI, filed as an issue.

1 Like