Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thoughts about breaking up the Splatting RFC into manageable chunks and revisiting the proposed syntax #209

Open
KirkMunro opened this issue Jul 3, 2019 · 4 comments

Comments

@KirkMunro
Copy link
Contributor

The RFC for generalized splatting is currently in the Draft-Approved state, but not being implemented due to a combination of other priorities and complexities in the implementation.

While it's in this wait state, can I express some strong objections to what it proposes, and suggest that more thought is needed here? I can write these up as additional competing RFCs, but I don't want to go through that process if people just disagree with me, so I'll just share my issues with the RFC as it is today for now. And yes, this is opinionated, but I really feel that the syntax proposed in that RFC is making things much more difficult than they need to be. The details below suggest how it may be broken up and simplified, such that there aren't than many splatting-specific improvements needed at all.

Generalized Splatting is not the right way to solve the backtick issue

The Motivation section of the RFC highlights how backticks are not a great solution for multi-line continuance, and neither is splatting. Part of the solution to that problem, as proposed by the RFC, is inline splatting, yet inline splatting has its own issues:

  • splatting uses a different syntax than normal use of parameters in a command invocation, and this inconsistency isn't necessary.
  • conversion to/from splatted parameters or normal use of parameters is a nuisance, even if you have inline splatting.
  • inline splatting can help multi-line continuance for command invocations, but it doesn't allow scripters to wrap other lines in a way that makes code easier to read and maintain (e.g. wrapping multiple method invocations with the dot-reference operator at the beginning of a line).

An alternative to inline splatting (and to getting rid of backtick in general, by allowing scripters to enable multi-line continuance) is described in this RFC proposal. It covers more scenarios, and can be implemented completely independent of splatting improvements.

Splatting expressions shouldn't need special syntax combining @ and $

The RFC proposes splatting the value of a variable using this syntax:

command @$PSBoundParameters

It is not clear what value that syntax offers in the RFC today.

If the intent is that we can support using members on a variable while splatting, why can't we support this less complicated syntax instead?

command @PSCmdlet.MyInvocation.BoundParameters

# or

Invoke-Something @obj.GetInvokerArgs()

As long as the result is a hashtable or an array, we should be able to just make the parser support those syntaxes, shouldn't we? They are unambiguous, and non-breaking. This is an actual splatting improvement that could be implemented as part of a splatting RFC.

Relaxed splatting

Does it even make sense to do this when you can just splat multiple separate hashtables into a command?

The only specific need I know of related to this is mentioned in the Modifying hashtables for splatting alternate proposal, where it would be useful to be able to splat part of a hashtable. For example, something like this:

# Splat all parameters but 'Force'
command @PSBoundParameters-['Force']
# Splat all parameters but 'Force' and 'WhatIf'
command @PSBoundParameters-['Force','WhatIf']
# Splat only the literal path and filter parameters
command @PSBoundParameters+['LiteralPath','Filter']

These aren't really specific to splatting though, they're just about having new index operators for collections that allow you to generate a copy of a collection that excludes certain indices (-[...]) or that only includes certain indices (+[...]). I would recommend that be handled in a separate RFC that could be implemented independently, and then added to splatting as part of the splatting RFC so that it supports those operators inline when splatting.

Splatting in method invocations

This section proposes passing in specific arguments to a method by name, like C# allows. That's a worthy addition to consider adding; however, instead of using a complicated syntax with @@{...} enclosures, how about the following syntax:

$str.SubString(2, length:2)

It's a non-breaking syntactical change, and it's much easier to type and read. The same rules would still apply (named arguments must be at the end).

This is not really splatting and could be proposed as a completely separate RFC and implemented independently of splatting.

@KirkMunro KirkMunro changed the title What to do when you have issues with an approved RFC Thoughts about breaking up the Splatting RFC into manageable chunks and revisiting the proposed syntax Jul 3, 2019
@bergmeister
Copy link

bergmeister commented Jul 6, 2019

For me the 2 most valuable scenarios are:

  • Get-Item @@{Path='C:\'}
  • Get-Item @$(Get-ItemArgs)
    I am currently working on a prototype (nothing pushed publicly yet) for the 1st scenario by adding a TokenKind.AtAtCurly token. I've gotten as far as adding it without making the parser crash when using the syntax. I do understand that in both scenarios, one needs a new, special syntax in order to differentiate from a hashtable being specified as the first argument.
    I think it is definitely worthwhile re-iterating over the specs but at the same time I don't think we'll end up with something or something useful by following waterfall. We've got a rough idea and if we do individual PRs of the pieces, we will probably explore and learn more details of implications that we were probably not aware of yet when thinking about it on a high level in the RFC. To me, an RFC does not mean the actual syntax is completely set in stone, just that the rough high level plan is clear and we do not go on a mission that is impossible or breaking. Therefore I consider things like relaxed splatting an implementation detail at the moment and would not worry too much about it. To be honest, if we get just the first scenario working, then that delivers already 90% of the value with probably just 10% of the time.

@KirkMunro
Copy link
Contributor Author

@bergmeister For those two scenarios, why do you find them valuable? I think I know the answers already, but I want to make sure I'm not making assumptions.

@bergmeister
Copy link

bergmeister commented Jul 7, 2019

@KirkMunro The first scenario is to avoid defining a variable just for the sake of using splatting.
The second is to have a scenario like Invoke-Something @$(Get-Options $IsWindows) where previously one had to either assign to a variable again as well or having to write conditional logic to manipulate a 'base' hashtable for a custom scenario. All the other advanced scenarios come afterwards but first we need to get the basics in. Most people also cannot write scripts that run only on v7 so having a good base of language support will be important down the line for the next years.
P.S. I already opened a PR for the 1st scenario:
PowerShell/PowerShell#10073

@KirkMunro
Copy link
Contributor Author

For me, neither of those add enough value, and both of them add significant syntactic complexity to the language.

The first one can be managed more easily without splatting at all, as described above.

And for the second, if someone really wants to use a function to get parameters, frankly, it's ok for them to need to store the results of that in a variable before they splat. Plus examples where this is needed would really, really help (I've yet to see one, so if anyone has specific examples, please share them). I'd wager that if people are using functions to get parameters/arguments that they want to splat, it's most likely helper functions used to manipulate/copy existing collections, which can also be done inline in a better way, without a helper function, as proposed above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants