What are the PowerShell “special” variables and characters - variables

This question is to help clear up some confusion I have with variables in PowerShell. I'm familiar with the concept of creating a variable and assigning it a value.. for example, in SharePoint, you would do this: $spsite = http://site
Yet, there are a lot of variables that come from PowerShell that can be used in various ways.
For example, if I set a site collection in a variable $spsite (like I did above), I can do a foreach loop on it and iterate through each web site..
foreach ($web in $spsite)
In another example, I see something like this
$a = 5
$b = 6
$c = 7
$d = $a,$b,$c
Foreach ($i in $d)
{ $i + 5}
In both cases, I have not assigned a value to $i or $web.. yet they have some kind of meaning or value. I get that $web is each website in a site collection. But how does PowerShell know this? It just does?
Can someone explain this and/or send me a link to where this is explained?
Also is there a list of all these special variables and special characters (shortcuts) in PowerShell.. for example, I believe % is the foreach-object cmdlet

$i and $web aren't special variables. They are just popular names that people reuse. The name of the current object in a foreach-loop is defined by you.
Ex:
#Creating a simple array for the demonstration
$MyArrayOfAwesomeObjects = 1,2,3
foreach ($ThisVariableIsAwesome in $MyArrayOfAwesomeObjects) {
#Here, $ThisVariableIsAwesome is the current object, and we can call methods on it.
$ThisVariableIsAwesome.GetType()
}
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
True True Int32 System.ValueType
True True Int32 System.ValueType
As for % -> Foreach-Object, that is just an alias. You can view all aliases with Get-Alias

Related

Why are arrays passed as arguments mutable but scalars are not?

