Skip to content

RFC for expanded implicit line continuance feature #176

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

Conversation

KirkMunro
Copy link
Contributor

This is an RFC to expand implicit line continuance in PowerShell so that users can wrap commands across multiple lines when using named parameters or splatted collections without having to use backticks or splatting.


Special casing the named unary operators could work (among the thousands of commands on my system, none of them have split or join parameters, but some may exist somewhere), but that would mean future unary operators be special cased as well, so that approach isn't desirable because it risks future breaking changes.

If the risk is deemed to be too high because of the risk with named unary operators, at a bare minimum I feel this feature offers enough significant value to the community that it should not be rejected, but instead offered as an optional feature so that users wanting the benefit can opt-into the functionality, and mark it as enabled for their scripts/modules. I also suspect the majority of scripters would want it turned on and would then simply write their scripts accordingly. It's really too bad though that unary operators with string names use the same single first character as parameter names because they get in the way here. In hindsight, named operators should probably have been prefixed with something other than a single dash to differentiate them from named parameters (something to consider if PowerShell ever comes out with a version with significant breaking changes plus conversion scripts).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it reduce the risk if we require some character on the line after the command to initiate support for parameter line wrapping? For instance, what if we put the splat character (and ignored whitespace) at the end of the line as an indicator that the parameters continue on multiple lines:

Get-Process @
-Id $pid

vs

Get-Process -Id $PID
-split 'a b c d'

Copy link
Contributor Author

@KirkMunro KirkMunro May 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting. That would eliminate the breaking change factor entirely, making it opt-in. A little unfortunate to have to add something to each command you want to wrap, vs having a feature/flag that allows script/module authors to enable this for their content without impacting end users ad-hoc use.

Another syntax that came to mind for me when I read your suggestion:

Get-Process ...
   -Id $pid

😆

Regardless of the character(s) used to indicate you want to wrap the command, that could also make it possible to use ad-hoc in a terminal, with PowerShell only terminating the command once you have pressed enter twice.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial read of this RFC was negative simply because it would change the functionality of non-visable characters in a non-obvious way. Choosing the begin wrapping with the '@' character makes the most sense to me. This is way better than using a back tick and if fully supported, should also provide intellisense. That would make this method preferable when compared to splatting which has no intellisense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I'm thinking it might be interesting if the Windows terminal supported a multi-line command mode, allowing users to enter multiple-line commands without executing them until enter is pressed after a blank line at the end of the command. And the terminal is open source now. Hmmm.....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ngetchell It would only be non-obvious if you followed a command with the -splat or -join unary operators (or a command whose name starts with dash, but I've yet to see one of those). Plus scripters should apply appropriate formatting to this, just like they would for wrapped pipelines, making it pretty obvious to the reader. What I like about the extra character at the end (and the other alternative I added, which happens to be my preference) is that it makes this become a non-breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth pointing out that Write-Host @ is currently not valid with a line-ending after it, whereas, for instance Write-Host ... is valid currently, because ... is interpreted as a string...

@essentialexch
Copy link

What about "-$i", "--$i", "--$i:$false", etc.?

In general, I think this is a bad idea. It provides little, if any, benefit over splatting.

@KirkMunro
Copy link
Contributor Author

@swngdnz None of those are valid named parameters, so there wouldn't be any implicit continuance.

Regarding whether or not this provides benefit over splatting, Intellisense and tab completion are a tremendous benefit for the scripting community. If you don't need them, that's ok, use splatting. But splatting isn't helpful to the PowerShell learning curve.

@Jaykul
Copy link
Contributor

Jaykul commented May 17, 2019

It does provide some benefits over splatting:

  1. The parameters are after the command. That's actually a major improvement in readability, and therefore maintainability.
  2. You get intellisense while typing parameters. That's a major improvement in maintainability too.
  3. You're not storing all the values you need to pass in into a hashtable indefinitely. This can be pretty significant, depending on how big those parameter objects are

@essentialexch
Copy link

