Accessing the last element in Perl6 - raku

Could someone explain why this accesses the last element in Perl 6
#array[*-1]
and why we need the asterisk *?
Isn't it more logical to do something like this:
#array[-1]

The user documentation explains that *-1 is just a code object, which could also be written as
-> $n { $n - 1 }
When passed to [ ], it will be invoked with the array size as argument to compute the index.
So instead of just being able to start counting backwards from the end of the array, you could use it to eg count forwards from its center via
#array[* div 2] #=> middlemost element
#array[* div 2 + 1] #=> next element after the middlemost one
According to the design documents, the reason for outlawing negative indices (which could have been accepted even with the above generalization in place) is this:
The Perl 6 semantics avoids indexing discontinuities (a source of subtle runtime errors), and provides ordinal access in both directions at both ends of the array.

If you don't like the whatever-star, you can also do:
my $last-elem = #array.tail;
or even
my ($second-last, $last) = #array.tail(2);
Edit: Of course, there's also a head method:
my ($first, $second) = #array.head(2);

The other two answers are excellent. My only reason for answering was to add a little more explanation about the Whatever Star * array indexing syntax.
The equivalent of Perl 6's #array[*-1] syntax in Perl 5 would be $array[ scalar #array - 1]. In Perl 5, in scalar context an array returns the number of items it contains, so scalar #array gives you the length of the array. Subtracting one from this gives you the last index of the array.
Since in Perl 6 indices can be restricted to never be negative, if they are negative then they are definitely out of range. But in Perl 5, a negative index may or may not be "out of range". If it is out of range, then it only gives you an undefined value which isn't easy to distinguish from simply having an undefined value in an element.
For example, the Perl 5 code:
use v5.10;
use strict;
use warnings;
my #array = ('a', undef, 'c');
say $array[-1]; # 'c'
say $array[-2]; # undefined
say $array[-3]; # 'a'
say $array[-4]; # out of range
say "======= FINISHED =======";
results in two nearly identical warnings, but still finishes running:
c
Use of uninitialized value $array[-2] in say at array.pl line 7.
a
Use of uninitialized value in say at array.pl line 9.
======= FINISHED =======
But the Perl 6 code
use v6;
my #array = 'a', Any, 'c';
put #array[*-1]; # evaluated as #array[2] or 'c'
put #array[*-2]; # evaluated as #array[1] or Any (i.e. undefined)
put #array[*-3]; # evaluated as #array[0] or 'a'
put #array[*-4]; # evaluated as #array[-1], which is a syntax error
put "======= FINISHED =======";
will likewise warn about the undefined value being used, but it fails upon the use of an index that comes out less than 0:
c
Use of uninitialized value #array of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
in block <unit> at array.p6 line 5
a
Effective index out of range. Is: -1, should be in 0..Inf
in block <unit> at array.p6 line 7
Actually thrown at:
in block <unit> at array.p6 line 7
Thus your Perl 6 code can more robust by not allowing negative indices, but you can still index from the end using the Whatever Star syntax.
last word of advice
If you just need the last few elements of an array, I'd recommend using the tail method mentioned in mscha's answer. #array.tail(3) is much more self-explanatory than #array[*-3 .. *-1].

Related

Converting Ordered Collection to Literal Array

I have an ordered collection that I would like to convert into a literal array. Below is the ordered collection and the desired result, respectively:
an OrderedCollection(1 2 3)
#(1 2 3)
What would be the most efficient way to achieve this?
The message asArray will create and Array from the OrderedCollection:
anOrderedCollection asArray
and this is probably what you want.
However, given that you say that you want a literal array it might happen that you are looking for the string '#(1 2 3)' instead. In that case I would use:
^String streamContents: [:stream | aCollection asArray storeOn: stream]
where aCollection is your OrderedCollection.
In case you are not yet familiar with streamContents: this could be a good opportunity to learn it. What it does in this case is equivalent to:
stream := '' writeStream.
aCollection asArray storeOn: stream.
^stream contents
in the sense that it captures the pattern:
stream := '' writeStream.
<some code here>
^stream contents
which is fairly common in Smalltalk.
UPDATE
Maybe it would help if we clarify a little bit what do we mean literal arrays in Smalltalk. Consider the following two methods
method1
^Array with: 1 with: 2 with: 3
method2
^#(1 2 3)
Both methods answer with the same array, the one with entries 1, 2 and 3. However, the two implementations are different. In method1 the array is created dynamically (i.e., at runtime). In method2 the array is created statically (i.e., at compile time). In fact when you accept (and therefore compile) method2 the array is created and saved into the method. In method1instead, there is no array and the result is created every time the method is invoked.
Therefore, you would only need to create the string '#(1 2 3)' (i.e., the literal representation of the array) if you were generating Smalltalk code dynamically.
You can not convert an existing object into a literal array. To get a literal array you'd have to write it using the literal array syntax in your source code.
However, I believe you just misunderstood what literal array means, and you are infact just looking for an array.
A literal array is just an array that (in Pharo and Squeak [1]) is created at compile time, that is, when you accept the method.
To turn an ordered collection into an array you use asArray.
Just inspect the results of
#(1 2 3).
(OrderedCollection with: 1 with: 2 with: 3) asArray.
You'll see that both are equal.
[1]: see here for an explanation: https://stackoverflow.com/a/29964346/1846474
In Pharo 5.0 (a beta release) you can do:
| oc ary |
oc := OrderedCollection new: 5.
oc addAll: #( 1 2 3 4 5).
Transcript show: oc; cr.
ary := oc asArray.
Transcript show: ary; cr.
The output on the transcript is:
an OrderedCollection(1 2 3 4 5)
#(1 2 3 4 5)
the literalArray encoding is a kind of "poor man's" persistency encoding to get a representation, which can reconstruct the object from a compilable literal array. I.e. an Array of literals, which by using decodeAsLiteralArray reconstructs the object.
It is not a general mechanism, but was mainly invented to store UI specifications in a method (see UIBuilder).
Only a small subset of classes support this kind of encoding/decoding, and I am not sure if OrderedCollection does it in any dialect.
In the one I use (ST/X), it does not, and I get a doesNotUnderstand.
However, it would be relatively easy to add the required encoder/decoder and make it possible.
But, as I said, its intended use is for UIspecs, not as a general persistency (compiled-object persistency) mechanism. So I rather not recommend using it for such.

Print Dynamic variable inside DynamicModule

