Is it possible get a variable name?

 

function SortList($list, $order){
    $tempList=New-Object Collections.Generic.List[string]
    for($i=0;$i -lt $order.count;$i++){
        $tempList.Add($list[$order[$i]])
    }
    $list=$tempList
}

This function sort a list of things based in other order. What i want to achieve is modify a global variable passed as $list.

I can't write '$global:list = $tempList' because that is going to create the variable "list" as global, and the line that i use instead create an internal $list that is lost when the function end, i.e. the global $list remains equal.

I don't know how can I modify that var if I don't know his name.  The function its supposed to be used with differents globals lists.

December 10th, 2011 8:43pm

function SortList($order){
    $tempList=New-Object Collections.Generic.List[string]
    for($i=0;$i -lt $order.count;$i++){
        $tempList.Add($global:list[$order[$i]])
    }
    $global:list=$tempList
}
New-Variable -Scope global -Name list
$global:list = (1,2,3)
SortList (2,1,0)
$global:list
#Remove-Variable -Name list

Notice I have left out the local parameter $list, and am using purely the global variable.
Free Windows Admin Tool Kit Click here and download it now
December 10th, 2011 9:17pm

As I say, I want to work with different lists not with only one.

function SortList($list, $order){
    if($list.count -ne $order.count){"The order has to have the same length: $($list.count)"; return}
    $tempList=New-Object Collections.Generic.List[string]
    for($i=0;$i -lt $order.count;$i++){
        $tempList.Add($list[$order[$i]])
    }
    for($i=0;$i -lt $order.count;$i++){
        $List[$i] = $tempList[$i]
    }
}

I found that this would work but I don't like it, i have to assign all the element.

December 11th, 2011 12:25am

I don't believe it is possible (nor would it be desirable) for a function to be able to determine the name of the variable making up one of the arguments it was passed. What would your script do if it found out that the argument was not actually a global variable, but a script level variable, a literal constant, the content of a file courtesy of get-childitem, or an element from a hash table?

I don't see that your function is returning any value to the calling program (other than an error message in some cases). Why not return the value you want to pass back to one of the arguments as the return value? Something like this:

    function SortList($list, $order){
        $tempList=New-Object Collections.Generic.List[string]
        for($i=0;$i -lt $order.count;$i++){
            $tempList.Add($list[$order[$i]])
        }
        $tempList
    }

Then call it like this:

    $mylist = sortlist $mylist $order

 

Free Windows Admin Tool Kit Click here and download it now
December 11th, 2011 2:04am

Or, l alternately, use the temporary variable differently:

    function SortList($list, $order){
        if($list.count -ne $order.count){"The order has to have the same length: $($list.count)"; return}
        $tempList=$list
        $list=New-Object Collections.Generic.List[string]
        for($i=0;$i -lt $order.count;$i++){
            $List.Add($templist[$order[$i]])
        }
    }

 

December 11th, 2011 2:11am

Exactly because of that

$mylist = sortlist $mylist $order 

is longer than

sortlist $mylist $order

I just ask this question because I was having the hope that maybe some kind of oscure and undocumented reflection mecanism exist to retrieve at any given time the name of a variable. If it don't exist well I move on and use the second script that I show (that I don't like because of the 2n execution time)

 

Free Windows Admin Tool Kit Click here and download it now
December 11th, 2011 2:21am

granted calling the function in the manner I suggested uses a few more chanracters. But the number of additional characters you'd need to add to the function to determine the name of the variable, if such a thing were possible would probably be greater. In addition, the complexity of this additional code would be much greater as well. In any case, relying on "obscure, undocumented" features seems more work than it is worth.

As to your 2n issue, I believe that neither of my suggested examples would exceed 1n.

 

December 11th, 2011 3:14am

One way would be to pass the argument as a scriptblock. The literal name of the varible will be available as the string value of the script block. The value of the variable will be available as the result of the invocation of the script block:

 

function test ($list){
"variable name of argument pass was $list"
"value of argument pass was $(&$list)"
}

$global:list1 = 1,2,3

test {$list1}

variable name of argument pass was $list1
value of argument pass was 1 2 3

Free Windows Admin Tool Kit Click here and download it now
December 11th, 2011 4:10am

Another option is to use the $$ automatic variable.  For this to work, you'd need to modify your function so that the global variable is the last argument passed:

function test ($order,$list){
"variable name passed was $$"
}

$global:global_list = "abc"