Sure, I generally add splatting "after the fact" when I know I'll have a long/variable parameter set.

Hashtables store object key-values by-ref don't they, not by-val? (I just tested this, and at least on 5.1 it's true.)

Hmmm. I'm not exactly sure what "get-module -$i" or "get-module --$i" are doing. But they don't generate an error.

I still think this adds complexity (more choices) and isn't powershell-y.

@Jaykul
Copy link
Contributor

Jaykul commented May 17, 2019

Get-Module -$i is passing the string "-$i" (with the value of $i expanded) as a parameter value not a parameter name. Kirk's point is that it's not a valid parameter name, so the RFC would not treat that as a continuation of the command.

You can see it better if you use get-command:

$i = "name"
Get-Command -$i help                                                                                                                                                          

# ERROR: Get-Command : The term '-name' is not recognized as the name of a cmdlet, function, script file, or operable program.

@essentialexch
Copy link

Yeah, I got that. I'm not intimately familiar with the parser to know how quickly it shortcuts '-'.

My point was an aside: what the heck is "get-module 3". :-) I guess it's looking for a module named "3". :-)

@GABeech
Copy link

GABeech commented May 18, 2019

I'm going to start with my Conclusion
I would much rather see this RFC withdrawn, #8938 reverted and a new RFC started to allow for a full, open discussion around the entire concept of having line endings no longer terminate statements.

I do not think this RFC is a good suggestion, and additionally I am surprised that this is an expansion on
a syntax that was added to the language (Set for PS7) without an RFC that I can tell, nor with the community reaching a consensus. Yes, it is an experimental feature now, but a fundamental shift in the way that the parser behaves should have gone through a full RFC IMO, not just pushed through in a PR.

