Windows Vista Forums

Functions as parameters

  1. #1


    klumsy@xtra.co.nz Guest

    Functions as parameters

    how can you pass a function to a function..

    i.e here i define a function, it takes whatever is in the pipeline, and
    calls a function that is passed through as a script block to it

    function taker ([scriptblock] $test) { process{ &$test $_} }

    and i can call it like this

    1.. 10 | taker {param([int]$inn) $inn * 3}

    this things i don't like that this is the [scriptblock] is not typed,
    unlike say a C# delegate. and also i haven't mangaged the syntax to
    actually pass in a real function

    like



    function myfunct([string] $astring ) { "this is a $astring " }

    1..10 | taker myfunct
    1..10 | taker {myfunct}

    etc all fail.. i'm sure with this last part its just a syntax error
    somewhere

    however the other problem is defining a parameter that doesn't just
    take any old scriptblock but a scriptblock that is a function of a
    particular signature


      My System SpecsSystem Spec

  2. #2


    dreeschkind Guest

    RE: Functions as parameters

    Well, as I tried to point out on IRC, I think these are basically the only
    ways to do that:

    function myfunct([string] $astring ) { "this is a $astring " }

    # parameter of type ScriptBlock
    function taker ([scriptblock] $test) { process{ &$test $_} }
    1..10 | taker $(invoke-expression ('{' + (gi function:myfunct).definition +
    '}'))

    # parameter of type FunctionInfo
    function taker ([System.Management.Automation.FunctionInfo]$test) { process{
    &$test $_} }
    1..10 | taker (gi function:myfunct)

    --
    greetings
    dreeschkind

    "klumsy@xtra.co.nz" wrote:

    > how can you pass a function to a function..
    >
    > i.e here i define a function, it takes whatever is in the pipeline, and
    > calls a function that is passed through as a script block to it
    >
    > function taker ([scriptblock] $test) { process{ &$test $_} }
    >
    > and i can call it like this
    >
    > 1.. 10 | taker {param([int]$inn) $inn * 3}
    >
    > this things i don't like that this is the [scriptblock] is not typed,
    > unlike say a C# delegate. and also i haven't mangaged the syntax to
    > actually pass in a real function
    >
    > like
    >
    > function myfunct([string] $astring ) { "this is a $astring " }
    >
    > 1..10 | taker myfunct
    > 1..10 | taker {myfunct}
    >
    > etc all fail.. i'm sure with this last part its just a syntax error
    > somewhere
    >
    > however the other problem is defining a parameter that doesn't just
    > take any old scriptblock but a scriptblock that is a function of a
    > particular signature
    >
    >


      My System SpecsSystem Spec

  3. #3


    klumsy@xtra.co.nz Guest

    Re: Functions as parameters

    thats for the work around, thats one thing i love about powershell,
    when it can't do something, youi can ussually do an interact hack to
    make it work..

    however there should be a better way. I thought that powershell treated
    functions and full citizens, but it seems a scriptblock and a function
    are a little different.

    the thing that i am more interested in those is taking a [scriptblock]
    as a parameter. i like how in a function with the param( ) statement
    you can define a strongly typed interface for your scriptblock or
    function.. rather than just having to do $args[0] , $args[1] etc.. in a
    dynamic language the ability to have it strongly typed, or not typed at
    all is great..when taking a scriptblock as an argument you should also
    be able to have it strongly typed.. being able to say this argument is
    not just any old scriptblock but a scriptblock that takes 2 arguments
    the first being an int the second a string.. just as you can with C#
    delegates

    is there any way to do this?


      My System SpecsSystem Spec

  4. #4


    Roman Kuzmin Guest

    Re: Functions as parameters

    Do I miss something? Why to use $args[0], $args[1] only? Script block can use
    param(), at least this simple example works fine:

    $x = {
    param([int]$int, [string]$string)
    "$int and $string"
    }

    & $x 123 xxx

    --
    Thanks,
    Roman


      My System SpecsSystem Spec

  5. #5


    Bruce Payette [MSFT] Guest

    Re: Functions as parameters

    Functions are just scripblocks that are stored in the function provider.
    Let's take a look at this. We'll define a function

    PS (1) > function hi { "Hi" }
    PS (2) > hi
    Hi

    Now let's use the call operator on the function:

    PS (3) > & $function:hi
    Hi

    Why does this work? Let's take a look at the type of the bject returned from
    the function provider:

    PS (4) > $function:hi.gettype().Fullname
    System.Management.Automation.ScriptBlock

    So - anywhere you can take a scriptblock, you can pass a function by doing
    $function:name

    PS (5) > function foo {$_ -gt 3}
    PS (6) > 1..5 | where $function:foo
    4
    5

    Now dreeschkind's post also brings up the use of CommandInfo objects to do
    indirect invocation of commands. This is also an interesting technique. The
    & (call) operator can take the name of a command, a scriptblock or a command
    info object. Internally that's how this works anyway - when you pass a
    string to &, it just calls get-command to get the command info object of the
    command to execute. This works with functions:

    PS (7) > $ci = get-command hi
    PS (8) > $ci.gettype().Fullname
    System.Management.Automation.FunctionInfo
    PS (9) > & $ci
    Hi

    And cmdlets:

    PS (10) > $ci = get-command get-date
    PS (11) > $ci.GetType().Fullname
    System.Management.Automation.CmdletInfo
    PS (12) > & $ci

    Sunday, October 22, 2006 11:17:39 AM

    It even works with script or external commands:

    PS (13) > $ci = get-command cmd.exe
    PS (14) > $ci.GetType().FullName
    System.Management.Automation.ApplicationInfo
    PS (15) > &$ci /c echo hi
    hi

    The interesting thing here is that the command info object is an absolute
    reference to a particular command. So - if you want to make sure you're
    always calling a particular command and bypass command lookup, this let's
    you do it.

    BTW - all of ths material (and more) is covered in chapter 8 of my book.

    -bruce

    --
    Bruce Payette [MSFT]
    Windows PowerShell Technical Lead
    Microsoft Corporation
    This posting is provided "AS IS" with no warranties, and confers no rights.

    Visit the Windows PowerShell Team blog at:
    http://blogs.msdn.com/PowerShell
    Visit the Windows PowerShell ScriptCenter at:
    http://www.microsoft.com/technet/scr.../hubs/msh.mspx
    My Book: http://manning.com/powershell

    "dreeschkind" <dreeschkind@discussions.microsoft.com> wrote in message
    news1708A5B-FBCB-4942-9FEC-10BFDCDA4CF8@microsoft.com...
    > Well, as I tried to point out on IRC, I think these are basically the only
    > ways to do that:
    >
    > function myfunct([string] $astring ) { "this is a $astring " }
    >
    > # parameter of type ScriptBlock
    > function taker ([scriptblock] $test) { process{ &$test $_} }
    > 1..10 | taker $(invoke-expression ('{' + (gi function:myfunct).definition
    > +
    > '}'))
    >
    > # parameter of type FunctionInfo
    > function taker ([System.Management.Automation.FunctionInfo]$test) {
    > process{
    > &$test $_} }
    > 1..10 | taker (gi function:myfunct)
    >
    > --
    > greetings
    > dreeschkind
    >
    > "klumsy@xtra.co.nz" wrote:
    >
    >> how can you pass a function to a function..
    >>
    >> i.e here i define a function, it takes whatever is in the pipeline, and
    >> calls a function that is passed through as a script block to it
    >>
    >> function taker ([scriptblock] $test) { process{ &$test $_} }
    >>
    >> and i can call it like this
    >>
    >> 1.. 10 | taker {param([int]$inn) $inn * 3}
    >>
    >> this things i don't like that this is the [scriptblock] is not typed,
    >> unlike say a C# delegate. and also i haven't mangaged the syntax to
    >> actually pass in a real function
    >>
    >> like
    >>
    >> function myfunct([string] $astring ) { "this is a $astring " }
    >>
    >> 1..10 | taker myfunct
    >> 1..10 | taker {myfunct}
    >>
    >> etc all fail.. i'm sure with this last part its just a syntax error
    >> somewhere
    >>
    >> however the other problem is defining a parameter that doesn't just
    >> take any old scriptblock but a scriptblock that is a function of a
    >> particular signature
    >>
    >>




      My System SpecsSystem Spec

  6. #6


    klumsy@xtra.co.nz Guest

    Re: Functions as parameters

    thankyou bruce

    using $function:hi

    is exactly what i needed to know for my first question.

    as for the 2nd.. when you are accepting an argument/parameter as a
    [scriptblock] is there anyway to strongly type the reciever (the same
    as you can in a function, or even when you declare a scriptblock..

    so my


    function taker ( [scriptblock] $thesb )

    so that i can say that scriptblock has to be 2 params, and int and a
    string (like the definition param([int]$theint,[string]$thestring)

    akin to C# delegates

    you can define a delegate

    public delegate string mydel(int theint, string thestring)

    then you could have a function/method that accepts a ponter to a
    function (delegate) that is stringly typed i.e

    public void taker (mydel del)
    {
    };

    -Karl


      My System SpecsSystem Spec

  7. #7


    Alex K. Angelopoulos [MVP] Guest

    Re: Functions as parameters


    "Bruce Payette [MSFT]" <brucepay@microsoft.com> wrote in message
    news:uS9H9sg9GHA.4196@TK2MSFTNGP03.phx.gbl...

    > It even works with script or external commands:
    >
    > PS (13) > $ci = get-command cmd.exe
    > PS (14) > $ci.GetType().FullName
    > System.Management.Automation.ApplicationInfo
    > PS (15) > &$ci /c echo hi
    > hi
    >
    > The interesting thing here is that the command info object is an absolute
    > reference to a particular command. So - if you want to make sure you're
    > always calling a particular command and bypass command lookup, this let's
    > you do it.
    >
    > BTW - all of ths material (and more) is covered in chapter 8 of my book.


    The simplest technique for bypassing lookup and which may not have been
    mentioned yet is to use the snapin-qualified name. For example:

    Microsoft.PowerShell.Core\Get-Command

    This has nothing to do with parameter indirection, of course.



      My System SpecsSystem Spec

  8. #8


    Bruce Payette [MSFT] Guest

    Re: Functions as parameters

    You can declare parameters to a scriptblock using the param statement just
    like in a script

    PS (1) > $sb = {param($a,$b) $a + $b}

    This works fine when you invoke the scriptblock with &

    PS (2) > & $sb 2 3
    5

    but it doesn't work properly when you use the Invoke():

    PS (5) > $sb.invoke(2,3)
    PS (6) >

    This is a particularly unfortunate bug which affects both functions and
    scriptblocks. The Invoke() mechansim bypasses the parameter binder and just
    sets $args. Since functions are just scriptblocks stored in the function
    provider, the bug affects them as well:

    PS (6) > function add($a,$y) {$x + $y}
    PS (7) > add 1 2
    2
    PS (8) > $function:add.invoke(1,2)

    If you just use $args then everything works...

    PS (9) > function add {$args[0] + $args[1]}
    PS (10) > add 3 4
    7
    PS (11) > $function:add.invoke(3,4)
    7


    We're working on getting this fixed...

    -bruce

    --
    Bruce Payette [MSFT]
    Windows PowerShell Technical Lead
    Microsoft Corporation
    This posting is provided "AS IS" with no warranties, and confers no rights.

    Visit the Windows PowerShell Team blog at:
    http://blogs.msdn.com/PowerShell
    Visit the Windows PowerShell ScriptCenter at:
    http://www.microsoft.com/technet/scr.../hubs/msh.mspx
    My Book: http://manning.com/powershell
    <klumsy@xtra.co.nz> wrote in message
    news:1161544402.246339.33450@k70g2000cwa.googlegroups.com...
    > thankyou bruce
    >
    > using $function:hi
    >
    > is exactly what i needed to know for my first question.
    >
    > as for the 2nd.. when you are accepting an argument/parameter as a
    > [scriptblock] is there anyway to strongly type the reciever (the same
    > as you can in a function, or even when you declare a scriptblock..
    >
    > so my
    >
    >
    > function taker ( [scriptblock] $thesb )
    >
    > so that i can say that scriptblock has to be 2 params, and int and a
    > string (like the definition param([int]$theint,[string]$thestring)
    >
    > akin to C# delegates
    >
    > you can define a delegate
    >
    > public delegate string mydel(int theint, string thestring)
    >
    > then you could have a function/method that accepts a ponter to a
    > function (delegate) that is stringly typed i.e
    >
    > public void taker (mydel del)
    > {
    > };
    >
    > -Karl
    >




      My System SpecsSystem Spec

  9. #9


    klumsy@xtra.co.nz Guest

    Re: Functions as parameters


    Bruce Payette [MSFT] wrote:
    > You can declare parameters to a scriptblock using the param statement just
    > like in a script
    >
    > PS (1) > $sb = {param($a,$b) $a + $b}
    >
    > This works fine when you invoke the scriptblock with &
    >
    > PS (2) > & $sb 2 3
    > 5
    >
    > but it doesn't work properly when you use the Invoke():
    >
    > PS (5) > $sb.invoke(2,3)
    > PS (6) >
    >
    > This is a particularly unfortunate bug which affects both functions and
    > scriptblocks. The Invoke() mechansim bypasses the parameter binder and just
    > sets $args. Since functions are just scriptblocks stored in the function
    > provider, the bug affects them as well:
    >
    > PS (6) > function add($a,$y) {$x + $y}
    > PS (7) > add 1 2
    > 2
    > PS (8) > $function:add.invoke(1,2)
    >
    > If you just use $args then everything works...
    >
    > PS (9) > function add {$args[0] + $args[1]}
    > PS (10) > add 3 4
    > 7
    > PS (11) > $function:add.invoke(3,4)
    > 7
    >
    >
    > We're working on getting this fixed...
    >
    > -bruce
    >
    > --
    > Bruce Payette [MSFT]
    > Windows PowerShell Technical Lead
    > Microsoft Corporation
    > This posting is provided "AS IS" with no warranties, and confers no rights.
    >
    > Visit the Windows PowerShell Team blog at:
    > http://blogs.msdn.com/PowerShell
    > Visit the Windows PowerShell ScriptCenter at:
    > http://www.microsoft.com/technet/scr.../hubs/msh.mspx
    > My Book: http://manning.com/powershell
    > <klumsy@xtra.co.nz> wrote in message
    > news:1161544402.246339.33450@k70g2000cwa.googlegroups.com...
    > > thankyou bruce
    > >
    > > using $function:hi
    > >
    > > is exactly what i needed to know for my first question.
    > >
    > > as for the 2nd.. when you are accepting an argument/parameter as a
    > > [scriptblock] is there anyway to strongly type the reciever (the same
    > > as you can in a function, or even when you declare a scriptblock..
    > >
    > > so my
    > >
    > >
    > > function taker ( [scriptblock] $thesb )
    > >
    > > so that i can say that scriptblock has to be 2 params, and int and a
    > > string (like the definition param([int]$theint,[string]$thestring)
    > >
    > > akin to C# delegates
    > >
    > > you can define a delegate
    > >
    > > public delegate string mydel(int theint, string thestring)
    > >
    > > then you could have a function/method that accepts a ponter to a
    > > function (delegate) that is stringly typed i.e
    > >
    > > public void taker (mydel del)
    > > {
    > > };
    > >
    > > -Karl
    > >



      My System SpecsSystem Spec

Functions as parameters

Similar Threads
Thread Thread Starter Forum Replies Last Post
Test for parameters in functions IT Staff PowerShell 1 02 Nov 2009
Q: Functions or Scripts that take parameters? Kevin Buchan PowerShell 4 18 Jun 2008
Call function with parameters that also call functions (.Net and P bsdz PowerShell 2 10 Jun 2008
Invoking PowerShell functions with parameters from .NET: issues. Roman Kuzmin PowerShell 0 23 Apr 2007
Functions and ScriptBlock parameters? Alex K. Angelopoulos [MVP] PowerShell 3 08 Jul 2006