View Issue Details

IDProjectCategoryView StatusLast Update
0000572LDMud 3.6Generalpublic2022-10-06 20:48
Reporterwarp Assigned ToGnomi  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionduplicate 
Product Version3.3.717 
Summary0000572: Assigning empty array to array slice in functions
DescriptionThe behaviour for assigning to arrays which are not explicitely passed by reference in functions is inconsistent. Assigning to a single element will modify the passed array, assigning to a slice will not modify it.

Example:

public void var1( mixed tmp) {
  tmp[0] = "test1";
}

public void var2( mixed tmp) {
  tmp[0..0] = ({ "test2" });
}

public void var3( mixed tmp) {
 tmp[0..0] = ({});
}

All examples assume: mixed arr= ({ 1, 2, 3 });

var1(arr); // arr is now "element", 2, 3
var2(arr); // arr is now "test2", 2, 3
var3(arr); // arr is now still 1, 2, 3

Assigning the empty array to delete the first element is not possible in a function.
It works though, if no function calls are involved:

mixed arr= ({ 1, 2, 3 });
arr[0..0]= ({}); // arr is no 2, 3

It would be nice if this could be made consistent (so that assigning empty arrays works inside the function, too) as this would e.g. allow to create shift/unshift/push/pull simul efuns without the need for reference-syntax


TagsNo tags attached.

Relationships

duplicate of 0000299 assignedGnomi LDMud 3.5 Redesigning mappings, arrays, lvalues 

Activities

warp

2008-09-11 09:33

reporter   ~0000783

Ah, it seems variant2 only works because [0..0] is effectively treated like [0] - assigning non-empty arrays would still copy the array instead of modifying the original array for [0..1]

So this probably is no bug but actually a feature request whether [start..end] could modify the original array, too, like [index] does, without explicit pass-by-reference

zesstra

2009-01-18 14:05

administrator   ~0000929

Yes, thats right. Everytime a new array is created in the process, the original one will be left unchanged. And a new array is created every time the array changes its length...
I am not sure if that is easily changeable by tuning the compiler and the implementation of the slicing operator - I guess not.
There is a feature request to improve the array implementation in a way that length changes do not alway involve the creation of a new array. But then we may introduce a non-deterministic behaviour for the LPC programmer, if some length changes involve the creation of a new array and some not and something relies on it..

And additionally: I am very sceptical if we _should_ change this behaviour. Because it was the standard array behaviour for many years, wizards got used to expect it - in MorgenGrauen I know several pieces of old code, which actually use return arr[0..] to return a shallow copy instead of the original array... (I know, I know...)
This is not like changing a rarely used efun or its interface, because the code will work and there will be no warning - but data corruption which may be difficult to detect and trace.

fufu

2009-01-18 15:42

manager   ~0000930

For the record, it's resizing the array that causes the reference to "break", because the array is copied:

tmp[0..1] = ({ 0, 1 }); // modifies the original array.
tmp[0..1] = ({ 0, 1, 2 }); // creates a copy of the array.

I agree with Zesstra that it's too late to change this behaviour. (If we wanted to change anything, I'd vote for slice assignments to always copy the array.)

zesstra

2009-01-18 16:56

administrator   ~0000931

I tend towards Fuchur, but that will probably also break enough code, which now trust on the slicing operator _not_ to copy in some circumstances. Difficult... Im pretty sure, some people used it to save a bit of execution time (but it may not be that tiny in case of big arrays, if we change it...)
I would not like to change all the tmp[0..1] = ({ 0, 1 });

warp

2009-01-19 05:21

reporter   ~0000932

I see, this is of course understandable. From a consistency point of view, a change in one direction or the other would be nice, but of course, with all the large codebases around, I see that it's not that easily changed.

zesstra

2009-05-10 15:37

administrator   ~0001098

I am transfering this to 3.5, because I do really recommend not to change the behaviour in the one or other direction in 3.3. There will be enough code to break in nasty ways by this...

Gnomi

2022-10-06 20:30

manager   ~0002700

Last edited: 2022-10-06 20:36

Next step: Add pragma (default on) to warn when array operations (slice assignment, operator assignments) create a new array and the original array has more than one reference (i.e. when the behavior would be different with an array with pure reference semantics). Also warn on comparisons with the empty array (==, !=, member, in, -=, &=, mapping lookup).

zesstra

2022-10-06 20:48

administrator   ~0002701

We are closing this issue because it is a duplicate of the older 0000299.
We will check for the feasibility of a change of behaviour in 3.7 and follow-up with 0000299.

Issue History

Date Modified Username Field Change
2008-09-11 09:06 warp New Issue
2008-09-11 09:33 warp Note Added: 0000783
2009-01-18 14:05 zesstra Note Added: 0000929
2009-01-18 15:42 fufu Note Added: 0000930
2009-01-18 16:56 zesstra Note Added: 0000931
2009-01-19 05:21 warp Note Added: 0000932
2009-05-10 15:37 zesstra Note Added: 0001098
2009-05-10 15:37 zesstra Project LDMud 3.3 => LDMud 3.5
2018-01-29 22:29 zesstra Project LDMud 3.5 => LDMud 3.6
2018-01-29 22:29 zesstra Category LPC Language => General
2018-02-04 00:19 Gnomi Relationship added duplicate of 0000299
2022-10-06 20:30 Gnomi Assigned To => Gnomi
2022-10-06 20:30 Gnomi Status new => assigned
2022-10-06 20:30 Gnomi Note Added: 0002700
2022-10-06 20:36 Gnomi Note Edited: 0002700
2022-10-06 20:48 zesstra Status assigned => closed
2022-10-06 20:48 zesstra Resolution open => duplicate
2022-10-06 20:48 zesstra Note Added: 0002701