Allow autocomplete after typing an underscore

It is great that libraries can use an underscored name to hide implementation details which need to be public for technical reasons, so they don’t pollute the autocomplete list.

However, sometimes it is important to actually use those underscored methods, in which case it would be nice to have autocomplete show them after explicitly typing an underscore. For example, if someone wants to implement isEven on BinaryInteger, the most efficient way to do so is:

extension BinaryInteger {
  var isEven: Bool { return _lowWord & 1 == 0 }
}

Right now, typing the underscore at the start of _lowWord does not bring up autocomplete, and manually bringing it up by hitting escape does not show the members starting with underscores. I think that after explicitly typing an underscore, autocomplete should then list the available underscored items.

I’m not sure if this would involve a change to Swift or Xcode (or both), but I wanted to discuss the idea and see if other people would find it useful.

4 Likes

It’s not hidden just so that they don’t pollute the list though—it’s so that people don’t use them!

2 Likes

Right, and when the situation arises that someone needs to use them, it would be helpful to show them in autocomplete after typing the underscore.

But that would expose some of the implementation detail from the standard library. I would like to keep the current behavior as otherwise you will leak too much. Here is one example. The users of this protocol are mostly unaware that these customization points exist.

Since they’re not meant to be used, this would be counterproductive rather than helpful because it would actively mislead users. The language would be suggesting the use of something that the language simultaneously doesn’t intend to be used.

I think rather that we should have an annotation that would make calling these functions outside the module a hard compiler error.

4 Likes

“Keeping users unaware of certain public declarations” strikes me as an anti-goal.

If anything, I would suggest that an interested developer who wants to learn about the implementation details of the standard library, should be able to discover underscored items by typing an underscore and hitting escape, rather than having to wade through the source code of the Swift repository to find them.

Speaking for myself, I personally would very much like to be able to browse, inspect, experiment with, and explore the underscored parts of the standard library in a hands-on manner, to improve my understanding of its workings.

I think it would benefit me, and anyone else who is interested in becoming more familiar with how things work under the hood, to be able to see the underscored items in autocomplete, if and only if I have typed an underscore to signify that I specifically want to see them.

There is a real, direct, educational benefit to having it work that way.

And, in addition, there is also the benefit I originally mentioned, for situations where it is necessary to actually use an underscored member.

1 Like

I understand and respect your view point, but I've read quite often on SE that anything with an underscore prefix that leaks from the stdlib to the enduser should be interpreted as 'hands off'.

1 Like

There is no reason to privilege underscored public members for this purpose over internal methods; the distinction is entirely an implementation detail.

If we want to encourage this, then we should make it possible to do a @testable import of the standard library and explore internal methods as well as underscored ones.

I disagree and think that this argument places undue requirements on Nevin to justify the additional behavior. We don't actually say much about leading underscores in TSPL. The fact that the IDE does so much to obscure them is not nearly as helpful as it might seem, especially when the user has no way to signal that they do, in fact, want to interact with things that have leading underscores.

2 Likes

That said, we probably should make clear that anything underscored is reserved to the implementation, and subject to change, despite public visibility.

6 Likes

To clarify: the stdlib folks decided on the convention that underscored public symbols are considered private to the stdlib. Code-completion only hides underscored API from the stdlib. We make no such assumptions about other code.

7 Likes

Thanks for pointing this out. I think it makes the rationale even stronger here:

Underscored items are only hidden when they come from the standard library, but the standard library is open source so it does not actually have any “hidden implementation details”. The implementation is available for anyone and everyone to peruse.

Therefore, the behavior of hiding underscored parts of the standard library from autocompletion is a matter of improving the programmer experience, not hiding implementation detail—it works that way so autocomplete is not polluted with things that most people shouldn’t use most of the time.

Since this behavior is about the programmer experience, when someone does bring up autocomplete after typing an underscore, the right thing to do is show the underscored items which are available, since that is what the programmer is specifically requesting.

1 Like

A compromise:
• Code complete things with an underscore when typing an underscore
• Have the listing show up with a warning of some sort

Hello, is it possible for other libraries to hide underscore-prefixed identifiers (methods, properties, types) from autocomplete? How to achieve this?

1 Like

I don't believe there is a way for non-stdlib code to do this currently. @rintaro

@blangmuir is right. There's no way for non-system modules to hide underscored API from code-completion.

Although code-completion also hides protocol with @_show_in_interface attribute, this is underscored, thus unsupported.

Thank you @rintaro,

Given that I presume that libraries expose underscored apis due to the inability to make hide protocols and some of their content (I may forget other reasons), what do you think is the way forward?

  1. Let modules declare that they want the same behavior as the stdlib?
  2. Enhance protocols so that we can hide them fully, or partially, from autocompletion?
  3. Enhance protocols so that we can hide them fully, or partially, from public apis/abi?
// Can't hide _Base
public protocol _Base {
    // Can't hide f
    func _f()
}

public protocol P: _Base {
    // Can't hide _customizationPoint()
    func _customizationPoint()
}

I feel that using naming conventions to mandate autocompletion behavior is messy and “un-Swifty". Instead, an attribute should be added to explicitly opt out of autocompletion, which may in turn be disregarded based on developer preferences.

Hiding a declaration from autocompletion is analogous to hiding a file. In macOS, files may be implicitly hidden using a dot prefix (like the standard library’s underscore prefixes), but the “proper” method of hiding files is setting a file attribute.

Like hidden files, hidden declarations should be used sparingly and with the understanding that they are hidden at the user’s discretion. They should be relatively well-documented, particularly with regard to warnings about potential bugs or reliability issues. If something should not be used, the documentation should explicitly state that.

4 Likes

If an attribute to suppress autocompletion was added, I’d be in favor of deprecating special treatment for underscore prefixes entirely.

5 Likes