consider this simple c program:
#include <stdio.h>
int search_dup(int counta, int a[], int elem, int countres, int res[]) {
int x = 0;
for (;x < counta; x++) {
if (x == elem) continue;
if (a[x] == a[elem]) {
int y = 0;
for (; y < countres; y++) {
if (res[y] == a[elem]) break;
}
if (y == countres) break;
}
}
if (x < counta) {
res[countres] = a[elem];
countres++;
}
return countres;
}
int data[8] = {1,2,3,4,4,2,5,4};
int main(int argc, char **argv) {
int dups[8];
int count_dups = 0;
for(int x = 0; x < 8; x++) {
count_dups = search_dup(8, data, x, count_dups, dups);
}
for(int x = 0; x < count_dups; x++) {
printf("dup[%d]=%d\n",x,dups[x]);
}
}
translated with c2nim gives you:
proc search_dup*(counta: cint; a: ptr cint; elem: cint; countres: cint;
res: ptr cint): cint =
var x: cint = 0
while x < counta:
if x == elem: continue
if a[x] == a[elem]:
var y: cint = 0
while y < countres:
if res[y] == a[elem]: break
inc(y)
if y == countres: break
inc(x)
if x < counta:
res[countres] = a[elem]
inc(countres)
return countres
var data*: array[0..8 - 1, cint] = [1, 2, 3, 4, 4, 2, 5, 4]
proc main*(argc: cint; argv: cstringArray): cint =
var dups: array[0..8 - 1, cint]
var count_dups: cint = 0
var x: cint = 0
while x < 8:
count_dups = search_dup(8, data, x, count_dups, dups)
inc(x)
var x: cint = 0
while x < count_dups:
printf("dup[%d]=%d\x0A", x, dups[x])
inc(x)
which is obvious not valid nimrod code and contains a dangerous error. A naive translation to nimrod style arrays gives you:
proc search_dup*(a: openarray[int]; elem: int; res: var seq[int]) =
var x: int = 0
while x < a.len:
if x == elem: continue # this will create an endless loop
if a[x] == a[elem]:
var y: cint = 0
while y < res.len:
if res[y] == a[elem]: break
inc(y)
if y == res.len: break
inc(x)
if x < a.len:
res.add(a[elem])
var data*: array[0..8 - 1, int] = [1, 2, 3, 4, 4, 2, 5, 4]
proc main*() =
var dups: seq[int] = @[]
for x in 0..data.len-1:
search_dup(data, x, dups)
for x in 0.. dups.len-1:
echo "dup[",x,"]=",dups[x]
main()
but why don't I use a for loop? Now the search_dups proc looks pretty ;-)
proc search_dup*(a: openarray[int]; elem: int; res: var seq[int]) =
var x: int = 0
for x in 0..a.len-1:
if x == elem: continue
if a[x] == a[elem]:
var y: int = 0
for y in 0..res.len-1:
if res[y] == a[elem]: break
if y == res.len: break
if x < a.len:
res.add(a[elem])
and compiles without a single warning or error - BUT produces garbish since the loop variables are shadowed. IMHO such a behavior is dangerous and not desired, since if you look at the code it looks pretty sane - this is one of those nasty little bugs which slip in unseen when you translate from one language to another. I would wish, that the compiler does not allow the usage of a loop variable with the same name as an already declared local variable.
What do you think ?
Cheers and a Happy and Successful 2013
no --warning[ShadowIdent]:on does not work for loop variables - bug report created.
Is it planed to make warnings default - at least when compiled without -d:release ?
To disallow identifier shadowing used to be a bad feature for templates/macros; but this shouldn't be relevant anymore thanks to the hygienic macro system.
Most warnings are turned on by default; this new warning isn't because var x = x is an idiom in Nimrod (for instance, if you want to modify a parameter). I frequently use it to prevent bugs so that I can't accidentically access the old version. However, there is a rule to please both sides:
"Shadowing is disallowed unless the new identifier shadows an identifier occuring on the right side of the defining assignment". So var x = x-1 # make it 0-based is allowed, but var x = y-1 is not should an outer x already exist.
With this rule in place, the warning can become an error. Well, let's implement it and see. ;-)