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

Make methods in custom classes support optional parameters #9701

Open
mklement0 opened this issue May 22, 2019 · 6 comments

Comments

Projects
None yet
5 participants
@mklement0
Copy link
Contributor

commented May 22, 2019

Summary of the new feature/enhancement

#9684 shows that while you can declare optional parameters, they are in effect mandatory, and the default value is ignored.

Reporting an error when an attempt is made to declare an optional parameter is one solution, but a better option is to enable proper support for optional method parameters, so that the following would work:

# Wishful thinking
PS> class Foo { [string] Bar($Baz = 'Bam') { return $Baz } }; [Foo]::new().Bar()
Bam
@iSazonov

This comment has been minimized.

Copy link
Collaborator

commented May 23, 2019

We need reference this in #6652 /cc @rjmholt

@rjmholt

This comment has been minimized.

Copy link
Member

commented May 23, 2019

I think this is essentially #7534.

@vexx32

This comment has been minimized.

Copy link
Contributor

commented May 23, 2019

@rjmholt it might be related, but that looks to be pretty different; for one, it affects c# classes added with Add-Type, not PS classes, and the error is different (it actually recognises that there was another argument that should be set by default, buy the looks of it).

@SeeminglyScience

This comment has been minimized.

Copy link
Contributor

commented May 23, 2019

Yeah TypeDefiner just ignores the assignment in class method parameters. This does bring up an interesting question though.

Method parameter defaults have to be written into metadata, therefore they must be constants. How will PowerShell handle that?

  1. Require parameter defaults to be constants, just like C# does
  2. Allow expressions, set the metadata default value to null or default, and add the expression as the first line in the method body. Problem is I can't think of a way for the expression to tell if the parameter was not specified, or if a null or default value was passed specifically. This seems impossible.
@rjmholt

This comment has been minimized.

Copy link
Member

commented May 23, 2019

@vexx32 I'm imagining there are two problems:

  • .NET methods with optional parameters don't have those parameters honoured. It doesn't matter whether it's a C# or a PS class, at execution time it's all .NET
  • The PS parser does not reject assignment in method parameter specifications, creating the expectation that optional parameters will work (probably because it was planned at some stage). We'd need store the RHS in the AST and hook it into the type generator.

I'd expect the fix for #7534 to make the first part work.

If we just went with ordinary .NET constant expressions, it wouldn't be too difficult to make the second part work either.

But I think it would be worth trying to make arbitrary expressions work:

  • Allow the RHS to be any expression, which is an implicit lambda like for function parameters
  • Given an argument of type [T], the lambda is compiled as a [Func[T]], wrapping an implicit scriptblock around the expression (since classes are decidedly type-checking)
  • When the parameter is supplied on method call, the lambda is not called
  • When the parameter is not supplied, the lambda is called (and the script block is dot-sourced into the class method body)
  • This could done by adding statements into the top of the class body, like:
    if (!paramN.HasValue && paramN.DefaultLambda != null)
    {
        $paramN = paramN.DefaultLambda()
    }
    
@SeeminglyScience

This comment has been minimized.

Copy link
Contributor

commented May 23, 2019

This could done by adding statements into the top of the class body, like:

@rjmholt How will you know if the parameter was or wasn't specified though? If the caller is from PowerShell then that could work, but if the caller isn't then it'll look like null or default was specified.

Edit: That actually might not be that big of a deal. I was thinking about implementing interfaces and subclassing types from a CLR lib. Now that I think about though, none of those can specify a default parameter value as a constraint, and even if they did the caller would still need to actually reference the PowerShell class to get the default value from it. Considering that's incredibly unlikely (or impossible?) from rosyln this probably isn't a concern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.