There is a set of PRs here ( #8938 #9614 ) that seem like a few people trying to push through a language change that they cannot get consensus on.

One of my major issues with this RFC is that it changes a fundamental way that the language works. These changes are mostly for stylistic changes and we cannot fully evaluate the extent of the problems that having line endings not terminate a statement could introduce. This RFC would introduce an unexpected (possibly breaking) behavior for little gain.

Yes, there are some exceptions already to the line ending terminates a statement, but those are all easily parseable and do not negate the rule. They all use known start and finish tokens and are not continuing statments. They can be abused to do so, but that shouldn't be a reason to implement this.

  @{
    Key1 = Value
    Key2 = Value
  }

In the above example the begining and end of the statement are clearly delinated by {} inside of this statement the individual Key/Value pairs are delinated by a line ending.

Another example is in the grouping syntax

  $test = (Get-Process -Name | 
    Format-Table)

Even in these contexts when you are inside of the Grouping or Block statement delimter, the normal rules apply. You need to conform to the parsing standard inside of these block section.

# Invalid
  $test = (Get-Process -name 
    | Format-Table)

We are only introducing unpredictable behavior that allows some people to write in a style they like instead of using styles that are currently supported by the language. This proposal doesn't do much to make code more readable, in situations that you are continuing onto the next line the location of the | isn't really the piece that makes it readable. The indentation - something that can be done today - is what makes it more readable.

Fundamentally, this is not a change that adds much - if anything - and introduces a whole lot of risk.

@KirkMunro
Copy link
Contributor Author

KirkMunro commented May 18, 2019

@GABeech: To be clear, RFC or no RFC, I think through code that I write, especially when I'm in a code base that is less familiar to me. This allows me to understand possibilities, look into code history, and see if something can/will just work before getting into discussions with others about whether or not it will work. This is just how my thought process works, and it allows me to provide a working build if people want to kick the tires on the idea, whether it's from an RFC or just a PR. It isn't a sign of me "trying to push through a language change that I cannot get consensus on".

As for the comment about "little gain" from this RFC, this solves a significant problem: it allows scripters to span commands across multiple lines for easier readability/maintenance without using backticks (which are considered an anti-pattern by many) without losing Intellisense and tab completion (as they do with splatting). The lack of Intellisense/tab completion may not be a big deal to you, if you are already knowledgeable of the commands you are working with, but they are a boon for users who are not familiar with commands, and being able to use Intellisense on wrapped commands that can have many parameters without backticks is significant gain for many scripters -- just maybe not for you.

As for risk, that's why this is an RFC, and why the experimental feature is used in the PR, because there are breaking changes involved, and I wanted discussion/thoughts around them, and some great suggestions and ideas I've come up with since the first post have already come out of that which would eliminate the possibility of breaking changes. Also note the implicit continuance is only applied in a very specific set of scenarios: named parameters, splatted collections, and the stop parsing sigil, and only when used on contiguous lines following a command. Given the scope of the changes, I disagree with you that this introduces a whole lot of risk, and your suggestion that "we cannot fully evaluate the extent of the problems that having line endings not terminate a statement could introduce" is simply unfounded.

As for the other PR that you're complaining about after the fact, it does not introduce any breaking changes, and in both of your last two examples in your post, the intent of those is clearly unambiguous, and the behavior is predictable. Style matters. If you don't like one style, use another.

@SteveL-MSFT SteveL-MSFT changed the title Add RFC for expanded implicit line continuance feature RFC for expanded implicit line continuance feature May 19, 2019
@KirkMunro
Copy link
Contributor Author

I still think this adds complexity (more choices) and isn't powershell-y.

@swngdnz, what part of splatting doesn't add complexity to command invocation for a scripter who wants Intellisense and Syntax Highlighting? How is this more complex than that? Or even backtick for that matter, which must be included on every line with some spacing requirements and is barely visible?

The point isn't more choices. The point is better options.

Those questions aside, more alternatives have been added to the RFC this morning.

For users commenting on this RFC, when it comes to feedback, rather than block/soapbox, how about trying to recognize/understand the issue(s) it is designed to solve and working together towards coming up with something that does just that. Of the few (they are the minority at this point) people who have expressed discontent over this RFC so far, they either completely ignored the intent of the RFC in their "feedback" (to provide Intellisense/tab completion on wrapped commands without needing to use the backtick), or they replied something along the lines of "well I just do ...", neither of which is serving the needs of the community IMO.

@essentialexch
Copy link

I've already written that I rarely start with splatting. It's something I add later, when I know I may have optional parameters or long command lines. By that point, I'm past any goodness that might be added by Intellisense or tab completion.

I don't think this RFC serves the needs of the community. It fragments it. It leads to an egregious syntactic difference between Windows PS and PS Core. One that, as originally written, is hidden.

I will say that I rather like the syntax you suggested this morning: "New-Command -{ -param1 value -param2 value }". Although I think syntax like "New-Command @{ param1 = value; param2 = value }" is more powershell-y and a natural extension of current splatting syntax. Yes, it would break anything that has a default hashtable parameter. Something in between: "New-Command -@{ param1 = value; param2 = value }" seems to be clean.

@GABeech
Copy link

GABeech commented May 20, 2019

@GABeech: To be clear, RFC or no RFC, I think through code that I write, especially when I'm in a code base that is less familiar to me. This allows me to understand possibilities, look into code history, and see if something can/will just work before getting into discussions with others about whether or not it will work. This is just how my thought process works, and it allows me to provide a working build if people want to kick the tires on the idea, whether it's from an RFC or just a PR. It isn't a sign of me "trying to push through a language change that I cannot get consensus on".

My issue - and apologies if this was not clear - has nothing to do with the fact that the code was written. I have an issue with the fact that it was pulled in before a full discussion of the issue. And, the way that things where being pushed forward without 1) and RFC or 2) Anything that seems to be consensus.

As for the comment about "little gain" from this RFC, this solves a significant problem: it allows scripters to span commands across multiple lines for easier readability/maintenance without using backticks (which are considered an anti-pattern by many) without losing Intellisense and tab completion (as they do with splatting).

