Variable declaration reset: Difference between revisions

From Rosetta Code
Content added Content deleted
(julia example)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(31 intermediate revisions by 15 users not shown)
Line 12: Line 12:
=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
In Algol 68, things that aren't explicitely initialised are notionally initialised to SKIP - an indeterminate value, so there should be no output from the program. Each iteration of the loop will get a new curr and prev, with prev initialised to SKIP. The following is equivalent to the Phix program...
In Algol 68, things that aren't explicitely initialised are notionally initialised to SKIP - an indeterminate value, so there should be no output from the program. Each iteration of the loop will get a new curr and prev, with prev initialised to SKIP. The following is equivalent to the Phix program...
<lang algol68>BEGIN
<syntaxhighlight lang="algol68">BEGIN
[]INT s = ( 1, 2, 2, 3, 4, 4, 5 );
[]INT s = ( 1, 2, 2, 3, 4, 4, 5 );
FOR i FROM LWB s TO UPB s DO
FOR i FROM LWB s TO UPB s DO
Line 21: Line 21:
prev := curr
prev := curr
OD
OD
END</lang>
END</syntaxhighlight>
...however, one of the non-standard features of Algol 68G is that uninitialised variables cause a runtime error instead of silently being set to SKIP.
...however, one of the non-standard features of Algol 68G is that uninitialised variables cause a runtime error instead of silently being set to SKIP.
{{out}} with [[ALGOL_68_Genie|Algol 68G]]:
{{out}} with [[ALGOL_68_Genie|Algol 68G]]:
Line 30: Line 30:
...whereas, with [[Rutgers_ALGOL_68|Rutgers Algol 68]]:<br>
...whereas, with [[Rutgers_ALGOL_68|Rutgers Algol 68]]:<br>
No output.
No output.
=={{header|AWK}}==
<syntaxhighlight lang="awk">
# syntax: GAWK -f VARIABLE_DECLARATION_RESET.AWK
BEGIN {
n = split("1,2,2,3,4,4,5",arr,",")
for (i=1; i<=n; i++) {
curr = arr[i]
if (i > 1 && prev == curr) {
printf("%s\n",i)
}
prev = curr
}
exit(0)
}
</syntaxhighlight>
{{out}}
<pre>
3
6
</pre>


=={{header|C}}==
=={{header|C}}==
Line 35: Line 55:


The following compiles using either C89/90 (-std=c90 -ansi -pedantic) or C99 syntax using gcc 9.4.0.
The following compiles using either C89/90 (-std=c90 -ansi -pedantic) or C99 syntax using gcc 9.4.0.
<lang c>#include <stdio.h>
<syntaxhighlight lang="c">#include <stdio.h>


int main() {
int main() {
Line 44: Line 64:
around the loop and set explicitly to zero. */
around the loop and set explicitly to zero. */
for (i = 0; i < 7; ++i) {
for (i = 0; i < 7; ++i) {
// for (int i = 0, prev; i < 7; ++i) { // as below, see note
int curr = s[i];
int curr = s[i];
int prev = 0;
int prev = 0;
Line 60: Line 81:


return 0;
return 0;
}</lang>
}</syntaxhighlight>
<small>(Note: Obviously the <code>for (int i=0, prev</code> needs the outer i and the inner prev removed, and the same "int" added to the second loop, for it to compile cleanly though it only does so under C99 (or later) as for loop initial declarations are not allowed in C89/90.)</small>
{{out}}
<pre>
2
5
</pre>

=={{header|C++}}==
<syntaxhighlight lang="cpp">#include <array>
#include <iostream>

int main()
{
constexpr std::array s {1,2,2,3,4,4,5};

if(!s.empty())
{
int previousValue = s[0];

for(size_t i = 1; i < s.size(); ++i)
{
// in C++, variables in block scope are reset at each iteration
const int currentValue = s[i];

if(i > 0 && previousValue == currentValue)
{
std::cout << i << "\n";
}

previousValue = currentValue;
}
}
}


</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 68: Line 123:
</pre>
</pre>


=={{header|F_Sharp|F#}}==
Functional programming doesn't really do variables!!! There is no particular judgement of right or wrong here, just a plain-speaking statement that using variables is awful.
<syntaxhighlight lang="fsharp">
// Variable declaration reset. Nigel Galloway: June 21st 2022
let s=[1;2;2;3;4;4;5]
// First let me write this in real F#, which rather avoids the whole issue
printfn "Real F#"
s|>List.pairwise|>List.iteri(fun i (n,g)->if n=g then printfn "%d" (i+1))
// Now let me take the opportunity to write some awful F# by translating the C++
printfn "C++ like awful F#"
let mutable previousValue = -1
for i in 0..s.Length-1 do
let currentValue=s.[i]
if previousValue = currentValue then printfn "%d" i
previousValue <- currentValue
</syntaxhighlight>
{{out}}
<pre>
Real F#
2
5
C++ like awful F#
2
5
</pre>
=={{header|Factor}}==
=={{header|Factor}}==
Normally you would not use lexical scoping for something like this in Factor. But since it is possible, here we go. Note that:
Normally you would not use lexical scoping for something like this in Factor. But since it is possible, here we go. Note that:
Line 75: Line 155:


{{works with|Factor|0.99 2022-04-03}}
{{works with|Factor|0.99 2022-04-03}}
<lang factor>USING: kernel math prettyprint sequences ;
<syntaxhighlight lang="factor">USING: kernel math prettyprint sequences ;


[let
[let
Line 85: Line 165:
curr prev!
curr prev!
] each
] each
]</lang>
]</syntaxhighlight>
{{out}}
{{out}}
[none]
[none]
Line 93: Line 173:


{{works with|Factor|0.99 2022-04-03}}
{{works with|Factor|0.99 2022-04-03}}
<lang factor>USING: kernel math prettyprint sequences ;
<syntaxhighlight lang="factor">USING: kernel math prettyprint sequences ;


[let
[let
Line 103: Line 183:
curr prev!
curr prev!
] each
] each
]</lang>
]</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 111: Line 191:
Now compare to how you would normally solve this in Factor, where issues of variables and scope are irrelevant:
Now compare to how you would normally solve this in Factor, where issues of variables and scope are irrelevant:
{{works with|Factor|0.99 2022-04-03}}
{{works with|Factor|0.99 2022-04-03}}
<lang factor>USING: grouping math.vectors prettyprint sequences.extras ;
<syntaxhighlight lang="factor">USING: grouping math.vectors prettyprint sequences.extras ;


{ 1 2 2 3 4 4 5 } 2 <clumps> [ all-eq? ] arg-where 1 v+n .</lang>
{ 1 2 2 3 4 4 5 } 2 <clumps> [ all-eq? ] arg-where 1 v+n .</syntaxhighlight>


=={{header|FreeBASIC}}==
=={{header|FreeBASIC}}==
<lang freebasic>Dim As Integer s(1 To 7) => {1,2,2,3,4,4,5}
<syntaxhighlight lang="freebasic">Dim As Integer s(1 To 7) => {1,2,2,3,4,4,5}
For i As Integer = 1 To Ubound(s)
For i As Integer = 1 To Ubound(s)
Dim As Integer curr = s(i), prev
Dim As Integer curr = s(i), prev
Line 122: Line 202:
prev = curr
prev = curr
Next i
Next i
Sleep</lang>
Sleep</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 135: Line 215:
=={{header|Go}}==
=={{header|Go}}==
Note firstly that unassigned variables are impossible in Go. If a variable is created (using the 'var' keyword) without giving it an explicit value, then it is assigned the default value for its type which in the case of numbers is zero. Fortunately, this doesn't clash with values in the slice in the following program.
Note firstly that unassigned variables are impossible in Go. If a variable is created (using the 'var' keyword) without giving it an explicit value, then it is assigned the default value for its type which in the case of numbers is zero. Fortunately, this doesn't clash with values in the slice in the following program.
<lang go>package main
<syntaxhighlight lang="go">package main


import "fmt"
import "fmt"
Line 163: Line 243:
prev = curr
prev = curr
}
}
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 177: Line 257:
First off, the idiomatic J approach to finding indices of numbers which match their predecessors would be:
First off, the idiomatic J approach to finding indices of numbers which match their predecessors would be:


