Powershell: Support named arguments in .NET method invocation

Created on 30 Jul 2020  路  11Comments  路  Source: PowerShell/PowerShell

Problem Statement

The RFC Generalized Splatting is going to be withdrawn. That RFC proposed to use the generalized splatting syntax to support named arguments to .NET method invocation, but the powershell committee has decided against the generalized splatting after further discussion.

However, it would be nice to support named arguments in .NET method invocation with a different syntax in PowerShell, which would improve the readability of the script.

Proposed technical implementation details

The proposal is to use the C# syntax for named arguments. For example:

$myOrder.PrintOrderDetails("Gift Shop", 31, "Red Mug")
$myOrder.PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop")

And use the same semantics as in C# if possible:

  1. The arguments can be in any order as long as they are all named;
  2. When named arguments are used with positional arguments, they are valid if

    • they're not followed by any positional arguments,

    • they're all used in the correct position (_not sure if this is doable in PowerShell -- given that conversion is lax compared to C#, it may not be feasible to accurately decide if positional arguments are used in correct position_)

No Goal

  • COM methods is not in scope.
  • Script methods (ETS) is doable, but not in scope.
Issue-Enhancement WG-Language

Most helpful comment

COM methods is not in scope.
Script methods (ETS) is doable, but not in scope.

@daxian-dbw Could you please add more info? These limitations would confuse users if they will suddenly get errors for some methods.

All 11 comments

I made a few attempts at implementing something like this, but never really got past the hurdle of parsing them. Might be worth another attempt though, I often wish this was a thing.

I'd close the old #7506 to avoid confusion with the withdrawned RFC.

Yes, I agree with @iSazonov. #7506 is the issue that led to the generalized splatting proposed in the RFC, which is going to be withdrawn, so I think it's better to close that one to make it less confusing.

@daxian-dbw IIRC the primary goal for splatting method arguments was really just to splat method arguments. This is a useful thing by itself and would bring parity with the ability to splat arguments to commands. However as a side-effect for doing this, it became possible to do the equivalent of named parameters by splatting a hashtable. This is probably still something we should support. However doing it this way makes it _value_ based and thus highly dynamic v.s. a _syntax-based_ solution which would lend itself to static analysis. So I am now of the opinion that we really should do both: formally supporting named parameters and also supporting splatting in method calls. In fact, in general we should allow splatting in any collection context (splatting hashtables into hashtables, splatting arrays into arrays, etc.)

That's a fun idea, but I don't really see that as being especially useful.

Splatting an array into an array / a hashtable into a hashtable is functionally no different than $array1 + $array2 / $hashtable1 + $hashtable2, at least that's how it'd be read in most cases I can imagine presently.

I like the idea of allowing some kind of splatting for method arguments, but IMO it's more important to just support named arguments in the first place; splatting for methods is something I'd see as a secondary and less useful goal.

@vexx32 Just to clarify, the scenario for ubiquitious splatting is building "complex" data structures where you want to default some of the properties on an object. Something like the following:

$defaultProperties = @{ Width = 200; height = 50 }
$defaultControls = [ ... define some buttons ... ]

# Partial specification for a GUI form.
$form = Form @{
        Text      = "Hi"
        BackColor = "red"
        Controls  = @(
            @{
                Name = "b1"
                OnClick = { ... }
                @defaultProperties # Add the default values to the button spec
            }
            @{
                Name = "b2"
                OnClick = { ... }
                @defaultProperties
            }
            ; add the default controls (help, etc.)
            @defaultControls
        )
    }
}

That makes sense for hashtables, I really like that syntax. For arrays, though, that's exactly equivalent to just dropping the array variable to the pipeline normally.

COM methods is not in scope.
Script methods (ETS) is doable, but not in scope.

@daxian-dbw Could you please add more info? These limitations would confuse users if they will suddenly get errors for some methods.

@iSazonov After enabling the ComInterop code by #13304, the COM operations will be handled by the com binders, which is the code copied from dotnet/runtime with additional refactoring. I'm afraid we don't have enough expertise to make changes to the code, and thus the COM method support is not in scope.

Whoever is going to work on this issue can first target making it work for .NET methods. Although COM/Script are not in scope, it doesn't mean they shouldn't be supported, but just should be a separate task/issue.

So I am now of the opinion that we really should do both: formally supporting named parameters and also supporting splatting in method calls. In fact, in general we should allow splatting in any collection context (splatting hashtables into hashtables, splatting arrays into arrays, etc.)

@bpayette If the "formally named parameter" for method invocation is implemented, I don't think it will be much additional work to support splatting hashtable as named arguments for method invocation. As for the "general splatting" support, I think it's interesting and worth more discussion.

Was this page helpful?
0 / 5 - 0 ratings