Yes, I understand that. However this is a fundamental change to the way the language works. And there are many more people than just scripter. Some - like myself - who don't see a readability problem with the current options. That is why I see little gain to this, and a lot of risk. Like I said above, for me the readability comes from having white space leading the continued line.

Have you explored what it would take to get intellisense with splatting? Maybe with hinting something like:

<#
  [get-childitem]
  Splat for get-childitem used to get the items in C:\temp\testing
#>
@{
      Path = "C:\Temp\testing
     Recurse = $True
}

It seems to me there are plenty of ways we could look at before changing the way the parser works.

The lack of Intellisense/tab completion may not be a big deal to you, if you are already knowledgeable of the commands you are working with, but they are a boon for users who are not familiar with commands, and being able to use Intellisense on wrapped commands that can have many parameters without backticks is significant gain for many scripters -- just maybe not for you.

It isn't a big deal to me, not because I am super familiar with the options of commands. But, because there are many options besides changing a fundamental assumption about the parser.

Things like testing on the command line, writing out the command then breaking it across multiple lines later, or just having the documentation up on another screen.

As for risk, that's why this is an RFC, and why the experimental feature is used in the PR, because there are breaking changes involved, and I wanted discussion/thoughts around them, and some great suggestions and ideas I've come up with since the first post have already come out of that which would eliminate the possibility of breaking changes. Also note the implicit continuance is only applied in a very specific set of scenarios: named parameters, splatted collections, and the stop parsing sigil, and only when used on contiguous lines following a command. Given the scope of the changes, I disagree with you that this introduces a whole lot of risk, and your suggestion that

Off the top of my head some risks would be:

  • How does this effect tooling?
  • What happens when the parser does the wrong thing?
  • How does this effect the large number of people using PS and expecting that outside of a few very specific circumstances commands are terminated with a new line?

"we cannot fully evaluate the extent of the problems that having line endings not terminate a statement could introduce" is simply unfounded.

There is a lot of PS code out there, there are a lot of tools out there, this is a fundamental change to the way the parser operates. I think that is a pretty fair statement.

As for the other PR that you're complaining about after the fact, it does not introduce any breaking changes, and in both of your last two examples in your post, the intent of those is clearly unambiguous, and the behavior is predictable.

Sure, the examples are unambiguous. That's part of the point of the examples. And honestly I haven't seen any examples where this new behavior improves anything beyond what we have available today. There are many ways to write a script in a very readable way without resorting to changing a core part of the the way the language operates.

Style matters. If you don't like one style, use another.

It does, but to be frank, I'm not the one proposing a change to a fundamental way the language operates. I didn't decide I didn't like a certain style and then try to modify the way a language operates to fit my preferred style. To me, "I don't like the current options on line continuation" is not a significant enough reason to make a change like this.

@KirkMunro
Copy link
Contributor Author

KirkMunro commented May 20, 2019

But @swngdnz, who cares how the RFC was originally written? It hasn't even been merged into the RFC tree yet. You just picked up on it because @Jaykul tweeted about it after I reached out to him and one other person for initial comment. I'm ok it was tweeted, because I've been able to incorporate feedback already, but regardless, the way an RFC is originally written doesn't matter, does it? That's the point of the RFC process, to massage it into something workable.

On Windows PS vs PS Core syntactic differences, you did see the memo that PowerShell 7 is the merger of these two separate things into one body, right? So there would be no differences. Just one PowerShell.

I thought about the -@{...} syntax, but that means working with parameters inline as hashtable values, which is restrictive, because you can also splat arrays as arguments into a command, and a hashtable wouldn't allow for that. -{} allows for wrapping positional parameters and/or arguments as well, in whatever order you choose.

@essentialexch
Copy link

I've also seen the memo that until PS Core can run on an Exchange server, replacing Windows PowerShell, Windows PowerShell is what matters to me. Based on comments from the team, there will be a number of workloads, Exchange among them, that PS 7 will not cover.

It's obvious you discount my perspective. It's unfortunate.

@KirkMunro
Copy link
Contributor Author

@swngdnz sigh I do not discount your perspective. How is that obvious? I may not understand every aspect of it, but I most certainly don't discount it. I read every word on the feedback, from everyone, think about it, and try to respond to it and work in alternatives if appropriate.

Let me ask you this: Windows PowerShell is what matters to you, and I understand why, but does that mean syntax changes in PowerShell v7 shouldn't happen until it's supported on an Exchange server?

I don't understand the point you're trying to make about Exchange, nor do I understand why you feel I'm discounting your perspective.

@KirkMunro
Copy link
Contributor Author

@GABeech Regarding PR8938, I should add one more important detail: other programming languages that do not have line terminators and that do have continuance characters recognize and support (where possible) multiple multi-line chaining styles without using line continuance characters(e.g. ruby. This doesn't break PowerShell. It offers an additional pipeline chaining style that suits the needs of the scripter. It doesn't have to have full consensus across the community to be worth adding to the language when the risk is insignificant. Arguments for/against such styles are similar to arguments about indentation or bracing styles. Let the community do what they want when it makes sense to do so (and despite there being some opposition, it made sense to support this syntax in scripts which increases readability for many). I don't really know what else to say about that PR on this thread, other than I'm sorry you don't like it.

This RFC is related because it's about parameter-chaining, ideally without continuance characters (because they shouldn't need to be used unnecessarily), but possibly with a sigil or enclosure for continuance if it's absolutely necessary to have one. You keep hitting on readability and fundamentals. I keep going back to Intellisense plus tab expansion without having to use line continuance (or one of the alternatives presented in the RFC). Feels like we're talking around each other there, which is unfortunate.

I didn't decide I didn't like a certain style and then try to modify the way a language operates to fit my preferred style. To me, "I don't like the current options on line continuation" is not a significant enough reason to make a change like this.

And in saying so you're implying that I did? How about we stop with the finger pointing. Having worked very closely with the PowerShell community for over 12 years, I'm most certainly not creating PRs/RFCs just because it suits my own needs.

@GABeech
Copy link

GABeech commented May 20, 2019

@KirkMunro Honestly, at this point I've made my points. You seem content to hand-wave them away with "It's an insignificant risk" I don't agree, and have given some examples as to why (as well as alternative suggestions).

Quite honestly throughout this thread you have been pretty dismissive of concerns brought up (by myself and others) and I have no desire to continue trying to get my point across where it is obvious you don't want to take those concerns into consideration.

@essentialexch
Copy link

You are the one that bought up "PS 7 to rule them all", not me. In fact, PS 7 will NOT rule them all. That's the only (counter-)point I was making to your statement.

There is nothing wrong with enlightened self-interest. You are almost certainly bringing this RFC up because, at least at some level, it meets your needs. Nothing wrong with that, whether I agree with your RFC or not.

I've also been involved with PowerShell for 12+ years, since we were using Monad in Exchange 2007 TAP. But I am a scripter, not a developer. I'm a good scripter, but "just" a scripter. Pulling out a C# compiler is something I do as a very last resort.

You wrote:

which is restrictive, because you can also splat arrays as arguments into a command, and a hashtable wouldn't allow for that

what exactly do you mean?

@{
  a=1
  b='str'
  c=1,2,3,4,5
}
$a=1,2,3,4,5
@{
  a=1
  b='str'
  c=$a
}

Both of these work exactly as I expect and splat as I expect.

In re: discounting my perspective - just like @GABeech - in my opinion, you have hand-waved my objections away and dismissed them as unimportant. No point in my taking any further effort.

@KirkMunro
Copy link
Contributor Author

KirkMunro commented May 20, 2019

Thanks for responding @swngdnz.

In re: discounting my perspective - just like @GABeech - in my opinion, you have hand-waved my objections away and dismissed them as unimportant. No point in my taking any further effort.

Last part first: I am trying to take all perspectives into account, not be dismissive or wave away something as unimportant, with one exception: I think arguments about this not being necessary from scripters who have been using PowerShell for a long time may be missing the point. That doesn't make those perspectives unimportant, but I am trying to keep focus on users less experienced with PowerShell or new to PowerShell while absolutely considering backwards compatibility with the thousands of scripts and many tools that are that are out there. That aside, there are some thoughts on this thread that I didn't respond to yet because I'm thinking about them, but that aside I'm reading/considering everything as best I can.

For the comments about splatting, my counterpoint about using -{...} enclosures instead of -@{..} enclosures was simply that inside of the former, I can mix named parameters, positional parameters, and arguments in any order I want, wrapping wherever I like. In the latter, I'm given a hashtable structure which gives me named parameters and their values only.

e.g. This is more flexible for all inputs into a command:

someCommand -{
    42
    -c foo
    --please
}

# or

Get-ChildItem -{
    C:\
    -Filter *.ps*1
    -File
    -Recurse
}

# or even if we went with a sigil that told PowerShell to parse the command parameters and/or
# arguments in multi-line mode until it encountered a non-newline command terminator or
# a blank line

New-ADUser ...
    -Name 'Jack Robinson'
    -GivenName 'Jack'
    -Surname 'Robinson'
    -SamAccountName 'J.Robinson'
    -UserPrincipalName '[email protected]'
    -Path 'OU=Users,DC=enterprise,DC=com'
    -AccountPassword (Read-Host -AsSecureString 'Input Password')
    -Enabled $true

This enclosure would presumably enforce hashtable syntax, which means no positional parameters, no arguments for external commands that don't have parameters at all (unless of course you also had -@(...), but then you'd have to pick one or the other):

Get-ChildItem -@{
    LiteralPath = 'C:\' # I can't use a positional parameter here
    Filter = '*.ps*1'
    File = $true
    Recurse = $true
}

In my mind, the former is more flexible and allows for transition to/from that syntax with no changes whatsoever to the parameters/arguments used with the command.

Here's another alternative sigil to do the same thing that is a bit more literal:

```PowerShell
New-ADUser ...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of ... over @. I think the readability of ... is poor. My vision is bad and the ellipsis blends in with the line below it. Also it could be confused with (The Unicode ellipsis character). But I do like the idea of using something here and won't bike shed on it. I just want to call out the readability issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My current favorite is this alternative -- not the ellipsis specifically, but some sigil to tell the parser to parse the rest of the command in multi-line mode, meaning it would parse parameters/arguments until it encountered a command terminator (e.g. semi-colon, closing brace/bracket, etc.) or a blank line. It's minimal, transitioning to/from that syntax is as simple as adding/deleting the sigil and some newlines, and commands could be wrapped however the scripter wants, it would work in the interactive shell, and it would be completely non-breaking as long as the sigil was chosen carefully.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'm rather fond of using ~ as the continuation token here:

Get-ChildItem ~
    C:\
    -Filter *.ps*1
    -File
    -Recurse

Copy link
Contributor Author

@KirkMunro KirkMunro May 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, when I saw this on my phone without my glasses, I thought the sigil you proposed was -, which I liked at first, but later realized that it is already used for continuance in arithmetic expressions, so that's out. I'm less fond of ~, at least at first glance, but once we decide on an approach to take (assuming we get that far), we can discuss which sigil makes the most sense and share a bunch of options.

Copy link
Contributor

@Jaykul Jaykul May 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I made the suggestion about a character after trying it out. You guys aren't even thinking about it very hard, never mind actually trying it out. I believe the @ works because it's not valid syntax currently. All those others are already valid input.

> write-host -{ write-output 'hello' }
- hello

> Write-Host ...
...

> Write-Host ~
~

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'm rather fond of using ~ as the continuation token here:
Get-ChildItem ~
C:
-Filter .ps1
-File
-Recurse

In addition to Jaykul's Write-Host example, ~ is a shortcut for the current user's home folder. Get-ChildItem ~ will return items from that folder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jaykul actually I'm thinking about this RFC a ton. I just didn't come back to comment again after I replied when I realized neither - not ~ would work. In the case of my last comment, it is less about not thinking too hard, more about responding too quickly to another comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to mention that I rarely if ever use Write-Host (which I know you have used a lot), so some of those use cases never occurred to me. Of course that's why we have an RFC for this.

@vexx32
Copy link
Contributor

vexx32 commented May 21, 2019

Tbh, with this we're kinda starting to get in the "generalized splatting" RFC territory, where supposedly this would be possible with this syntax instead (among other things outlined in that RFC):

Get-ChildItem @@{
    Path = "C:\"
    Filter = "*.ps*1"
    File = $true
    Recurse = $true
}

@KirkMunro
Copy link
Contributor Author

@vexx32 I agree, except that splatting has a specific syntax for either named parameters only or arguments only, which is one reason why I really don't like the idea of inline splatting. Regardless of whether a sigil is used or enclosures, something very nice about both approaches is that the syntax of the parameters/arguments themselves does not change at all, making going to/from that syntax with any command very, very easy.

@Jaykul
Copy link
Contributor

Jaykul commented May 22, 2019

I have to add with regards to @GABeech's argument that we need to preserve line endings as statement terminators:

I don't think that the PR that already went in, allowing placing the | on the front instead of the end of the line is that significant a change to syntax. The idea that newlines are always statement terminating is clearly simplistic: there are a lot of exceptions. One such is when there is a | at the end of the line (optionally followed by white space). Now there's one more: when there is a | at the front of the next line.

Simply moving the pipeline continuation character to the other side of the white space is not going to break simple tooling (like the regex-based parsers in textmate editors such as VS Code), because entire statements are kept together, and simple tooling doesn't care about pipes as a relationship, only as a separator. More complex tooling built on top of the AST is unlikely to be affected, since the AST parser will continue working, and individual statements are still all on one line.

The change in this RFC would be a much more significant change, which I can imagine breaking external tooling.

Even with a mode character like @, we would be introducing a modified parser mode that might be difficult for tooling to handle (it might require a new scope in the TextMate syntax, for instance).

That's made worse if the line-wrapping requires one of a whole range of patterns on the next line. To simplify, there's at least three in the RFC, right?

  • \s*-\w
  • \s*--%
  • \s*@\w

Maybe it breaks tooling

That's relatively true for every change that we make to the language, whether it's adding -parallel to foreach, adding new literal number types, unicode character syntax, or new operators. I don't think needing to update third-party tools is an argument that can prevent a change. I'm not sure that even the difficulty of parsing in this case is enough of an argument.

For me the question is:

  • Is the change worth the effort to update the tooling "we" are responsible for (i.e. VS Code tooling, ScriptAnalyzer, etc.)
  • Is the change worth the possible breakage of existing scripts

In this case, I think that it's worth the effort to update tooling, at least as an experiment, but I don't think the improvement is worth (potential) breakage of existing scripts. With a change to make it explicit, I think it's OK.

@SimonWahlin
Copy link

I like it!

I do a lot training/instructing/helping people new to PowerShell. Splatting is a hard concept to understand for beginners.

A lot of documentation uses examples with backticks for readability and accidental trailing whitespaces brings a lot of grief for beginners.

Some kind of reliable and easy to understand line continuation would be great. If implicit continuation could be made reliable, sure, but I think some kind of token would be safer. Since --% already is a token interpreted by the parser, something similar would make sense to me, like this here-string inspired one
Get-ChildItem --@
C:
-File
@--

@SeeminglyScience
Copy link

I've always found splatting to be lacking when it comes to readability. In my experience it provides the illusion of readability for the writer, but it feels like it hurts readability when reading code written by other folks.

Even if the command is directly under the hashtable (best case scenario for readability) you're still reading parameters first, command second. It takes more time to mentally parse, even if by a very small margin. On top of that, if you are working with a module that is very heavy on parameters, you can end up splatting most of your commands which quickly becomes a mess.

As for a continuation character, < seems to fit thematically and currently results in a hard parse error. That would sort of close the door to implementing input redirection though.

@vexx32
Copy link
Contributor

vexx32 commented May 22, 2019

We could take a leaf from F# and make it a two character token with <| which does that without completely closing the door on redirection?

@Graham-Beer
Copy link

Graham-Beer commented May 22, 2019

@vexx32 Something like this?

Get-ChildItem <|
     path = c:\
|>

or more

Get-ChildItem <|
    c:\
|>

But then are you relying on positional parameters for the latter?

@vexx32
Copy link
Contributor

vexx32 commented May 22, 2019

Not sure if an enclosure is strictly necessary, but you could presumably mix and match using regular parameter syntax:

Get-ChildItem <|
    C:\
    -Recurse
    -Filter '*.txt'

Or perhaps we could follow the recent trend and allow something more like...?

Get-ChildItem
<| C:\
<| -Recurse
<| -Filter '*.txt'

@Graham-Beer
Copy link

I personally like the first option Joel of a single <|
Could also enforce a tab or 4 spaces (like python) for the arguments. Like the idea of using the <| as its an additional character to the language and can't be confused with another action.

@SteveL-MSFT
Copy link
Member

How about a counter-proposal for "inline splatting"?

get-foo -@{
  bar = 1
  param2 = "hello"
}

PowerShell would understand this so that intellisense would be supported.

@essentialexch
Copy link

I also suggested that at #176 (comment).

@vexx32
Copy link
Contributor

vexx32 commented May 22, 2019

The one drawback there which it seems @KirkMunro was trying to avoid is that it mandates named parameters.

@KirkMunro
Copy link
Contributor Author

KirkMunro commented May 22, 2019

@SteveL-MSFT I have two main problems with using inline splatting as a way to get multi-line commands in PowerShell more easily:

  1. You cannot transition to/from the inline splatted syntax without a bunch of manual tweaks to the command (either converting parameter syntax into hashtable or array syntax or vice versa).
  2. You're forced to choose between named parameters or positional parameters/arguments. i.e. You can splat in a hashtable of named parameter/value pairs or an array of positional values, but you can't mix the two.

Compare that with this syntax, which can be converted between a single-line command and a multi-line command by just adding/removing a sigil and some newline characters:

# Single-line version
Get-ChildItem $rootFolder -Recurse -Filter *.ps*1

# Multi-line version of the same
Get-ChildItem @
    $rootFolder
    -Recurse
    -Filter *.ps*1

The fact that the syntax doesn't change other than newlines and the sigil, even for parameters of type switch (one of a few splatting annoyances), allowing any combination of named parameters, arguments/positional parameters, splatted collections stored in variables, and even the stop-parsing sigil to be used in the command the same way regardless of whether it's single-line or multi-line significantly lowers the learning curve for something that should be pretty basic.

I'm not opposed to having the counter-proposal, but it's important to know the limitations of that proposal up front.

@KirkMunro KirkMunro closed this May 23, 2019
@KirkMunro KirkMunro deleted the implicit-line-continuance-for-parameters-and-splatting branch May 23, 2019 00:09
@KirkMunro
Copy link
Contributor Author

After reviewing feedback again and doing more research, I've cleaned up the RFC and due to significant changes (and the fact that I renamed the branch, which I thought would carry through GitHub and didn't realize would disconnect me from the original RFC's PR), I posted the updated version a new PR: #179.

@SteveL-MSFT
Copy link
Member

@KirkMunro the sigil helps alleviate some of the compatibility concerns, but isn't sufficient without a closing sigil.

@KirkMunro
Copy link
Contributor Author

KirkMunro commented May 23, 2019

@SteveL-MSFT See the comments in the "Enclosures instead of a sigil" on the bottom half of this. What closing sigil could be used after the stop-parsing sigil without introducing a breaking change?

Plus when users aren't using the stop-parsing sigil, there already are multiple closing sigils: semi-colon, pipe, closing enclosures (e.g. }), the background operator, a redirection operator.

Or...a blank line.

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

Successfully merging this pull request may close these issues.