Why is it that not the value of b gets printed in the following example but the symbolname? How can I force the printing of the actual dynamic value of the variable?
a = {1, 2, 3};
DynamicModule[{b},
Print[Dynamic[b]];
{Dynamic[a], Dynamic[b]}
,
Initialization :> (b = Length[a]; a = a + 2)
]
output:
b$107
Out[2]= {{3, 4, 5}, 3}
Edit (after reading your answers/comments):
Consider the more simple example, without Initialization code (to get around WReach's example):
a = {1, 2, 3};
DynamicModule[{b = Length[a]},
Print[Dynamic[b]];
{Dynamic[a], Dynamic[b]}
]
output:
During evaluation of In[4]:= b$602
Out[5]= {{1, 2, 3}, 3}
Note, that this example does what I want to if I use Module instead of DynamicModule or leave out Dynamic from the Print line. My concerns are:
Why does this second example fail to print the value of b correctly? There is no Initialization, which (according to the help) contains "an expression to evaluate when the DynamicModule is first displayed". Also according to help: "When DynamicModule is first evaluated, initial assignments for local variables are made first, and then any setting for the Initialization option is evaluated."
The help should read: "Initialization: an expression to evaluate when the result of DynamicModule is first displayed", meaning that a Print statement onscreen does not constitute the "result" of the DynamicModule. If this is correct, then (and only then) I understand why the Print statement does not mean that the Dynamic object appears correctly.
I believe this happens because the Dynamic object b has not been displayed at the time the Print statement is called, and therefore the initialization has not been made. As I recall, Dynamic functionality does not operate until it is actually, visibly displayed.
See Why won't this work? Dynamic in a Select for more information.
In response to your update, my theory is that the Dynamic statement within Print in never displayed by the FrontEnd, and therefore it is never actually initialized. That is, it remains a unique placeholder, waiting to be filled by the dynamic value of b when it is finally displayed.
One may see from the example below that the assignment RHS evaluation takes place before the body Print, at least by measure of the display order in the FrontEnd. Further, we see that Print "goes inside" Dynamic and takes the unique symbol name created by DynamicModule, and prints that. We can use ToString to cause Print to display the entire expression as it is. Likewise, if we extract the symbol name from that string, and convert it to an actual symbol, before printing, we get the expected value that has indeed already been assigned.
alarm := (Print["Initialized!"]; 3)
DynamicModule[{b = alarm},
Print # ToString # Dynamic # b;
Print # Symbol # StringTake[ToString#Dynamic#b, {9, -2}];
Print # Dynamic # b;
];
Output:
Initialized!
Dynamic[b$701]
3
b$701
The crucial behaviour is described under the More Information section of the documentation for DynamicModule:
DynamicModule first gives unique names to local variables in expr,
just like Module, then evaluates the resulting expression, and then
returns a version of this wrapped in DynamicModule.
The exact sequence of events becomes more apparent if you add a Print statement to the Initialization option, thus:
a = {1, 2, 3};
DynamicModule[{b},
Print[Dynamic[b]];
{Dynamic[a], Dynamic[b]}
,
Initialization :> (b = Length[a]; Print["init:", b]; a = a + 2)
]
resulting in three cells:
b$107
Out[7]= {{3, 4, 5}, 3}
init:3
The cell containing b$107 is the result of the Print inside the DynamicModule. Then, we get the result cell (tagged Out[7] here). Finally, we see the third cell output by Print statement in the Initialization.
If you inspect the cell expression of the Out[7] cell, you will find that the localized variable is b$$. This is different from the variable in the first cell, which is b$107. This difference is attributable to the "double scoping" described in the DynamicModule documentation. The b$107 cell contains a Dynamic box, as can be seen if we assign a value to b$107.
Update
In response to the updated question...
Returning to the original expression (without the extra Print in the Initialization), the exact sequence of events is as follows:
First, the body of the DynamicModule is evaluated after giving "unique names to local variables [...] just like Module". That is, this expression is evaluated:
Print[Dynamic[b$107]]; {Dynamic[a], Dynamic[b$107]}
The result of this expression is the list {Dynamic[a], Dynamic[b$107]}. As a side-effect, a dynamic cell containing b$107 is created but that cell is now removed from further consideration as it is not part of the result of the evaluation. Now, "a version of [{Dynamic[a], Dynamic[b$107]}] is wrapped in DynamicModule" and returned. This is evaluated and implicitly printed to produce an output cell expression like this:
Cell[BoxData[
DynamicModuleBox[{$CellContext`b$$ = 3},
RowBox[{"{",
RowBox[{
DynamicBox[ToBoxes[$CellContext`a, StandardForm],
ImageSizeCache->{57., {2., 8.}}], ",",
DynamicBox[ToBoxes[$CellContext`b$$, StandardForm],
ImageSizeCache->{7., {0., 8.}}]}], "}"}],
DynamicModuleValues:>{},
Initialization:>($CellContext`b$$ =
Length[$CellContext`a]; $CellContext`a = $CellContext`a + 2)]], "Output"]
Note particularly that b$107 is renamed to $CellContext`b$$ as a function of DynamicModule symbol localization. The Initialization expression is now evaluated as the box is displayed and visible.
The key point is that the printed cell containing b$107 is not coupled in any way to the final DynamicModule cell.

How to suppress VB's "Iteration variable shouldn't been used in lambda expression"

I'm working with LINQ in VB.NET and sometimes I get to a query like
For i = 0 To 10
Dim num = (From n In numbers Where n Mod i = 0 Select n).First()
Next
and then it comes the warning "Using the iteration variable in a lambda expression may have unexpected results. Instead, create a local variable within the loop and assign it the value of the iteration variable."
I know it's not a good practice to use the iteration variable in the lambda expression, because lambda expressions are evaluated only when needed. (This question is about that)
Now my question is, how to suppress this warning in cases where the expression is evaluated in-place, with constructions like First(), Single(), ToList(), etc. (It's only a warning, but i like my code clean.)
(Declaring a local variable and passing the iteration variable to it is an option, but I'm looking for a clean solution.)
In this particular case where the lambda is evaluated immediately, then you can safely eliminate the warning by moving the declaration of the iteration variable outside the for loop.
Dim i = 0
For i = 0 To 10
...
I do want to stress though that this only works if the lambda does not escape the for loop (true for your scenario).
Also here is a detailed link to an article I wrote on this warning (why it exists, how to avoid it, etc ...)
http://blogs.msdn.com/b/jaredpar/archive/2007/07/26/closures-in-vb-part-5-looping.aspx

What is this syntax #[] in REBOL?

In another question, I saw the following syntax:
#[unset!]
What is that? If I say type? #[unset!] in R3, it tells me unset!, but it doesn't solve the mystery of what #[] is.
So curious.
#[] is the serialized form for values. Play with MOLD versus MOLD/ALL in the console to get a feel for it.
the #[] "syntax" is actually not a syntax as such (not legal syntax, if you try it), only special cases of such constructs are "legal", like the #[unset!] syntax, #[true] syntax, #[false] syntax, #[none!] syntax, or #[datatype! unset!] syntax.
What is even more interesting, is, what the #[unset!] value actually is. It happens to be the value every "uninitialized" variable in REBOL has (not in functions, though, function local variables are initialized to #[none!]), as well as the result of such expressions like print 1, do [], (), etc.
Regarding the "function local variables ... initialized to #[none!]" I should add, that only the variables following an "unused refinement" (i.e. the one not used in the actual call) are initialized to #[none!] together with the refinement variable.
To explain the issue further, the syntactic (Data exchange dialect) difference between true and #[true] is, that the former is a word, while the latter is a value of the logic! type. Seen from the semantic (Do dialect) point of view, the difference is smaller, since the (global) word is interpreted as a variable, which happens to refer to the #[true] value.
Looks like it's the value-construction syntax for an unset instance, as opposed to the word unset!:
>> comparison: [unset! #[unset!]]
== [unset! unset!]
>> type? first comparison
== word!
>> type? second comparison
== unset!
>> second comparison
>> first comparison
== unset!
If you're in a programmatic context you could do this with to-unset, but having a literal notation lets you dodge the reduce:
>> comparison: reduce ['unset! to-unset none]
== [unset! unset!]
>> second comparison
>> first comparison
== unset!
Looks like they've reserved the #[...] syntax for more of these kinds of constructors.
Look at the example below:
trace on
>> e: none
Trace: e: (set-word)
Trace: none (word) ;<<<<<
>> e: #[none]
Trace: e: (set-word)
Trace: none (none) ;<<<<<
none is a word in the first one, but in the second one, #[none] is not a word, it is the Rebol value of the datatype none!.
Similarly for other values like true, false. The #[unset!] case is special since every undefined variable actually has this value.

Rebol simulating unlimited args any example from what is said here?

http://www.rebol.org/ml-display-thread.r?m=rmlJNWS
Graham wrote:
Can a function have a variable number of arguments?
No. But you can simulate it, by using 'any-type! function specifiers and passing unset! as arguments. Better is to use refinements.
Rebol's default dialect (the do dialect) does not support the notion of a call to a function having a variable number of arguments. If you want to break a rule as fundamental as this, then you need your own dialect. Nothing stopping you from making:
tweet [Hello World How Are You Today?]
But the idea of using word! instead of string! in this case is a little dodgy, as many common tweets aren't valid for the Rebol parser:
tweet [LOL! :)]
Neglecting that issue, note that by default you won't get any expression evaluation. So this tweet dialect would have to choose a way to show where you want an evaluation. You might use get-word elements to do variable substitution, and parentheses for more general evaluations:
>> a: 10
>> b: 20
>> tweet [When you add :a and :b you get (a + b), LOL ":)"]
"When you add 10 and 20 you get 30, LOL :)"
BTW, take-n in Rowland's example isn't returning a block. Not directly, I mean. It's perhaps better understood with parentheses, and by addressing the implicit "do" that's there on every interpretation:
do [do (take-n 4) 1 2 3 4]
take-n works with only one parameter (the "n") and then returns a function which takes n parameters. Let's call that function f, so step one of this evaluation turns into something equivalent to:
do [f 1 2 3 4]
When the second do kicks in, that function gets run...and it's returning a block. In practice, I doubt you're going to want to be counting the parameters like this.
The answer on that page is:
yes, a function can have a variable number of arguments. Do is such a function, as e.g. in:
take-n: func [n /local spec] [
spec: copy []
for i 1 n 1 [
append spec to word! append copy "a" to string! i
]
func spec reduce [:reduce append reduce [to lit-word! append copy "take" to string! n] spec]
]
do take-n 4 1 2 3 4
== [take4 1 2 3 4]