Got this:
#! /usr/bin/env raku
use v6;
multi blah (#arg) { #arg = 7; }
multi blah ($arg) { $arg = '3'; }
my #array = 1, 2, 3;
blah #array;
say #array;
my $string = 'onetwothree';
blah $string;
say $string;
Get this:
[7]
Cannot assign to a readonly variable or a value
in sub blah at ./chop.raku line 5
in block <unit> at ./chop.raku line 12
I found this behavior surprising, particularly the ability to change to the array outside of the scope of the function.
Can someone please explain why I can change an array argument passed to a function but not a scalar? And is there a way to make arrays read only when passed to a function? Is there any way to make a scalar passed to a function mutable?
Can someone please explain why I can change an array argument passed to a function but not a scalar?
Arguments passed to a function are read-only (by default; more on that below) and so generally can't be changed. The reason that you can modify the Array is that Arrays are, themselves, mutable (see the Lists, sequences, and arrays page in the docs for details). This means that, even though you can't change the Array itself, you can still change the values in the Array.
And is there a way to make arrays read only when passed to a function?
The List is Raku's immutable type for positional data (sort of; it's not deeply immutable, but that's beyond the scope here). If you pass a List into a function, the function won't be able to modify the contents of that list. For example, this code throws an error:
my #l is List = (1, 2, 3);
sub f(#var) { #var[1] = 42 }
f #l;
Is there any way to make a scalar passed to a function mutable?
There are two ways, depending on what sort of mutability you want: you can use either the is rw and is copy traits. For example, you might declare a function like so:
sub f($a is copy, $b is rw) {...}
That declaration allows &f to modify both $a and $b. But for $a, &f is modifying its own local copy and won't have any effect on the value its callers see for $a. With $b, however, &f is modifying shared state and any changes it makes to $b will be visible even outside the scope of &f.

`does` versus `but` operators when mixing in a Role into an object in Raku

If I have a Role R defined as:
role R { method answer { 42 } }
What is the difference (if any) between these two lines:
my $a = 'question' does R;
my $b = 'question' but R;
They appear very similar:
say $a.answer; # OUTPUT: «42»
say $b.answer; # OUTPUT: «42»
say $a.WHAT; # OUTPUT: «(Str+{R})»
say $b.WHAT; # OUTPUT: «(Str+{R})»
Is this a case of there being More Than One Way To Do It™, and these both mean the same thing? Or is there a subtle difference that I'm missing?
note:
I understand that does is both an operator and a trait and thus can be used when for compile-time mixins (e.g., class C does R {}) whereas but is only for runtime mixins. I also understand that but can be used with an object (e.g., my $c = 'question' but False) whereas does can only be used with a Role. I'm not asking about either of those differences; my only question is about whether there's a difference when both are used at runtime with a Role. I have read the documentation section on mixing in Role, but didn't see an answer.
Put simply:
does modifies an object in place (and should be used with caution with value types, see note below)
but returns a new object.
When created off of a literal, it's probably not as evident, but when used with another object, it's pretty clear I think:
role R { method answer { 42 } }
my $question = 'question';
my $but = $question but R;
my $does = $question does R;
say $question.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R})
say $does.WHAT;  # (Str+{R})
say $question.WHERE; # 129371492039210
say $but.WHERE; # 913912490323923
say $does.WHERE; # 129371492039210 <-- same as $question's
Notice I cheated a bit and swapped the order of does and but. If I had preserved the order you had, the does would modify $question in place, applying the role, meaning that but would clone $question (with its role) and apply the role (again!):
my $does = $question does R;
my $but = $question but R;
say $does.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R}+{R})
This is because does as an operator is conceptually akin to ++ or +=, that is, designed to be used in a standalone context, for instance
my $foo = …;
given $bar {
when 'a' { $foo does A }
when 'b' { $foo does B }
when 'c' { $foo does B }
}
Using but is conceptually closer to using $foo + 1 — mostly meaningless unless assigned to or passed to something else.
A warning for does and value types
If you use does on a value type (strings, numbers mainly), there is an extremely high likelihood that you will cause unintended side effects. This is because value types (which, e.g., strings are) are supposed to be immutable and substitutable for one other. Note the following:
role Fooish { }
my $foo = 'foo';
$foo does Fooish;
say 'foo'.WHAT; # (Str+{Fooish})
This is a substitution that's happening at compile time (so it won't affect, e.g, 'foobar'.substr(0,3), that happens at runtime), but can cause some truly weird effects if you toss them in a loop:
role Fooish { }
my #a;
#a.push('foo' does Fooish) for ^10;
say #a[0].WHAT; # (Str+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish}
+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish})
Applying multiple rolls takes longer and longer the more you do it, so if you change that to ^100000, be ready to wait a while. OTOH, doing but gives you nice constant time and doesn't pollute the literal. This behavior seems, AFAICT, to be perfectly valid, but definitely something that can catch you unexpectedly.

Parametrized types in Raku, how to use run time values as parameters