test 123 $global_list

variable name passed was global_list

December 11th, 2011 4:32am

My PowerShell V2 seems to have a bug in it that makes that technique not work:   C:> test 123 $global_list variable name passed was global_list C:> test 123 $global_list variable name passed was global_list C:> test 123 $global_list variable name passed was global_list C:> test $global_list 123 variable name passed was global_list C:> test 456 789 variable name passed was 123  
Free Windows Admin Tool Kit Click here and download it now
December 11th, 2011 5:16am

Hmm.  Same here.  Seems like it should work, but it seems buggy.
December 11th, 2011 5:32am

One way would be to pass the argument as a scriptblock. The literal name of the varible will be available as the string value of the script block. The value of the variable will be available as the result of the invocation of the script block:

 

 

function test ($list){
"variable name of argument pass was $list"
"value of argument pass was $(&$list)"
}

$global:list1 = 1,2,3

test {$list1}

variable name of argument pass was $list1
value of argument pass was 1 2 3

Free Windows Admin Tool Kit Click here and download it now
December 11th, 2011 5:36am

The $$ seemed to work in limited test, but you're right, it's not a viable option. 

The scriptblock seems to be a good option. 

FWIW, here's another example of leveraging a scriptblock to expose code as literal text:

http://mjolinor.wordpress.com/2011/10/08/new-object-from-a-hash-table-in-a-script-block/

December 11th, 2011 5:42am

Leteo X....I don't remember well his name and why it delete his own post :S, but well, it shows how $MyInvocation automatic variable could be used. The function using this variable:
function SortListX($list, $order){
    if($list.count -ne $order.count){"The order has to have the same length: $($list.count)"; return}
    $tempList=New-Object Collections.Generic.List[string]
    for($i=0;$i -lt $order.count;$i++){
        $tempList.Add($list[$order[$i]])
    }
    
    $name = ($MyInvocation.Line -split "\s+" | select -Index 1).remove(0,1)
    
    Set-Variable $name -Value $tempList -Scope Global -Force
}

The invocation is clean, for example: "SortListX $MyGlobalList (2,1,0)" and the execution time match the solution of passing scriptblock as Mjollnor says. To the guy that mention the use of $MyInvocation: thanks and don't delete your useful post! I check the used time with this: 1..10|% {$tot=New-TimeSpan} {$tot+=Measure-Command {SortList2N $WorkList (2,1,0)}} $tot 1..10|% {$tot=New-TimeSpan} {$tot+=Measure-Command {SortListSB {$WorkList} (2,1,0)}}
$tot 1..10|% {$tot=New-TimeSpan} {$tot+=Measure-Command {SortListMI $WorkList (2,1,0)}} $tot Still the 2N solution runs faster but I'm going to accept the rests as proper answers because they provide alternative ways to get the variable argument name.




Free Windows Admin Tool Kit Click here and download it now
December 11th, 2011 6:58am

Is it just me, or does it seem to anyone else that all this convoluted extra work (and an apparently buggy feature) makes the complexity of replacing this statement:

    sortlist $mylist $order

with this one that Voodoomsr said was too long:

    $mylist = sortlist $mylist $order

a bit less of an issue?

Is there a universe somewhere in which the use of "some kind of oscure and undocumented reflection mecanism" is considered better programming practice than simplicity, to say nothing of the use of global variables where they are not needed?

 

December 14th, 2011 9:12am

Is it just me, or does it seem to anyone else that all this convoluted extra work (and an apparently buggy feature) makes the complexity of replacing this statement:

    sortlist $mylist $order

with this one that Voodoomsr said was too long:

    $mylist = sortlist $mylist $order

a bit less of an issue?

Is there a universe somewhere in which the use of "some kind of oscure and undocumented reflection mecanism" is considered better programming practice than simplicity, to say nothing of the use of global variables where they are not needed?

 


My sentiments exactly.  There is IMO sometimes a certain feeling of superiority that comes with creating a piece of obfusticated code that works, but is virtually impossible to understand.

