Is there an easier way to access private scoped variable? - powershell

Currently I am using the following syntax to explicitly access a private scoped variable, inside of a PowerShell function:
function MyPowershellFunction {
param($param1)
# ...
# lot of code here
# ...
# access variable x on private scope explicitly
if ($private:x) {
# do something
}
}
I am doing this so that I do not accidentally refer to a variable defined in parent scope. But the code looks ugly by having private all around. Is there a simpler way?

By making a variable private you restrict its visibility to the current scope. Since variables are looked up in the current scope first $x should give you the private variable after it was initially declared private as long as you don't leave the scope. Using the scope modifier all the time shouldn't be necessary.

Just use the Local scope modifier:
function MyPowershellFunction {
param($param1)
# access variable x on private scope explicitly
if ($local:x) {
# do something
}
}
The if statement does not see any $x defined in the parent scope.

Related

Access a variable from parent scope

In Single Module Scenario: Running Set-Var returns 10.
# m.psm1
function Set-Var {
$MyVar = 10
Get-Var
}
function Get-Var {
$MyVar
}
In Nested Modules Scenario: Running Set-Var does not return any value.
# m1.psm1
function Get-Var {
$MyVar
}
# m.psm1
Import-Module .\m1.psm1
function Set-Var {
$MyVar = 10
Get-Var
}
How do I achieve the same effect as a single module with nested modules? Using $script:MyVar also does not work. However, I would like to keep the scope of the variable local to enable concurrent executions with different values.
Your code doesn't work because local variables are not inherited by functions in nested module context.
You can do this instead:
$null = New-Module {
function Get-Var {
[CmdletBinding()] param()
$PSCmdlet.SessionState.PSVariable.Get('MyVar').Value
}
}
The New-Module command creates an in-memory module, because this code only works when the caller is in a different module or script.
Use the CmdletBinding attribute to create an advanced function. This is a prerequisite to use the automatic $PSCmdlet variable, which we need in the next step.
Use its SessionState.PSVariable member to get or set a variable from the parent (module) scope.
This answer shows an example how to set a variable in the parent (module) scope.
See also: Is there any way for a powershell module to get at its caller's scope?

How to access global variable from class method

Sorry for bothing, just a quick question. How can I access to global variable like $pid from class method? The following code results compile error.
class C {
C() {
Write-Host $pid
}
}
You need to define it as a global variable, otherwise it will look in the methods scope.
Write-Host $Global:pid

Coffeescript "#" variables

What does it mean in Coffeescript when a variable name begins with an "#" sign?
For example, I've been looking through the hubot source code and just in the first few lines I've looked at, I found
class Brain extends EventEmitter
# Represents somewhat persistent storage for the robot. Extend this.
#
# Returns a new Brain with no external storage.
constructor: (robot) ->
#data =
users: { }
_private: { }
#autoSave = true
robot.on "running", =>
#resetSaveInterval 5
I've seen it several other places, but I haven't been able to guess what it means.
The # symbol is a shorcut for this as you can see in Operators and Aliases.
As a shortcut for this.property, you can use #property.
It basically means that the “#” variables are instance variables of the class, that is, class members. Which souldn't be confused with class variables, that you can compare to static members.
Also, you can think of #variables as the this or self operators of OOP languages, but it's not the exact same thing as the old javascript this. That javascript this refer to the current scope, which causes some problems when your are trying to refer to the class scope inside a callback for example, that's why coffescript have introduced the #variables, to solve this kind of problem.
For example, consider the following code:
Brain.prototype = new EventEmitter();
function Brain(robot){
// Represents somewhat persistent storage for the robot. Extend this.
//
// Returns a new Brain with no external storage.
this.data = {
users: { },
_private: { }
};
this.autoSave = true;
var self = this;
robot.on('running', fucntion myCallback() {
// here is the problem, if you try to call `this` here
// it will refer to the `myCallback` instead of the parent
// this.resetSaveInterval(5);
// therefore you have to use the cached `self` way
// which coffeescript solved using #variables
self.resetSaveInterval(5);
});
}
Final thought, the # these days means that you are referring to the class instance (i.e., this or self). So, #data basically means this.data, so, without the #, it would refer to any visible variable data on scope.