I'd like to create some parametrized types for Raku; basically, I'd like to create some different classes whose main difference would be the range of values of one of its attributes; for instance, classes represent types of building, I'd like to have different classes for buildings with 3 or any other number of floors.
So this is the best I could think of:
subset Two-Tops of UInt where * <=2;
subset Three-Tops of UInt where * <=3;
role Zipi[ ::Capper ] {
has Capper $.floor;
}
class Capped-at-three does Zipi[Three-Tops] {}
my $capped = Capped-at-three.new( floor => 2 );
say $capped.raku;
This is clearly unpractical as soon as you need to take care of many different numbers of floors (not here in Granada, where they have at most 10, I think, but well... ). The problem here is basically you need to have the information for subsets at compile time, so unless you use macros (still experimental), there's no way you can use any kind of variable. So can you think of a practical way of defining this kind of curried roles for any value of the parameter?
Actually, unlike I said in my previous you can use conditions in where clauses without problem, you just need to encase them in braces:
role Zipi[$condition] {
has $.floor is rw where {$_ ~~ $condition}
method foo($x) { $!floor = $x }
}
class A does Zipi[2 < * < 5] {
method bar($x) { $.floor = $x }
}
#my $a = A.new( floor => 10); # error
my $a = A.new( floor => 4); # OK
#$a.foo(10); # error
$a.foo(3); # OK
#$a.bar(0); # error
$a.bar(4); # OK
#$a.floor = 9; # error
$a.floor = 3; # OK
That should cover all of the assignment types
I have very limited MOP chops, and the following seems ugly, but it works, and might be a step in the right direction.
What I've done:
Dynamically constructed an array of 10,000 subsets via the MOP.
Time shifted their construction to compile time via BEGIN.
Used an appropriate element from the array to parameterize the role.
my #max-floors-checkers;
BEGIN {
#max-floors-checkers = do for ^10_000 -> \floors {
Metamodel::SubsetHOW.new_type:
refinee => UInt,
refinement => { $^floors <= floors }
}
}
role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
class Capped-at-three does BuildingCategory[ #max-floors-checkers[3] ] {}
my $capped3 = Capped-at-three.new( floors => 2 );
say $capped3.raku; # Capped-at-three.new(floors => 2
my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed
I tried using anonymous where clauses, but similarly to no avail, but I tracked down the issue: the where clause is apparently being ignored by the BUILD method . I'm not sure if it's because it has direct access (via $!floor) which bypasses the where clause, or if something else weird is going on (probably the latter, I general got Nil if I tried to use the paramaterized value in a where clause).
Nonetheless, this should work nicely, including giving a helpful error message:
role Zipi[$condition] {
has $.floor;
submethod BUILD(:$floor, |c) {
die "Invalid floor number."
unless $floor ~~ $condition;
$!floor = $floor;
}
}
You can see how it'd be easy to modify if you can assume floors are always 0 .. x, or x .. y and could provide an even more helpful error message.
A nanswer covering the case a reader knows Java but not Raku.
Collection<String> coll = new LinkedList<String>();
parametrized types for Raku
The linked Java example is:
The instantiation of a generic type with actual type arguments is called a parameterized type. Example (of a parameterized type):
Collection<String> coll = new LinkedList<String>();
A reasonable Raku analog is:
my Positional[Str] \coll = Array[Str].new;
The Positional type is a parameterizable role. A role specifies an interface and/or partial implementation of a type. I believe Raku's Positional is sufficiently analogous to Java's Collection that it serves for the purposes of this nanswer.
The Array type is a parameterizable class. It specifies a data structure that adheres to the Positional role. It isn't a linked list but it will suffice for the purposes of this nanswer.

"Cannot assign to immutable value" when trying to assign to a string + role

Starting with the example in the Iterable doc page
role DNA does Iterable {
method iterator(){ self.comb.iterator }
};
my #a does DNA = 'GAATCC';
.say for #a; # OUTPUT: «G␤A␤A␤T␤C␤C␤»
I found it weird it's declared using the #, so I changed it to the natural way of declaring strings, $:
my $a does DNA = 'GAATCC';
But that fails with a somewhat bewildering "Cannot assign to an immutable value". No need to assign on the spot, so we can do:
my $a = 'GAATCC';
$a does DNA;
.say for $a;
Which just leaves mixing-in for later. But that just prints the string, without paying any attention to the Iterable mixin. Let's call it then explicitly:
.say for $a.iterator;
it does kinda the same thing as before, only it prints the value of $a.iterator, without actually calling the function:
<anon|69>.new
This looks like the same thing it's going on in this other question. Baseline question is I don't understand what role Iterable really does, and what for really does and when it is calling iterator on some object. Any idea?
I don't think this line does what you think it does:
my #a does DNA = 'GAATCC';
It is the same as:
my #a := [ 'GAATCC', ];
#a does DNA;
Basically the .comb call coerces the array into a Str, and splits that into characters.
If you instead did this:
my #a = 'GAATCC' but DNA;
Which is basically the same as
my #a := Seq.new(('GAATCC' but DNA).iterator).Array;
Note that # variables store Positional values not Iterable values.
The thing you want is
my $a = 'GAATCC' but DNA;
$a.map: &say;
If you want to be able to use for you can't use a variable with a $ sigil
my \a = 'GAATCC' but DNA;
.say for a;
You may want to add Seq list List etc methods to DNA.
role DNA does Iterable {
method iterator(){
self.comb.iterator
}
method Seq(){
Seq.new: self.iterator
}
method list(){
# self.Seq.list
List.from-iterator: self.iterator
}
}
my $a = 'GAATCC' but DNA;
.say for #$a;
Your question's title points to a bug. This answer covers the bug and also other implicit and explicit questions you asked.
Background
fails with a somewhat bewildering "Cannot assign to an immutable value".
I think that's a bug. Let's start with some code that works:
my $a = 42;
say $a; # 42
say WHAT $a; # (Int) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 42; # works fine
In the my declaraton $a gets BOUND to a new Scalar container. A Scalar container normally hides itself. If you ask WHAT type $a is, you actually get the type of the value currently ASSIGNED to the Scalar (the value it "contains"). You need VAR to access the container BOUND to $a. When you assign with = to a Scalar container you copy the assigned value into the container.
role foo {}
$a does foo; # changes the VALUE currently ASSIGNED to $a
# (NOT the VARIABLE that is BOUND to $a)
say $a; # 42 mixed in `foo` role is invisible
say WHAT $a; # (Int+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99
The does mixes the foo role into the 42. You can still assign to $a because it's still bound to a Scalar.
Note how these two uses of does have very different effects:
my $a does foo; # mixes `foo` into VARIABLE bound to $a
$a does foo; # mixes `foo` into VALUE assigned to $a
The bug
$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a; # Scalar+{foo}.new VALUE currently ASSIGNED to $a
say WHAT $a; # (Scalar+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo}) type of VARIABLE currently BOUND to $a
$a = 'uhoh'; # Cannot assign to an immutable value
The does mixes the foo role into the Scalar bound to $a. It seems that a Scalar with a mixin no longer successfully functions as a container and the assignment fails.
This currently looks to me like a bug.
my $b does foo; # BINDS mixed in VARIABLE to $b
$b = 'uhoh'; # Cannot assign to an immutable value
my $b does foo has the same result as my $b; $b.VAR does foo; so you get the same problem as above.
Other things you were confused about
my $a = 'GAATCC';
$a does DNA;
.say for $a;
just prints the string, without paying any attention to the Iterable mixin.
Because the $a VARIABLE is still bound to a Scalar (as explained in the Background section above), the VALUE that now has a DNA role mixed in is irrelevant per the decision process for uses about whether to call its argument's .iterator method.
Let's call it then explicitly ... prints the value of $a.iterator, without actually calling the function:
.say for $a.iterator;
Well it does call your DNA role's .iterator method. But that has another .iterator call at the end of the self.comb returned by your DNA role's iterator method so you're .saying that secondary .iterator.
Solutions that work today
I think Brad's answer nicely covers most of your options.
And I think your nice does DNA gist is as good as it gets with today's P6 if you want to use the $ sigil.
A solution that might one day work
In an ideal world all the sweetness in the P6 design would be fully realized in 6.c and the Rakudo compiler implementation of Perl 6. Perhaps that would include the ability to write this and get what you want:
class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;
The ... code would be about the same as what you have in your gist except that the DNA class would be a scalar container, and so the new method would instead be a STORE method or similar that would assign the passed value to a $!value attribute or some such when a value was assigned to the container using =.
But instead, you get:
is trait on $-sigil variable not yet implemented. Sorry.
So the closest you can get today to the ideal of = 'string' to change $a is to bind using := DNA.new('string') as you did in your gist.
Note that you can bind arbitrary composite containers to # and % sigil variables. So you can see how things are supposed to eventually work.

How can i use powershell embedded parameters?

$b = "a00000"
Now due to a complicated application, i want to access $a00000.ID
The application stores a return object inside a variablename (which is a string value of another)
When i try "$b" it shows the value, but $"$b".ID is an error
${$b}.ID is also an error
$'"$b"'.ID is also an error
How do i access value of $a00000.ID given that previously $b=a00000 ?
(one variable name is assigned by a previous string value)
Give this a try:
(Get-Variable $b -ValueOnly).Id