<lang J> 1+I.(}:=}.) 1 2 2 3 4 4 5
<syntaxhighlight lang="j"> 1+I.(}:=}.) 1 2 2 3 4 4 5
2 5</lang>
2 5</syntaxhighlight>


In other words, compare adjacent numbers (which results in a list of results one element shorter than the argument), find the indices of the matches (which would be the indices of the pairs which match) and add one (to get the indices in the original list of the second value of each of the pairs).
In other words, compare adjacent numbers (which results in a list of results one element shorter than the argument), find the indices of the matches (which would be the indices of the pairs which match) and add one (to get the indices in the original list of the second value of each of the pairs).
Line 188: Line 268:
Anyways, here's a rough approximation of what the task is asking for:
Anyways, here's a rough approximation of what the task is asking for:


<lang J>same2=: {{
<syntaxhighlight lang="j">same2=: {{
i=. 0
i=. 0
r=. ,EMPTY
r=. ,EMPTY
Line 202: Line 282:
end.
end.
r
r
}}</lang>
}}</syntaxhighlight>


This gives us:
This gives us:


<lang J> same2 1,2,2,3,4,4,5
<syntaxhighlight lang="j"> same2 1,2,2,3,4,4,5
2 5</lang>
2 5</syntaxhighlight>


But, since we were unable to declare 'prev' before it was assigned, we have no way of moving that declaration of 'prev' outside of the loop. We could add a declaration of 'prev' outside of the loop,
But, since we were unable to declare 'prev' before it was assigned, we have no way of moving that declaration of 'prev' outside of the loop. We could add a declaration of 'prev' outside of the loop,


<lang J>same3=: {{
<syntaxhighlight lang="j">same3=: {{
i=. 0
i=. 0
r=. ,EMPTY
r=. ,EMPTY
Line 226: Line 306:
end.
end.
r
r
}}</lang>
}}</syntaxhighlight>


But it would not alter the generated result.
But it would not alter the generated result.


Also... J's control words (like '<tt>while.</tt>') do not create new variable scopes. Given J's scoping rules, if J introduced new variable scopes for control words, that would prevent updates inside those blocks from being visible outside those blocks (unless we also added new scoping rules for that case -- a major engine upgrade -- or used non-local variables, such as J's "locales" which are probably out of scope for this task...). Where J's block scope isolation is desirable, we can use nested functions (J's verbs, adverbs or conjunctions).
In other words, J's control words (like '<tt>while.</tt>') do not create new variable scopes.

But J's design -- which does not allow variables to be declared which are not assigned -- makes most variable declaration problems trivial. This is arguably a good thing.


=={{header|Java}}==
=={{header|Java}}==
Note firstly that variables declared in methods must be assigned a value before they can be used in Java and so here we give '(g)prev' an initial value of 0 which won't clash with the values in the array.
Note firstly that variables declared in methods must be assigned a value before they can be used in Java and so here we give '(g)prev' an initial value of 0 which won't clash with the values in the array.
<lang java>public class VariableDeclarationReset {
<syntaxhighlight lang="java">public class VariableDeclarationReset {
public static void main(String[] args) {
public static void main(String[] args) {
int[] s = {1, 2, 2, 3, 4, 4, 5};
int[] s = {1, 2, 2, 3, 4, 4, 5};
Line 258: Line 340:
}
}
}
}
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 267: Line 349:


=={{header|JavaScript}}==
=={{header|JavaScript}}==
<lang javascript><!DOCTYPE html>
<syntaxhighlight lang="javascript"><!DOCTYPE html>
<html lang="en" >
<html lang="en" >
<head>
<head>
Line 287: Line 369:
</script>
</script>
</body>
</body>
</html></lang>
</html></syntaxhighlight>
No output<br>
No output<br>
Manually moving the declaration of prev to before the loop, or changing the third "let" to "var" (causes legacy hoisting and) gives:
Any of 1) manually moving the declaration of prev to before the loop, or 2) using <code>for (let i=0, prev; i<7; i+=1)</code>, and in fact initialising prev there, to any value, works exactly the same, or 3) changing the third "let" to "var" (causes legacy hoisting and) gives:
{{out}}
{{out}}
<pre>
<pre>
Line 295: Line 377:
5
5
</pre>
</pre>

=={{header|jq}}==
The following "straightforward longhand loop" produces correct answers because the iteration
is specified to begin at the second element.

As it happens, if the first argument of range/2 was changed to 0, then in this particular case the correct results would still be correct because at the first iteration, the test would be $array[0] == $array[-1], the point being that $array[-1] evaluates to the last element of the array. That is, the "bug" in the program would not be revealed by the test case.
<syntaxhighlight lang="jq">[1,2,2,3,4,4,5]
| . as $array
| range(1;length)
| select( $array[.] == $array[.-1])
</syntaxhighlight>


