Powershell: PSMethod should be supported by invocation operator &

Created on 20 Jun 2019  路  12Comments  路  Source: PowerShell/PowerShell

Summary of the new feature/enhancement

Benefits of:
& $object.Method @args

  1. more consistent invocation syntax with commands
  2. gain of PS argument magic
  3. no collision with existing method overloads discovery mechanism when method is used as command
Breaking-Change Issue-Enhancement WG-Language

Most helpful comment

[math]::sqrt | % invoke 9 works nicely. I still think that if an object has Invoke, then & should be able to invoke it.

Yes! I've always wished delegates could be invoked with &.

All 12 comments

@sizur This syntax already has a defined meaning. The result of the expression after the & is evaluated as a module object which is used as the context for the rest of the command. :

Desktop (1:12) >  $m = @{ m = get-module PSReadLine }
Desktop (1:13) >  & $m.m gv PSScriptRoot

Name                           Value
----                           -----
PSScriptRoot                   C:\Users\bpayette\Documents\WindowsPowerShell\Modules\PSReadline\2.0.0

@bpayette does this cause any issue? I mean you can interpret a method in this context as a module closure. What am I missing here?

@bpayette are you trying to say there'd be some kind of conflict in syntax? $m.m can be evaluated, check if it's a PSModuleInfo, and if not we can add an extra case to check if it's a MethodInfo object?

@sizur - I'm with you here. I don't think it is a conflict at all; it seems to be an expansion of the call operator's capabilities. I asked for this functionality way back in 2007, but it couldn't be justified. Then powershell 2's modules came along and muddied the water. Right now, the call operator can be used with strings, scriptblocks and moduleinfos (what @bpayette said). Extending it to handle PSMethods should be doable.

IIRC, I told the powershell team that "& should be able to call All the Things"

@sizur The expression is currently parsed as:

& ($foo.bar) cmd args...

which should effectively result in

& <executionContextObject> cmd args...

It also currently supports CommandInfo objects

& (get-command getdate)

Otherwise, the value is converted to a string and used as the name of the command to run:

& ("get-" + "process") -name csr*

So while it is possible to special-case MethodInfo objects and treat the command line as a method call, this would be a (minor) breaking change. As to the utility of this change, I vaguely remember trying this out when I originally implemented modules and it didn't seem like it was worth the effort when you can just do

$foo.bar(1,2,3) | some-thing...

Note that expressions are only allowed at the beginning of the pipeline. There is also an RFC out that addresses splatting/spreading for methods. Finally, if you do want to invoke a method in the pipeline, ForEach-Object already allows you to do that

{master}PSCore (1:16) >  "Hello world" | foreach substring 2 3
llo

(Aside: the other thing I considered was allowing you to assign MethodInfos to function table entries (converting them into some type CommandInfo) e.g.

$function:sin = [math]::Sin
sin 0.5

Which I thought seemed promising but others disagreed :-)

@bpayette what about using a TypeConverter mechanism for implicit PSMethod->ScriptBlock enclosing over method and just rely on &'s handling of ScriptBlock?

[math]::sqrt | % invoke 9 works nicely. I still think that if an object has Invoke, then & should be able to invoke it.

[math]::sqrt | % invoke 9 works nicely. I still think that if an object has Invoke, then & should be able to invoke it.

Yes! I've always wished delegates could be invoked with &.

PS > function call {$invokable, $params = $args; $invokable | foreach Invoke @params}
PS > call ([System.Math]::Pow) 2 8                                                   
256

@bpayette, you mentioned that adding MethodInfo case to & would be a minor breaking change. It's not yet clear to me why. Do you expect some code somewhere intentionally invoking a command based on stringified method object?

PS > function call {$invokable, $params = $args; $invokable | foreach Invoke @params}
PS > call ([System.Math]::Pow) 2 8                                                   
256

@bpayette, you mentioned that adding MethodInfo case to & would be a minor breaking change. It's not yet clear to me why. Do you expect some code somewhere intentionally invoking a command based on stringified method object?

I presume because you could do something like this today:

Set-Content -LiteralPath "function:$($Host.UI.WriteLine)" -Value {
    $Host.UI.WriteLine.Invoke($args)
}

& $Host.UI.WriteLine 'this is a test'

Note that he did say minor. It's definitely a breaking change, it's just incredibly unlikely to actually break anything.

... that's... that wouldn't even work, though. The output from $Host.UI.WriteLine shouldn't result in the text necessary to invoke the function. You'd have to call it like this:

& '$Host.UI.WriteLine' 'this is a tes'

So the odds of anyone doing something _that_ kludgy are astronomically low, just because it's both difficult to make work _and_ really out in the weeds, as it were.

... that's... that wouldn't even work, though. The output from $Host.UI.WriteLine shouldn't result in the text necessary to invoke the function.

Sure it does

PS> $Host.UI.WriteLine.ToString()
void WriteLine(), void WriteLine(string value), void WriteLine(System.ConsoleColor foregroundColor, System.ConsoleColor backgroundColor, string value)

The PSMethod is converted to a string in both places, and that's unique enough for a function name (assuming it's a method on a singleton-like object like $Host). You can run the example I gave, it does indeed work.

So the odds of anyone doing something _that_ kludgy are astronomically low, just because it's both difficult to make work _and_ really out in the weeds, as it were.

Yeah I did say incredibly unlikely to actually break anything. I'm not arguing that it shouldn't be done, and I don't think @bpayette was either. It's still worth mentioning in case someone has a use case that hasn't been considered.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

manofspirit picture manofspirit  路  3Comments

andschwa picture andschwa  路  3Comments

HumanEquivalentUnit picture HumanEquivalentUnit  路  3Comments

rkeithhill picture rkeithhill  路  3Comments

JohnLBevan picture JohnLBevan  路  3Comments