This is in contrast to my own view, which is that code should be as simple and clear as possible.  This is just a basic Best Practice, for reasons of extensibility and maintainability (esp. for others who didn't write the code in the first place).

As for global variables, I never use them.  I was trained in classical Pascal, and keeping variables as local as possible is another Best Practice.  If you are using global variables, it's likely you are writing spagetti code, not structured code.  Once again, not good for maintainability.  (My teacher didn't even allow program-scope variables - everything had to be passed by reference if that's what you needed to do.)

 

Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 9:38am

I love obscure undocumented methods! :D   but, only for working in the console, which I do more than I write scripts...   scripts however, whats an extra kb or two? is typing it out slowing the loading of the script? no... is it slowing down the processing of the script? very unlikely...    
December 14th, 2011 4:39pm

This is admittedly probably a bad application of the principle, but it does serve as a platform to explore the different mechanisms available to expose both the literal name of a variable (or any other component of the code) and it's evaluated value.  This can be more useful in some applications than the one presented for consideration in this thread.
Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 4:45pm

This is admittedly probably a bad application of the principle, but it does serve as a platform to explore the different mechanisms available to expose both the literal name of a variable (or any other component of the code) and it's evaluated value.  This can be more useful in some applications than the one presented for consideration in th
December 14th, 2011 5:01pm

Dealing with script code as both code and data.

Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 5:05pm

About "Best practices":

Teddy, personally I think that doing everything based only in "Best practices" is not really the "Best". If we don't experiment and break that autoimposed box the space to explore and find new ways of doing things is going to be seriously shrunken. In the process of finding and uncovering those dark things they stop being like that and instead the become familiar to anyone.

About the importance of the call lenght:

The length of how we call and access a functionality, for me at least, is very important, I see it from the point of view of the user that want  'a function to sort a any global list based in a given order'. In this case the user don't need to know how it works, he only need to be sure that the function do what  supposedly do.

Back on the proposed "solutions":

Mjolinor the scriptblock parameter is a nice way to get that variable name, I'm going to mark it as the answer.  The use of $MyInvocation.Line is also very useful, but it needs a little more parsing. The final call that the user must do is consice in both cases:

sortlist {$AnyGlobalList} $OrderArray    # scriptblock parameter

sortlist $AnyGlobalList $OrderArray        # $MyInvocation

December 14th, 2011 6:27pm

Best Practices are best, the reason they are there is because someone who created that black box (more on your second point in a bit) has said 'this is the best way to use my black box' that being said, im not saying you shouldnt try new things, but you shouldnt deploy new things. do you want to buy software thats full of shortcuts? no, I want to know that they created clean and structured code, so there are less patches and updates I need to worry about...   you are right, the end user doesnt care about the actual inner workings, but when you leave your job and someone has to come in and they are asked to modify your script, well, if its all cryptic they'll likely just toss it out and start over wasting more time...   you state that a small amount of code is important to you, but not why....   I like short code too provided its efficient... there is no point in making it short if it doesnt increase the over all resource usage... which, in your case, a couple more letters isnt going to impact much...   also in your case you are limiting the user, you are FORCING them to update the list they provided, perhaps they want a new list that is sorted but wants to keep the current order as well? now they have to do extra work,   $oldlist = $AnGlobalList sortlist $AnyGlobalList $OrderArray   you arent really giving a strong case for hacking away at things...    
Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 6:40pm

JRich you are assuming a great amount of stuff.

The requisite is: 'a function to sort a any global list based in a given order', The behaviour must be like [array]::Reverse, i.e. it must modify the argument and don't return anything.  This is fixed. If we analize the infinite ways that the user could want to do this were going to discuss for an equal infinite time, that is not a good thing. 

You say that I should not "deploy new things", I could not be more in disagrement with that statement but arguing about it is completelly out of topic.

You are asumming cryptic code everywhere, deployments, installations, etc, etc. I say where is the cryptic code, are we in the topic about that extreme little function, when the real problematic was "modify any global variable passed as argument"?

 

 

December 14th, 2011 7:16pm

true, let me toss another option at you  function test{ param($name)    $temp = (Get-Variable -Scope global -Name $name).value    write-host "Variable to be modified: $name"    write-host "Current Value: $temp"    Set-Variable -Scope global -Name $name -Value "CHANGED!"    $temp = (Get-Variable -Scope global -Name $name).value    write-host "New Value: $temp" }   $global:myvar = "TESTING!" test myvar    
Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 7:34pm

Justin, what point are you trying to make with that code sample?
December 14th, 2011 7:51pm

rather than pass the variable and try to get its name, just pass the name of the variable and then pull that variable in...  
Free Windows Admin Tool Kit Click here and download it now
December 14th, 2011 8:10pm

you sir...are a genius! greatest signature ever

August 21st, 2013 3:53pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics