Benefits of:
& $object.Method @args
@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 hasInvoke
, 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.
Most helpful comment
Yes! I've always wished delegates could be invoked with
&
.