Generic way to turn mutating into nonmutating functions?


#1

Hi!
I want to use functions like deleteat! or insert! without mutating whatever they work on.
Concretely, I have vectors where I replace two neighboring values by their sum which I thought I’d achieve with

vec = [1:10...]
indices = [3;4]
newvec = deleteat!(insert!(vec,max(indices)+1,sum(vec[indices])),indices);

but I still need the original vector.
If someone can tell me how to do it more readable, I’d appreciate that too.

Anyway, I guess a solution would be to use copy, i.e.

newvec = copy(vec)
newvec = deleteat!(insert!(newvec,max(indices)+1,sum(newvec[indices])),indices);

but that makes my code a lot less readable since I’m mapping this operation over an iterator of dictionary keys so the whole thing turns into a monster like

map(x->deleteat!(insert!(x,max(indices)+1,sum(x[indices])),indices), copy(keys(somedict)))

which doesn’t even work because I can’t copy KeyIterators and I’d rather not collect all keys beforehand.

Any ideas? I’m a bit irritated by all the functions that aren’t available side-effect free such as push!, pop!, insert!, etc. but maybe I’m just missing something.

Thanks!


#2

What about

sum_adjacent(v, i) = vcat(v[1:(i-1)], v[i] + v[i+1], v[(i+2):end])

sum_adjacent(1:10, 3)

#3

Thanks, that’s way more readable.
I still prefer the insert/deleteat method since it allows easier generalisation for non-neighboring values but for the specification I gave in my post that’s great!

This leaves open the question of whether there’s a straightforward way to get mutating functions without side-effects (maybe by some Macro that inserts copy or deepcopy automatically in the mutating functions?)

Cheers


#4

I am at loss to understand why you would want to start with mutating functions then turn them into non-mutating ones. I don’t see any performance gains in doing so, and it will lead to really convoluted code, instead of a simple solution. Bringing macros into it does not look necessary (from what I have seen so far).

The solution with non-mutating forms should be easy to generalize. I am very happy to help if you describe what you need.


#5

Dear Tamas

My situation was like this: I needed a functionality such as e.g. remove an element at a certain position and I wanted it to be non-mutating since I prefer functions without side effects. In the documentation I only found functions such as deleteat! or pop! that mutate my array.

Of course I could always just copy the array I work on first, then use those functions and have the same functionality but I thought that since that must be a quite common use-case - working on data you don’t want to modify and instead save the modified data in another variable - there might be a julian way to do it.

For the problem at hand I used your suggestion above which works fine and is very readable, thanks for that!