=={{header|Julia}}==
=={{header|Julia}}==
In Julia, variables are declared by being defined. Because variables also must be initialized before they are
In Julia, variables are declared by being defined. Because variables also must be defined before they are
referred to in compiled code, the code below yields an error that the variable `prev` is not defined:
referred to in compiled code, the code below yields an error that the variable `prev` is not defined:
<lang julia>
<syntaxhighlight lang="julia">
s = [1, 2, 2, 3, 4, 4, 5]
s = [1, 2, 2, 3, 4, 4, 5]
Line 307: Line 400:
prev = curr
prev = curr
end
end
</syntaxhighlight>
</lang>
If the variable `prev` is defined before the `for` statement, the code then runs. We also may
If the variable `prev` is defined before the `for` statement, the code then runs. We also may
declare the variable `prev` as global to refer explicitly to the variable declared outside of the for block:
declare the variable `prev` as global to refer explicitly to the variable declared outside of the for block:
<lang julia>
<syntaxhighlight lang="julia">
s = [1, 2, 2, 3, 4, 4, 5]
s = [1, 2, 2, 3, 4, 4, 5]
prev = -1
prev = -1
Line 320: Line 413:
prev = curr
prev = curr
end
end
</lang> {{out}}
</syntaxhighlight> {{out}}
<pre>
<pre>
3
3
6
6
</pre>
</pre>
Parenthetical note: making a global variable to support a for loop has a bad code smell in Julia. A better
way to do such a comparison of adjacent values in an array is to alter the start of the loop variable:
<syntaxhighlight lang="julia">
s = [1, 2, 2, 3, 4, 4, 5]

for i in eachindex(s)[begin+1:end] # or 2:length(s)
s[i] == s[i - 1] && println(i)
end
</syntaxhighlight>

=={{header|K}}==
There is no such thing as a <i>straightforward longhand loop</i> in K. See also: https://nsl.com/

A natural expression for finding the indices of repeated elements (in [[ngn/k]]) might be:<syntaxhighlight lang=K>&=/'2':1 2 2 3 4 4 5
1 4</syntaxhighlight>

But of course, there's no variables here.

Longhand loops can be emulated, using lambdas (in which case local variables expire when the lambda exits), but this is not what many programmers would think of as a straightforward longhand loop.

=={{header|Nim}}==
In Nim, a loop create a new block. Variables declared in the loop body are created and initialized at each round: they do not retain the value from one round to the next.

Moreover, a variable needs to be declared before use, except variables in “for” loop which are implicitly declared in the loop block scope. If the variable has not been declared, the program fails to compile.

Is is not mandatory to initialize a variable. If there is no explicit initialization, the variable gets a default value which depends on its type (this is a binary zero).

Thus, the following program doesn’t compile, as, at compile time, “prev” is used before its declaration:

<syntaxhighlight lang="Nim">let s = [1, 2, 2, 3, 4, 4, 5]
for i in 0..s.high:
let curr = s[i]
if i > 0 and curr == prev:
echo i
var prev = curr
</syntaxhighlight>

The following program compiles but doesn’t output the right result as “prev” is reset at beginning of each round:

<syntaxhighlight lang="Nim">let s = [1, 2, 2, 3, 4, 4, 5]
for i in 0..s.high:
let curr = s[i]
var prev: int
if i > 0 and curr == prev:
echo i
prev = curr
</syntaxhighlight>

To get the right result, we need to declare “prev” outside the loop.
<syntaxhighlight lang="Nim">let s = [1, 2, 2, 3, 4, 4, 5]
var prev: int
for i in 0..s.high:
let curr = s[i]
if i > 0 and curr == prev:
echo i
prev = curr
</syntaxhighlight>

{{out}}
<pre>2
5
</pre>

=={{header|Perl}}==
By default, variables can be created on-the-fly, as with <code>$prev</code> here. Testing against <code>$curr</code> is not an error, even when it's value is undefined. This is perhaps not "best practices", but it does work just fine.
<syntaxhighlight lang="perl">@s = <1 2 2 3 4 4 5>;
for ($i = 0; $i < 7; $i++) {
$curr = $s[$i];
if ($i > 1 and $curr == $prev) { print "$i\n" }
$prev = $curr;
}</syntaxhighlight>
{{out}}
<pre>2
5</pre>

But better to do it this way, requiring <code>my</code> declarations imposing lexical scope (an instance of <code>$curr</code> is instantiated on every pass through loop) and employing a <code>state</code> variable (persistent within loop).
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'state';

my @s = <1 2 2 3 4 4 5>;
for (my $i = 0; $i < 7; $i++) {
my $curr = $s[$i];
state $prev;
if ($i > 1 and $curr == $prev) { print "$i\n" }
$prev = $curr;
}</syntaxhighlight>
{{out}}
<pre>2
5</pre>


=={{header|Phix}}==
=={{header|Phix}}==
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">}</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">}</span>
Line 337: Line 520:
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">curr</span>
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">curr</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
Line 350: Line 533:
Although PL/M has block scope, all variables are static, so PREV retains its value between iterations of the loop.<br>
Although PL/M has block scope, all variables are static, so PREV retains its value between iterations of the loop.<br>
Note the extra DO which is necessary to introduce a new scope as declarations are not allowed in a DO loop.
Note the extra DO which is necessary to introduce a new scope as declarations are not allowed in a DO loop.
<lang pli>100H:
<syntaxhighlight lang="pli">100H:


/* CP/M BDOS SYSTEM CALL */
/* CP/M BDOS SYSTEM CALL */
Line 383: Line 566:
END;
END;


EOF</lang>
EOF</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 391: Line 574:


