Bug - Fixed Array Initialization in a Loop Doesn't Update

Stewbeef

New member
So I made a little function to find/replace words and bold them. You pass it text and a string[int] array and then it iterates over each %s it finds and each words replacing them one by one. (So "%s is a good %s" with {"fido","dog"} would become "fido is a good dog")

However, there seems to be a bug with how initialization happens for an array within a loop.

(Safeguard_Array() just returns a map in the form int [string,item]).* This whole function is just to handle preveting some items from getting PVP'd, selling other items, etc.

Consider the following:

Code:
foreach it in Safeguard_Array()[type]
{
	string itname = it.to_string();
	string numstr = Safeguard_Array()[type,it].to_string();
	string[int] word_array;
	word_array[0] = itname;
	word_array[1] = type;
	word_array[2] = numstr;
	print_html("%s, %s all but %s", word_array);
}

vs.

Code:
foreach it in Safeguard_Array()[type]
{
	string[int] word_array;
	word_array = string[int]{it.to_string(),type,Safeguard_Array()[type,it].to_string()};
	print_html("%s, %s all but %s", word_array);
}

These should be provide identical output. However, what I get is the following (bolded not included)..

For the first one:
Code:
seal-clubbing club, junk all but 0
disco mask, junk all but 0
moxie weed, junk all but 0
strongness elixir, junk all but 0
magicalness-in-a-can, junk all but 0

For the second:
Code:
seal-clubbing club, junk all but 0
seal-clubbing club, junk all but 0
seal-clubbing club, junk all but 0
seal-clubbing club, junk all but 0

This is still true if I change the second bit of code so that all of its elements are initialized as variables first outside of the array initialization (e.g. they are initialized like the first bit of code, then the array is initialized all at once).

Makes things take up more space, but at least there's a workaround.

*I use this to load from a file if the array in memory doesn't have anything in it, otherwise it returns the array in memory.
 
Last edited:

Veracity

Developer
Staff member
Yeah.

Code:
for i from 1 to 10 {
    int [] arr = { i, i, i };
    print( "arr " + i + " = { " + arr[0] + " , " + arr[1] + ", " + arr[2] + "}" );
}
yields:

Code:
[color=green]> albug[/color]

arr 1 = { 1 , 1, 1}
arr 2 = { 1 , 1, 1}
arr 3 = { 1 , 1, 1}
arr 4 = { 1 , 1, 1}
arr 5 = { 1 , 1, 1}
arr 6 = { 1 , 1, 1}
arr 7 = { 1 , 1, 1}
arr 8 = { 1 , 1, 1}
arr 9 = { 1 , 1, 1}
arr 10 = { 1 , 1, 1}

and this:

Code:
for i from 1 to 10 {
    int [] arr = { i, i * 2, i * 3 };
    print( "arr " + i + " = { " + arr[0] + " , " + arr[1] + ", " + arr[2] + "}" );
}
yields:

Code:
[color=green]> albug2[/color]

[color=red]Expected }, found * (albug2.ash, line 2)[/color]
The issue is that array literals were originally coded to allow only constants. Thus, {1, 2, 3}. Seeing them as the equivalent of plural typed constants, I made array literals constants too: you only needed to initialize them once. Later, I extended the syntax to allow you to use variable references in there too: { x, y, z }.

1) It never made sense for them to be constants; why shouldn't you be able to initialize them and then change them and then (as in your loop), initialize them again?
2) Why not expressions, rather than variable references?

I'll fix these things.
 

Linknoid

Member
Not going to comment on how this should work. I'll say that I came across basically the same questions: what happens when you assign maps? Are they by reference, or by value? So if I pass in a map and modify it, is the original modified as well?

Then I realized that I could just not care. Rather than coding in a way that assumes a specific behavior, I can just code assuming it could behave either way, and it won't matter how it behaves.

You're writing code and assuming it should work one way, but there might be dozens of active scripts that depend on the current behavior. Let's say it's agreed this is a bug and should be changed, but then the change gets deployed, and it breaks half the active scripts out there in subtle ways that don't get noticed for a while. Then someone else brings up a legitimate point about how it really needs the prior behavior, so it gets reverted. Now everyone who was using the new behavior has broken scripts again.

I don't know how likely such a change in behavior is likely to occur, but it is best to code in a way that won't break because some of the more obscure mechanics of the language changed. In this case, your first example is much more likely to work forever more than your second example.
 

Veracity

Developer
Staff member
Code:
[color=green]> albug.ash[/color]

arr 1 = { 1 , 1, 1}
arr 2 = { 2 , 2, 2}
arr 3 = { 3 , 3, 3}
arr 4 = { 4 , 4, 4}
arr 5 = { 5 , 5, 5}
arr 6 = { 6 , 6, 6}
arr 7 = { 7 , 7, 7}
arr 8 = { 8 , 8, 8}
arr 9 = { 9 , 9, 9}
arr 10 = { 10 , 10, 10}

[color=green]> albug2.ash[/color]

arr 1 = { 1 , 2, 3}
arr 2 = { 2 , 4, 6}
arr 3 = { 3 , 6, 9}
arr 4 = { 4 , 8, 12}
arr 5 = { 5 , 10, 15}
arr 6 = { 6 , 12, 18}
arr 7 = { 7 , 14, 21}
arr 8 = { 8 , 16, 24}
arr 9 = { 9 , 18, 27}
arr 10 = { 10 , 20, 30}
Revision 18454.
 

Veracity

Developer
Staff member
Not going to comment on how this should work. I'll say that I came across basically the same questions: what happens when you assign maps? Are they by reference, or by value? So if I pass in a map and modify it, is the original modified as well?
Maps are passed by reference.

You're writing code and assuming it should work one way, but there might be dozens of active scripts that depend on the current behavior. Let's say it's agreed this is a bug and should be changed, but then the change gets deployed, and it breaks half the active scripts out there in subtle ways that don't get noticed for a while. Then someone else brings up a legitimate point about how it really needs the prior behavior, so it gets reverted. Now everyone who was using the new behavior has broken scripts again.
The previous way, if you initialized an array or map with a literal - { a, y, z } - you could not change that map. Therefore, all currently working scrips that use that kind of literal do not try to change the map. After the change, they are still not trying to change the map, and they will continue to work as before.

Now, were there scripts that depended on the bug? They initialize a map to a literal value using variables, not constants, they don't modify the values (because they couldn't), and then the initialize it again, but the variables have changed - and they expect to see the values from the first time they initialized it?

Seems unlikely.
 

Veracity

Developer
Staff member
By the way - if somebody really wants a map that gets initialized only once (even if the initialization appears in a loop), they can declare it "static".

Code:
for i from 1 to 10 {
    static int [] arr = { i, i, i };
    print( "arr " + i + " = { " + arr[0] + " , " + arr[1] + ", " + arr[2] + "}" );
}
yields

Code:
[color=green]> albug3.ash[/color]

arr 1 = { 1 , 1, 1}
arr 2 = { 1 , 1, 1}
arr 3 = { 1 , 1, 1}
arr 4 = { 1 , 1, 1}
arr 5 = { 1 , 1, 1}
arr 6 = { 1 , 1, 1}
arr 7 = { 1 , 1, 1}
arr 8 = { 1 , 1, 1}
arr 9 = { 1 , 1, 1}
arr 10 = { 1 , 1, 1}
 
Top