What is a twigil in Perl6?

I'm reading this fantastic introduction to Perl6 and came across a rather interesting term:
Note the ! twigil means “this is private to the class”.
class ScoreKeeper {
has %!player-points;
}
I know what sigils are in Perl5. But what's a twigil?
Is it just a fancy way to say that there are two sigils prepending the attribute/variable name?
The design documents S02 and S99 both talk about twigils. (Emphasis mine).
Ordinary sigils indicate normally scoped variables, either lexical or
package scoped. Oddly scoped variables include a secondary sigil (a
twigil) that indicates what kind of strange scoping the variable is
subject to: [...]
So it is a secondary sigil or rather a second sigil. Declaring $*foo will not declare $foo.
my $*foo = 1;
say $foo;
This will yield Variable '$foo' is not declared at....
It seems to be related to variable scoping:
Twigils influence the scoping of a variable...
Twigil Scope
------ ----------------------------------------------
none Based only on declarator
* Dynamic
! Attribute (class member)
? Compile-time variable
. Method (not really a variable)
< Index into match object (not really a variable)
^ Self-declared formal positional parameter
: Self-declared formal named parameter
= Pod variables
~ The sublanguage seen by the parser at this lexical spot
http://docs.raku.org/language/variables#Twigils
From the documentation on twigils:
Attributes are variables that exist per instance of a class. They may be directly accessed from within the class via !:
class Point {
has $.x;
has $.y;
method Str() {
"($!x, $!y)"
}
}
Note how the attributes are declared as $.x and $.y but are still accessed via $!x and $!y. This is because in Perl 6 all attributes are private and can be directly accessed within the class by using $!attribute-name. Perl 6 may automatically generate accessor methods for you though. For more details on objects, classes and their attributes see object orientation.
Public attributes have the . twigil, private ones the ! twigil.
class YourClass {
has $!private;
has #.public;
# and with write accessor
has $.stuff is rw;
method do_something {
if self.can('bark') {
say "Something doggy";
}
}
}

Add PowerShell function to the parent scope

I have some PowerShell helper functions in a file. I'd like to make them available to the scope of another file that I am writing, but not pollute the global scope.
Helpers.ps1
function global:Helper1
{
# this function pollutes the global scope
}
function Helper2
{
# this function is not visible to the Utility.ps1 file.
}
Utilities.ps1
&{
./Helpers.ps1
function global:Utility1
{
Helper1
}
function global:Utility2
{
Helper2
}
}
I found this question:
How do I dynamically create functions that are accessible in a parent scope? but the answers discuss adding functions to the global scope. What I really want to do is make the Helper functions from one PS1 file available to a calling PS1 file, without polluting the global scope with the helpers.
I want to avoid defining the functions as variables, which is possible with Set-Variable and the -Scope parameter. The closest I've seen (from the linked thread) is using Set-Item in the function: drive.
Any help would be appreciated!
Edit: here is the solution expanded from Mike's answer
Helpers.ps1
function Helper
{
}
Utilities.ps1
&{
function global:Utility
{
. ./Helpers.ps1
Helper1
}
}
Using the dot-source syntax to load Helpers.ps1 puts it's contents in the scope of the Utility function. Putting Helpers.ps1 outside the Utility function causes it to be in the &{...} scope but that scope ends once the functions are defined.
You can use this snippet in the Utilities.ps1 file. What we do is get all current functions then we dot source the helpers. We then make a diff of the before and after functions. From the diff we recreate the functions in the global scope.
$beforeFunctions = ls function:
. .\helpers.ps1
$afterFunctions = ls function:
$functionDiff = #(Compare-Object $beforeFunctions $afterFunctions)
foreach($diffEntry in $functionDiff){
$func = $diffEntry.InputObject
invoke-expression "function global:$($func.Name) { $($func.definition) }"
}
If you dot-source a .ps1 file in a function, the definitions that are in the ps1 file are not global, unless the function was itself dot-sourced.