=={{header|Python}}==
=={{header|Python}}==
In Python, variables are not declared before use. If you assign to a non-existent variable, you create a new variable with that name. The language does not prohibit writing code to read a variable that may or may not exist. But if the code tries at runtime to read a variable that happens to not have been assigned to (or a variable that happens to have been <code>del</code>'ed), you get a <code>NameError</code> exception at runtime.
In Python, variables are supposed to be defined before they are used. The code does run, but note that a Python code checker such as pyflakes will flag such code with an error.

<lang python>
The following code is legal, but note that a Python code checker such as pyflakes will flag such code with an error.
<syntaxhighlight lang="python">
s = [1, 2, 2, 3, 4, 4, 5]
s = [1, 2, 2, 3, 4, 4, 5]
Line 400: Line 585:
print(i)
print(i)
prev = curr
prev = curr
</lang>{{out}}
</syntaxhighlight>{{out}}
<pre>
<pre>
2
2
Line 409: Line 594:
By default, Raku variables need a prefix sigil indicating the storage / interface, and a scope declarator to indicate the variables' accessibility. The vast majority of the time, variables are declared with a "my" scope declarator that constrains them to the present block and any enclosed sub blocks. When a 'my' variable is declared inside a loop (block), a new independent instance of the variable is instantiated every time through.
By default, Raku variables need a prefix sigil indicating the storage / interface, and a scope declarator to indicate the variables' accessibility. The vast majority of the time, variables are declared with a "my" scope declarator that constrains them to the present block and any enclosed sub blocks. When a 'my' variable is declared inside a loop (block), a new independent instance of the variable is instantiated every time through.


<lang perl6>my @s = 1, 2, 2, 3, 4, 4, 5;
<syntaxhighlight lang="raku" line>my @s = 1, 2, 2, 3, 4, 4, 5;
loop (my $i = 0; $i < 7; $i += 1) {
loop (my $i = 0; $i < 7; $i += 1) {
my $curr = @s[$i];
my $curr = @s[$i];
Line 417: Line 602:
}
}
$prev = $curr;
$prev = $curr;
}</lang>
}</syntaxhighlight>
{{out|Yields}}
{{out|Yields}}
<pre>Use of uninitialized value of type Any in numeric context
<pre>Use of uninitialized value of type Any in numeric context
Line 432: Line 617:
Lots of warnings but nothing else. If we suppress the warnings:
Lots of warnings but nothing else. If we suppress the warnings:


<lang perl6>my @s = 1, 2, 2, 3, 4, 4, 5;
<syntaxhighlight lang="raku" line>my @s = 1, 2, 2, 3, 4, 4, 5;
quietly loop (my $i = 0; $i < 7; $i += 1) {
quietly loop (my $i = 0; $i < 7; $i += 1) {
my $curr = @s[$i];
my $curr = @s[$i];
Line 440: Line 625:
}
}
$prev = $curr;
$prev = $curr;
}</lang>
}</syntaxhighlight>


No output.
No output.
Line 447: Line 632:
We can however, declare the variable with an "our" scope, which effectively makes it a package global. Use of 'our' scoping is discouraged except in a few very specific situations. It "works" (for some value of works), but pollutes the namespace. The 'our' variable will trample any other instance of a variable with that name anywhere in the program in any other scope.
We can however, declare the variable with an "our" scope, which effectively makes it a package global. Use of 'our' scoping is discouraged except in a few very specific situations. It "works" (for some value of works), but pollutes the namespace. The 'our' variable will trample any other instance of a variable with that name anywhere in the program in any other scope.


<lang perl6>my @s = 1, 2, 2, 3, 4, 4, 5;
<syntaxhighlight lang="raku" line>my @s = 1, 2, 2, 3, 4, 4, 5;
loop (my $i = 0; $i < 7; $i += 1) {
loop (my $i = 0; $i < 7; $i += 1) {
my $curr = @s[$i];
my $curr = @s[$i];
Line 455: Line 640:
}
}
$prev = $curr;
$prev = $curr;
}</lang>
}</syntaxhighlight>


{{out|Yields}}
{{out|Yields}}
Line 463: Line 648:
A better solution is to declare a state variable. A 'state' variable is essentially scoped similar to a 'my' variable (visible only inside the block), but is persistent across calls.
A better solution is to declare a state variable. A 'state' variable is essentially scoped similar to a 'my' variable (visible only inside the block), but is persistent across calls.


<lang perl6>my @s = 1, 2, 2, 3, 4, 4, 5;
<syntaxhighlight lang="raku" line>my @s = 1, 2, 2, 3, 4, 4, 5;
loop (my $i = 0; $i < 7; $i += 1) {
loop (my $i = 0; $i < 7; $i += 1) {
my $curr = @s[$i];
my $curr = @s[$i];
Line 471: Line 656:
}
}
$prev = $curr;
$prev = $curr;
}</lang>
}</syntaxhighlight>


{{out|Yields}}
{{out|Yields}}
Line 480: Line 665:


No scope declarators at all. Every variable is a global. Bad idea. Do not do this casually.
No scope declarators at all. Every variable is a global. Bad idea. Do not do this casually.
<lang perl6>no strict;
<syntaxhighlight lang="raku" line>no strict;
@s = 1, 2, 2, 3, 4, 4, 5;
@s = 1, 2, 2, 3, 4, 4, 5;
loop ($i = 0; $i < 7; $i += 1) {
loop ($i = 0; $i < 7; $i += 1) {
Line 488: Line 673:
}
}
$prev = $curr;
$prev = $curr;
}</lang>
}</syntaxhighlight>


{{out|Yields}}
{{out|Yields}}
Line 497: Line 682:
* Blocks start at index 1 in Red.
* Blocks start at index 1 in Red.
* <code>all</code> short-circuits, so <code>prev</code> will be defined by the time <code>curr = prev</code> is checked.
* <code>all</code> short-circuits, so <code>prev</code> will be defined by the time <code>curr = prev</code> is checked.
<lang rebol>Red[]
<syntaxhighlight lang="rebol">Red[]
s: [1 2 2 3 4 4 5]
s: [1 2 2 3 4 4 5]
repeat i length? s [
repeat i length? s [
Line 505: Line 690:
]
]
prev: curr
prev: curr
]</lang>
]</syntaxhighlight>
{{out}}
<pre>
3
6
</pre>

=={{header|Seed7}}==
Variables must be declared in the locals section (or as globals) before execution begins, so this whole excercise is moot. There is only one way to write it and it's the way that works.
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i";

const proc: main is func
local
const array integer: s is [] (1, 2, 2, 3, 4, 4, 5);
var integer: i is 0;
var integer: curr is 0;
var integer: prev is 0;
begin
for i range 1 to length(s) do
curr := s[i];
if i > 1 and curr = prev then
writeln(i);
end if;
prev := curr;
end for;
end func;</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 513: Line 723:


=={{header|Visual Basic .NET}}==
=={{header|Visual Basic .NET}}==
<lang vbnet>Option Strict On
<syntaxhighlight lang="vbnet">Option Strict On
Option Explicit On
Option Explicit On


Line 532: Line 742:
End Sub
End Sub


End Module</lang>
End Module</syntaxhighlight>
{{out}}
<pre>
2
5
</pre>

=={{header|V (Vlang)}}==
Note firstly that unassigned variables are impossible in Vlang. If a variable is created it must have an explicit value, then it is assigned the default value for its type which in the case of numbers is zero. Fortunately, this doesn't clash with values in the slice in the following program.
<syntaxhighlight lang="v (vlang)">fn main() {
s := [1, 2, 2, 3, 4, 4, 5]
// There is no output as 'prev' is created anew each time
// around the loop and set implicitly to zero.
for i := 0; i < s.len; i++ {
curr := s[i]
mut prev := 0
if i > 0 && curr == prev {
println(i)
}
prev = curr
}
// Now 'prev' is created only once and reassigned
// each time around the loop producing the desired output.
mut prev := 0
for i := 0; i < s.len; i++ {
curr := s[i]
if i > 0 && curr == prev {
println(i)
}
prev = curr
}
}</syntaxhighlight>

{{out}}
{{out}}
<pre>
<pre>
Line 541: Line 785:
=={{header|Wren}}==
=={{header|Wren}}==
Note firstly that unassigned variables are impossible in Wren. If a variable is created without giving it an explicit value, then it is assigned the special value 'null' which is the only instance of the Null class and therefore distinct from all other values in the language.
Note firstly that unassigned variables are impossible in Wren. If a variable is created without giving it an explicit value, then it is assigned the special value 'null' which is the only instance of the Null class and therefore distinct from all other values in the language.
<lang ecmascript>var s = [1, 2, 2, 3, 4, 4, 5]
<syntaxhighlight lang="wren">var s = [1, 2, 2, 3, 4, 4, 5]


// There is no output as 'prev' is created anew each time
// There is no output as 'prev' is created anew each time
Line 559: Line 803:
if (i > 0 && curr == prev) System.print(i)
if (i > 0 && curr == prev) System.print(i)
prev = curr
prev = curr
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}

Latest revision as of 10:05, 16 February 2024

Task
Variable declaration reset
You are encouraged to solve this task according to the task description, using any language you may know.

A decidely non-challenging task to highlight a potential difference between programming languages.

Using a straightforward longhand loop as in the JavaScript and Phix examples below, show the locations of elements which are identical to the immediately preceding element in {1,2,2,3,4,4,5}. The (non-blank) results may be 2,5 for zero-based or 3,6 if one-based.
The purpose is to determine whether variable declaration (in block scope) resets the contents on every iteration.
There is no particular judgement of right or wrong here, just a plain-speaking statement of subtle differences.
Should your first attempt bomb with "unassigned variable" exceptions, feel free to code it as (say)

 // int prev // crashes with unassigned variable
    int prev = -1 // predictably no output

If your programming language does not support block scope (eg assembly) it should be omitted from this task.

ALGOL 68

In Algol 68, things that aren't explicitely initialised are notionally initialised to SKIP - an indeterminate value, so there should be no output from the program. Each iteration of the loop will get a new curr and prev, with prev initialised to SKIP. The following is equivalent to the Phix program...

BEGIN
    []INT s = ( 1, 2, 2, 3, 4, 4, 5 );
    FOR i FROM LWB s TO UPB s DO
        INT curr := s[ i ], prev;
        IF IF i > LWB s THEN curr = prev ELSE FALSE FI THEN
            print( ( i, newline ) )
        FI;
        prev := curr
    OD
END

...however, one of the non-standard features of Algol 68G is that uninitialised variables cause a runtime error instead of silently being set to SKIP.

Output:

with Algol 68G

5             IF IF i > LWB s THEN curr = prev ELSE FALSE FI THEN
                                          1
a68g-2.8.3: runtime error: 1: attempt to use an uninitialised INT value (detected in BOOL conditional-clause starting at "IF" in this line).

...whereas, with Rutgers Algol 68:
No output.

AWK

# syntax: GAWK -f VARIABLE_DECLARATION_RESET.AWK
BEGIN {
    n = split("1,2,2,3,4,4,5",arr,",")
    for (i=1; i<=n; i++) {
      curr = arr[i]
      if (i > 1 && prev == curr) {
        printf("%s\n",i)
      }
      prev = curr
    }
    exit(0)
}
Output:
3
6

C

Note firstly that it's possible to create variables in C without initializing them. However, if you do so, the value the variable will contain is unpredictable and so here we give '(g)prev' an initial value of 0 to make absolutely sure it won't clash with the values in the array.

The following compiles using either C89/90 (-std=c90 -ansi -pedantic) or C99 syntax using gcc 9.4.0.

#include <stdio.h>

int main() {
    int i, gprev = 0;
    int s[7] = {1, 2, 2, 3, 4, 4, 5};

    /* There is no output as 'prev' is created anew each time
       around the loop and set explicitly to zero. */
    for (i = 0; i < 7; ++i) {
//  for (int i = 0, prev; i < 7; ++i) { // as below, see note
        int curr = s[i];
        int prev = 0;
//      int prev; // produces same output as second loop
        if (i > 0 && curr == prev) printf("%d\n", i);
        prev = curr;
    }

    /*  Now 'gprev' is used and reassigned
        each time around the loop producing the desired output. */
    for (i = 0; i < 7; ++i) {
        int curr = s[i];
        if (i > 0 && curr == gprev) printf("%d\n", i);
        gprev = curr;
    }

    return 0;
}

(Note: Obviously the for (int i=0, prev needs the outer i and the inner prev removed, and the same "int" added to the second loop, for it to compile cleanly though it only does so under C99 (or later) as for loop initial declarations are not allowed in C89/90.)

Output:
2
5

C++

#include <array>
#include <iostream>

int main()
{
  constexpr std::array s {1,2,2,3,4,4,5};

  if(!s.empty())
  {
    int previousValue = s[0];

    for(size_t i = 1; i < s.size(); ++i)
    {
      // in C++, variables in block scope are reset at each iteration
      const int currentValue = s[i];

      if(i > 0 && previousValue == currentValue)
      {
        std::cout << i << "\n";
      }

      previousValue = currentValue;
    }
  }
}
Output:
2
5

F#

Functional programming doesn't really do variables!!! There is no particular judgement of right or wrong here, just a plain-speaking statement that using variables is awful.

// Variable declaration reset. Nigel Galloway: June 21st 2022
let s=[1;2;2;3;4;4;5]
// First let me write this in real F#, which rather avoids the whole issue
printfn "Real F#"
s|>List.pairwise|>List.iteri(fun i (n,g)->if n=g then printfn "%d" (i+1))
// Now let me take the opportunity to write some awful F# by translating the C++
printfn "C++ like awful F#"
let mutable previousValue = -1
for i in 0..s.Length-1 do
  let currentValue=s.[i]
  if previousValue = currentValue then printfn "%d" i
  previousValue <- currentValue
Output:
Real F#
2
5
C++ like awful F#
2
5

Factor

Normally you would not use lexical scoping for something like this in Factor. But since it is possible, here we go. Note that:

  • Factor doesn't allow you to declare a lexical variable without initializing it.
  • Lexical variables are immutable by default. To make a lexical variable mutable, you need to add a ! to its declaration.


Works with: Factor version 0.99 2022-04-03
USING: kernel math prettyprint sequences ;

[let
    { 1 2 2 3 4 4 5 } :> s
    s length <iota> [| i |
        i s nth -1 :> ( curr prev! )    
        i 0 > curr prev = and
        [ i . ] when
        curr prev!
    ] each
]
Output:

[none]


To get output, we need to declare prev outside the each quotation.

Works with: Factor version 0.99 2022-04-03
USING: kernel math prettyprint sequences ;

[let
    { 1 2 2 3 4 4 5 } -1 :> ( s prev! )
    s length <iota> [| i |
        i s nth :> curr
        i 0 > curr prev = and
        [ i . ] when
        curr prev!
    ] each
]
Output:
2
5

Now compare to how you would normally solve this in Factor, where issues of variables and scope are irrelevant:

Works with: Factor version 0.99 2022-04-03
USING: grouping math.vectors prettyprint sequences.extras ;

{ 1 2 2 3 4 4 5 } 2 <clumps> [ all-eq? ] arg-where 1 v+n .

FreeBASIC

Dim As Integer s(1 To 7) => {1,2,2,3,4,4,5}
For i As Integer = 1 To Ubound(s)
    Dim As Integer curr = s(i), prev
    If i > 1 And curr = prev Then Print i
    prev = curr
Next i
Sleep
Output:
3
6

Go

Note firstly that unassigned variables are impossible in Go. If a variable is created (using the 'var' keyword) without giving it an explicit value, then it is assigned the default value for its type which in the case of numbers is zero. Fortunately, this doesn't clash with values in the slice in the following program.

package main

import "fmt"

func main() {
    s := []int{1, 2, 2, 3, 4, 4, 5}

    // There is no output as 'prev' is created anew each time
    // around the loop and set implicitly to zero.
    for i := 0; i < len(s); i++ {
        curr := s[i]
        var prev int
        if i > 0 && curr == prev {
            fmt.Println(i)
        }
        prev = curr
    }

    // Now 'prev' is created only once and reassigned
    // each time around the loop producing the desired output.
    var prev int
    for i := 0; i < len(s); i++ {
        curr := s[i]
        if i > 0 && curr == prev {
            fmt.Println(i)
        }
        prev = curr
    }
}
Output:
2
5

J

It may be difficult to say what is natural here, from the J perspective.

First off, the idiomatic J approach to finding indices of numbers which match their predecessors would be:

   1+I.(}:=}.) 1 2 2 3 4 4 5
2 5

In other words, compare adjacent numbers (which results in a list of results one element shorter than the argument), find the indices of the matches (which would be the indices of the pairs which match) and add one (to get the indices in the original list of the second value of each of the pairs).

Also, J's for loop is analogous to javascript's foreach loop (and also tracks and makes available the index of the current value, which is useful when working with parallel lists). So we have to use J's while loop to approximate the javascript implementation.

But, also, J makes no distinction between a variable declaration and a variable assignment. And this task seems to be asking about how we handle that distinction.

Anyways, here's a rough approximation of what the task is asking for:

same2=: {{
  i=. 0
  r=. ,EMPTY
  while. i < #y do.
    curr=. i{y
    if. i>0 do.
      if. curr=prev do.
        r=. r,i
      end.
    end.
    prev=. curr
    i=. i+1
  end.
  r
}}

This gives us:

   same2 1,2,2,3,4,4,5
2 5

But, since we were unable to declare 'prev' before it was assigned, we have no way of moving that declaration of 'prev' outside of the loop. We could add a declaration of 'prev' outside of the loop,

same3=: {{
  i=. 0
  r=. ,EMPTY
  prev=. 99
  while. i < #y do.
    curr=. i{y
    if. i>0 do.
      if. curr=prev do.
        r=. r,i
      end.
    end.
    prev=. curr
    i=. i+1
  end.
  r
}}

But it would not alter the generated result.

Also... J's control words (like 'while.') do not create new variable scopes. Given J's scoping rules, if J introduced new variable scopes for control words, that would prevent updates inside those blocks from being visible outside those blocks (unless we also added new scoping rules for that case -- a major engine upgrade -- or used non-local variables, such as J's "locales" which are probably out of scope for this task...). Where J's block scope isolation is desirable, we can use nested functions (J's verbs, adverbs or conjunctions).

But J's design -- which does not allow variables to be declared which are not assigned -- makes most variable declaration problems trivial. This is arguably a good thing.

Java

Note firstly that variables declared in methods must be assigned a value before they can be used in Java and so here we give '(g)prev' an initial value of 0 which won't clash with the values in the array.

public class VariableDeclarationReset {
    public static void main(String[] args) {
        int[] s = {1, 2, 2, 3, 4, 4, 5};

        // There is no output as 'prev' is created anew each time
        // around the loop and set to zero.
        for (int i = 0; i < s.length; ++i) {
            int curr = s[i];
            int prev = 0;
//          int prev; // triggers "error: variable prev might not have been initialized"
            if (i > 0 && curr == prev) System.out.println(i);
            prev = curr;
        }

        int gprev = 0;

        // Now 'gprev' is used and reassigned
        // each time around the loop producing the desired output.
        for (int i = 0; i < s.length; ++i) {
            int curr = s[i];
            if (i > 0 && curr == gprev) System.out.println(i);
            gprev = curr;
        }
    }
}
Output:
2
5

JavaScript

<!DOCTYPE html>
<html lang="en" >
 <head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>variable declaration reset</title>
 </head>
 <body>
  <script>
"use strict";
let s = [1, 2, 2, 3, 4, 4, 5];
for (let i=0; i<7; i+=1) {
    let curr = s[i], prev;
    if (i>0 && (curr===prev)) {
        console.log(i);
    }
    prev = curr;
}
  </script>
 </body>
</html>

No output
Any of 1) manually moving the declaration of prev to before the loop, or 2) using for (let i=0, prev; i<7; i+=1), and in fact initialising prev there, to any value, works exactly the same, or 3) changing the third "let" to "var" (causes legacy hoisting and) gives:

Output:
2
5

jq

The following "straightforward longhand loop" produces correct answers because the iteration is specified to begin at the second element.

As it happens, if the first argument of range/2 was changed to 0, then in this particular case the correct results would still be correct because at the first iteration, the test would be $array[0] == $array[-1], the point being that $array[-1] evaluates to the last element of the array. That is, the "bug" in the program would not be revealed by the test case.

[1,2,2,3,4,4,5]
| . as $array
| range(1;length)
| select( $array[.] == $array[.-1])

Julia

In Julia, variables are declared by being defined. Because variables also must be defined before they are referred to in compiled code, the code below yields an error that the variable `prev` is not defined:

s = [1, 2, 2, 3, 4, 4, 5]
 
for i in eachindex(s)
    curr = s[i]
    i > 1 && curr == prev && println(i)
    prev = curr
end

If the variable `prev` is defined before the `for` statement, the code then runs. We also may declare the variable `prev` as global to refer explicitly to the variable declared outside of the for block:

s = [1, 2, 2, 3, 4, 4, 5]
prev = -1 

for i in eachindex(s)
    global prev
    curr = s[i]
    i > 1 && curr == prev && println(i)
    prev = curr
end
Output:
3
6

Parenthetical note: making a global variable to support a for loop has a bad code smell in Julia. A better way to do such a comparison of adjacent values in an array is to alter the start of the loop variable:

s = [1, 2, 2, 3, 4, 4, 5]

for i in eachindex(s)[begin+1:end] # or 2:length(s)
    s[i] == s[i - 1] && println(i)
end

K

There is no such thing as a straightforward longhand loop in K. See also: https://nsl.com/

A natural expression for finding the indices of repeated elements (in ngn/k) might be:

&=/'2':1 2 2 3 4 4 5
1 4

But of course, there's no variables here.

Longhand loops can be emulated, using lambdas (in which case local variables expire when the lambda exits), but this is not what many programmers would think of as a straightforward longhand loop.

Nim

In Nim, a loop create a new block. Variables declared in the loop body are created and initialized at each round: they do not retain the value from one round to the next.

Moreover, a variable needs to be declared before use, except variables in “for” loop which are implicitly declared in the loop block scope. If the variable has not been declared, the program fails to compile.

Is is not mandatory to initialize a variable. If there is no explicit initialization, the variable gets a default value which depends on its type (this is a binary zero).

Thus, the following program doesn’t compile, as, at compile time, “prev” is used before its declaration:

let s = [1, 2, 2, 3, 4, 4, 5]
for i in 0..s.high:
  let curr = s[i]
  if i > 0 and curr == prev:
    echo i
  var prev = curr

The following program compiles but doesn’t output the right result as “prev” is reset at beginning of each round:

let s = [1, 2, 2, 3, 4, 4, 5]
for i in 0..s.high:
  let curr = s[i]
  var prev: int
  if i > 0 and curr == prev:
    echo i
  prev = curr

To get the right result, we need to declare “prev” outside the loop.

let s = [1, 2, 2, 3, 4, 4, 5]
var prev: int
for i in 0..s.high:
  let curr = s[i]
  if i > 0 and curr == prev:
    echo i
  prev = curr
Output:
2
5

Perl

By default, variables can be created on-the-fly, as with $prev here. Testing against $curr is not an error, even when it's value is undefined. This is perhaps not "best practices", but it does work just fine.

@s = <1 2 2 3 4 4 5>;
for ($i = 0; $i < 7; $i++) {
    $curr = $s[$i];
    if ($i > 1 and $curr == $prev) { print "$i\n" }
    $prev = $curr;
}
Output:
2
5

But better to do it this way, requiring my declarations imposing lexical scope (an instance of $curr is instantiated on every pass through loop) and employing a state variable (persistent within loop).

use strict;
use warnings;
use feature 'state';

my @s = <1 2 2 3 4 4 5>;
for (my $i = 0; $i < 7; $i++) {
    my $curr = $s[$i];
    state $prev;
    if ($i > 1 and $curr == $prev) { print "$i\n" }
    $prev = $curr;
}
Output:
2
5

Phix

with javascript_semantics
sequence s = {1,2,2,3,4,4,5}
for i=1 to length(s) do
    integer curr = s[i], prev
    if i>1 and curr=prev then
        ?i
    end if
    prev = curr
end for
Output:
3
6

Like the first/unchanged JavaScript example, under pwa/p2js there is no output (at least as things currently stand)
Obviously you can achieve consistent results by manually hoisting the declaration of prev to before/outside the loop.

PL/M

Works with: 8080 PL/M Compiler

... under CP/M (or an emulator)

Although PL/M has block scope, all variables are static, so PREV retains its value between iterations of the loop.
Note the extra DO which is necessary to introduce a new scope as declarations are not allowed in a DO loop.

100H:

   /* CP/M BDOS SYSTEM CALL */
   BDOS: PROCEDURE( FN, ARG ); DECLARE FN BYTE, ARG ADDRESS; GOTO 5;END;
   /* CONSOLE OUTPUT ROUTINES */
   PR$CHAR:   PROCEDURE( C ); DECLARE C BYTE;    CALL BDOS( 2, C ); END;
   PR$STRING: PROCEDURE( S ); DECLARE S ADDRESS; CALL BDOS( 9, S ); END;
   PR$NL:     PROCEDURE; CALL PR$STRING( .( 0DH, 0AH, '$' ) );      END;
   PR$NUMBER: PROCEDURE( N );
      DECLARE N ADDRESS;
      DECLARE V ADDRESS, N$STR( 6 ) BYTE INITIAL( '.....$' ), W BYTE;
      N$STR( W := LAST( N$STR ) - 1 ) = '0' + ( ( V := N ) MOD 10 );
      DO WHILE( ( V := V / 10 ) > 0 );
         N$STR( W := W - 1 ) = '0' + ( V MOD 10 );
      END;
      CALL PR$STRING( .N$STR( W ) );
   END PR$NUMBER;

   /* TASK */
   DECLARE S( 6 ) BYTE INITIAL( 1, 2, 2, 3, 4, 4, 5 );
   DECLARE I BYTE;
   DO I = 0 TO LAST( S );
      DO;
         DECLARE ( CURR, PREV ) BYTE;
         CURR = S( I );
         IF I > 1 AND CURR = PREV THEN DO;
            CALL PR$NUMBER( I );
            CALL PR$NL;
         END;
         PREV = CURR;
      END;
   END;

EOF
Output:
2
5

Python

In Python, variables are not declared before use. If you assign to a non-existent variable, you create a new variable with that name. The language does not prohibit writing code to read a variable that may or may not exist. But if the code tries at runtime to read a variable that happens to not have been assigned to (or a variable that happens to have been del'ed), you get a NameError exception at runtime.

The following code is legal, but note that a Python code checker such as pyflakes will flag such code with an error.

s = [1, 2, 2, 3, 4, 4, 5]
 
for i in range(len(s)):
    curr = s[i]
    if i > 0 and curr == prev:
        print(i)
    prev = curr
Output:
2
5

Raku

By default, Raku variables need a prefix sigil indicating the storage / interface, and a scope declarator to indicate the variables' accessibility. The vast majority of the time, variables are declared with a "my" scope declarator that constrains them to the present block and any enclosed sub blocks. When a 'my' variable is declared inside a loop (block), a new independent instance of the variable is instantiated every time through.

my @s = 1, 2, 2, 3, 4, 4, 5;
loop (my $i = 0; $i < 7; $i += 1) {
    my $curr = @s[$i];
    my $prev;
    if $i > 1 and $curr == $prev {
        say $i;
    }
    $prev = $curr;
}
Yields:
Use of uninitialized value of type Any in numeric context
  in block <unit> at var.p6 line 5
Use of uninitialized value of type Any in numeric context
  in block <unit> at var.p6 line 5
Use of uninitialized value of type Any in numeric context
  in block <unit> at var.p6 line 5
Use of uninitialized value of type Any in numeric context
  in block <unit> at var.p6 line 5
Use of uninitialized value of type Any in numeric context
  in block <unit> at var.p6 line 5

Lots of warnings but nothing else. If we suppress the warnings:

my @s = 1, 2, 2, 3, 4, 4, 5;
quietly loop (my $i = 0; $i < 7; $i += 1) {
    my $curr = @s[$i];
    my $prev;
    if $i > 1 and $curr == $prev {
        say $i;
    }
    $prev = $curr;
}

No output.


We can however, declare the variable with an "our" scope, which effectively makes it a package global. Use of 'our' scoping is discouraged except in a few very specific situations. It "works" (for some value of works), but pollutes the namespace. The 'our' variable will trample any other instance of a variable with that name anywhere in the program in any other scope.

my @s = 1, 2, 2, 3, 4, 4, 5;
loop (my $i = 0; $i < 7; $i += 1) {
    my $curr = @s[$i];
    our $prev;
    if $i > 1 and $curr == $prev {
        say $i;
    }
    $prev = $curr;
}
Yields:
2
5

A better solution is to declare a state variable. A 'state' variable is essentially scoped similar to a 'my' variable (visible only inside the block), but is persistent across calls.

my @s = 1, 2, 2, 3, 4, 4, 5;
loop (my $i = 0; $i < 7; $i += 1) {
    my $curr = @s[$i];
    state $prev;
    if $i > 1 and $curr == $prev {
        say $i;
    }
    $prev = $curr;
}
Yields:
2
5

If you really want to run fast and loose, and bypass all the protections Raku builds in, you can turn off strict scoping with a pragma. This is heavily discouraged. Anyone trying to release code with strictures turned off will receive some degree of side-eye... but just because something is a bad idea in general doesn't mean Raku forbids it. The Raku mindset is "Make it difficult to make casual mistakes but make it possible to bypass those protections if you have the need."

No scope declarators at all. Every variable is a global. Bad idea. Do not do this casually.

no strict;
@s = 1, 2, 2, 3, 4, 4, 5;
loop ($i = 0; $i < 7; $i += 1) {
    $curr = @s[$i];
    if $i > 1 and $curr == $prev {
        say $i;
    }
    $prev = $curr;
}
Yields:
2
5

Red

  • Blocks start at index 1 in Red.
  • all short-circuits, so prev will be defined by the time curr = prev is checked.
Red[]
s: [1 2 2 3 4 4 5]
repeat i length? s [
    curr: s/:i
    if all [i > 1 curr = prev][
        print i
    ]
    prev: curr
]
Output:
3
6

Seed7

Variables must be declared in the locals section (or as globals) before execution begins, so this whole excercise is moot. There is only one way to write it and it's the way that works.

$ include "seed7_05.s7i";

const proc: main is func
  local
    const array integer: s is [] (1, 2, 2, 3, 4, 4, 5);
    var integer: i is 0;
    var integer: curr is 0;
    var integer: prev is 0;
  begin
    for i range 1 to length(s) do
      curr := s[i];
      if i > 1 and curr = prev then
        writeln(i);
      end if;
      prev := curr;
    end for;
  end func;
Output:
3
6

Visual Basic .NET

Option Strict On
Option Explicit On

Imports System.IO

Module vMain

    Public Sub Main
        Dim s As Integer() = New Integer(){1, 2, 2, 3, 4, 4, 5}
        For i As Integer = 0 To Ubound(s)
            Dim curr As Integer = s(i)
            Dim prev As Integer
            If i > 1 AndAlso curr = prev Then
                  Console.Out.WriteLine(i)
            End If
            prev = curr
        Next i
    End Sub

End Module
Output:
2
5

V (Vlang)

Note firstly that unassigned variables are impossible in Vlang. If a variable is created it must have an explicit value, then it is assigned the default value for its type which in the case of numbers is zero. Fortunately, this doesn't clash with values in the slice in the following program.

fn main() {
    s := [1, 2, 2, 3, 4, 4, 5]
 
    // There is no output as 'prev' is created anew each time
    // around the loop and set implicitly to zero.
    for i := 0; i < s.len; i++ {
        curr := s[i]
        mut prev := 0
        if i > 0 && curr == prev {
            println(i)
        }
        prev = curr
    }
 
    // Now 'prev' is created only once and reassigned
    // each time around the loop producing the desired output.
    mut prev := 0
    for i := 0; i < s.len; i++ {
        curr := s[i]
        if i > 0 && curr == prev {
            println(i)
        }
        prev = curr
    }
}
Output:
2
5

Wren

Note firstly that unassigned variables are impossible in Wren. If a variable is created without giving it an explicit value, then it is assigned the special value 'null' which is the only instance of the Null class and therefore distinct from all other values in the language.

var s = [1, 2, 2, 3, 4, 4, 5]

// There is no output as 'prev' is created anew each time
// around the loop and set implicitly to null.
for (i in 0...s.count) {
    var curr = s[i]
    var prev
    if (i > 0 && curr == prev) System.print(i)
    prev = curr
}

// Now 'prev' is created only once and reassigned
// each time around the loop producing the desired output.
var prev
for (i in 0...s.count) {
    var curr = s[i]
    if (i > 0 && curr == prev) System.print(i)
    prev = curr
}
Output:
2
5