Show default arguments in code-completion placeholders

#1

I’m not sure if this is really a topic for Swift Evolution, but I’m also not sure where else it would go. :-)

When using code completion to insert a function (or method or initializer) call, the placeholders for the arguments currently show the parameter types, but give no indication which ones can be omitted. It would be nice if they also showed the default value where applicable, so that it’s easy to see at a glance which arguments are and are not required.

This is especially relevant to Foundation, Cocoa, and UIKit, which are notorious for having types whose initializers and methods take a large number of parameters, with default values for many of them. Rather than having to consult the documentation to identify which arguments are necessary, the editor placeholders for each argument should indicate when a default value is available.

As a small contrived example, using « » to delimit the editor placeholders, we might have:

struct BandSection {
  init(n: Int = 76, instrument: String = "trombones") {}
}

// Current code-completion placeholders:
let x = BandSection(n: «Int», instrument: «String»)

// Proposed:
let x = BandSection(n: «Int = 76», instrument: «String = "trombones"»)

To be clear, I am talking solely and exclusively about changing the placeholder text that appears for each argument upon code completion. There would be no change to the language syntax or behavior in any way. This is simply a matter of letting code completion placeholders show the default value for each argument that has one.

9 Likes
(Frederick Kellison-Linn) #2

I like this; it seems useful to know what the default behavior is without having to look up the documentation. Alternatively, what if the entire argument (and default value) were shown as a code completion placeholder rather than actually inserted:

let x = BandSection(«n: Int = 76, »«instrument: String = "trombones"»)

This would allow for the entire argument to be deleted in a single stroke if the user decides that the default behavior is actually acceptable. Currently in order to delete a default argument you're required to navigate back and forth to delete both the argument label and the subsequent comma, if present.

2 Likes
(Jordan Rose) #3

I'm pretty sure we have a Radar for this, though I don't see a JIRA. Maybe @blangmuir will have time to comment.

(Garth Snyder) #4

I know this is all Apple stuff, but I'll vent here since there are lots of Apple folks here and Apple's own Radar system and forums are pretty much just a black hole. :blush:

There's some room for improvement here, but I'm not sure I would want to see the actual default values. They're sometimes long and just have an obvious interpretation: nil, [], .default, etc. The signatures are presented in a sizable list along with other alternatives, so simpler is always better - just help me pick out the proper argument set as quickly as possible and then help with the details later once I've picked the signature.

The current scheme seems to be to display the maximally-shortened argument list (leaving out everything with a default) along with the complete signature, as if they were separate functions. This has always struck me as being kind of misleading, especially since defaulted arguments aren't marked.

I think what I'd like to see is some stylistic marking for argument labels that have a default -- italicize the labels in the selection list, perhaps, to indicate that they're optional.

It would also be nice to have an indication that there's a default for an argument once you have picked your function and Xcode has inserted it in the code. And it'd also be nice to have some one-keystroke way to toggle between the template for the full signature and the required-only version of the signature once you have inserted the template.

And lastly, has anyone else noticed that autocomplete seems to have become far slower recently? On my Mac Mini, it's essentially useless now because I can type faster than autocomplete can make suggestions.

4 Likes
(Ben Langmuir) #5

+1 to putting the default value in the

@jrose do we always serialize the text of the default value in swift modules now? I know at some point all we could do was "= default", but I seem to recall this was improved.

I would suggest the development forum, and/or bugs.swift.org :smiley:

rdar://45318854

This could work well with nested placeholders:

<#, instrument: <#String = "trombones"#>#>

Expanding the placeholder would add the comma and argument label and leave you with a new placeholder for the value. I believe the LSP protocol lets us do this, but Xcode does not currently support it AFAICT.

1 Like
(Jordan Rose) #6

Swift 5 always prints the default value now in the generated interface view, yes.

2 Likes
(Ben Langmuir) #7

I agree that the desired behaviour is to have a single completion, probably with some visual indication of which arguments have default values. The current behaviour was added as a crutch for the fact we don't yet have a workflow for adding/removing default arguments once the completion is inserted.

We could either insert all the arguments, but make it obvious which ones are defaulted and make it easy to remove them (would be nice if deleting it removed the preceding comma), or we could insert the minimal set and try to make it easy to add the defaulted arguments. I think there's an argument to be made for either design.

If you have specific cases you can share, please file a bug on bugs.swift.org or bugreport.apple.com. It would be helpful to include a sample of the SourceKitService process taken while the completion is happening if you can catch it in the act. And if you can share the code that reproduced it that would be ideal.

(Frederick Kellison-Linn) #8

Slightly off topic for this thread, but how does this work if the default value is e.g. a private static member?

(Anthony Latsis) #9

Interesting! I would be glad to take this on. I think we should keep the current design of listing shorthand calls (for now) and focus on displaying default values for call variants that have them.

2 Likes
(Jordan Rose) #10

The compiler disallows using a private member in a default argument because we knew we wanted to print them (as a form of documentation). Even if we decide they're cluttering up this view, they're still part of your API, and so that information should be available somewhere.

(If you want to hide what the default value is, (a) how do you expect people to use your function, and (b) make a wrapper function that just exists to hide it.)

5 Likes
(Garth Snyder) #11

Thanks for the specific guidance. I'll keep my eyes open for a good test case.