# Can we explain why using Nothing twice on a list does not operate twice?

Below I generate a list of numbers between 1 and 15. I then set the value at position 10 to Nothing and as expected the value at position 10 is changed. This is as expected.

   In[1]:= b = Range[15]
b[[10]] = Nothing;
b
b[[10]]

Out[1]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

Out[3]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15}

Out[4]= 11


So far so good. However, if I do this again then nothing happens, the list is unaltered. I was expecting to have the value now at position 10 removed.

In[5]:= b[[10]] = Nothing;
b
b[[10]]

Out[6]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15}

Out[7]= 11


Can anyone explain this? Thanks

"13.0.1 for Microsoft Windows (64-bit) (January 28, 2022)"

• Oh that is strange. You can continue the process: do b[[9]] = Nothing; Print[b]; b[[9]] = Nothing; b and the same thing happens. But perhaps Nothing is not meant to be used this way? Mar 13, 2023 at 17:12

Take a look at Definition[b].

b = Range[15];
Definition[b]
(* b={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} *)

b[[10]] = Nothing;
Definition[b]
(* b={1,2,3,4,5,6,7,8,9,Nothing,11,12,13,14,15} *)


When you set element 10 to Nothing, the list retains its shape, just its definition changes so that the 10th element is Nothing. Whenever symbol b is then used (evaluated), this Nothing gets stripped away.

Trace[b] // Column
(* b
{1,2,3,4,5,6,7,8,9,Nothing,11,12,13,14,15}
{1,2,3,4,5,6,7,8,9,11,12,13,14,15} *)

Trace[b[[10]]] // Column
(* {b,{1,2,3,4,5,6,7,8,9,Nothing,11,12,13,14,15},{1,2,3,4,5,6,7,8,9,11,12,13,14,15}}
{1,2,3,4,5,6,7,8,9,11,12,13,14,15}[[10]]
11 *)

• A very useful and informative analysis. The Trace[b[[10]]]is particular revealing about how things work. Thanks.
– Hugh
Mar 13, 2023 at 20:02

[Based on the timestamp, it looks like Domen's answer has priority. I'm leaving my answer, because I think it adds some extra flavor, but I don't think there is sufficient reason for these answers to be in competition. I.e. if one of these is to be selected as "the answer", it should be Domen's based on priority.]

Look at Information["b"]. I'm assuming that this is working as expected. The token Nothing is just an expression like everything else. It just gets interpreted specially when it's in a list. So, when you evalute b[[10]] = Nothing, you are literally assigning the 10th element of b to Nothing. Now, whenever you subsequently evaluate b, that Nothing gets interpreted and the result is a list that's missing the 10.

You could re-assign the 10th element of b if you want (you actually did this, you just re-used the same value though):

b = Range[15]


{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

b[[10]] = Nothing;
b


{1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15}

b[[10]] = 99999;
b


{1, 2, 3, 4, 5, 6, 7, 8, 9, 99999, 11, 12, 13, 14, 15}

Interestingly, if you evaluated b = b at some point, this would change the actual definition of b to be a list without the Nothings.

UPDATE

I thought it would be worth explicitly showing the b = b evaluation, because I think that might clarify some issues that have come up in comments. So, from the top:

b = Range[15]


{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

b[[10]] = Nothing;
OwnValues[b]


{HoldPattern[b] :> {1, 2, 3, 4, 5, 6, 7, 8, 9, Nothing, 11, 12, 13, 14, 15}}

Length[b]


14 <- This is because b was evaluated, and during evaluation Nothing was removed.

(OwnValues[b] /. List -> Hold)[[1, 2]]


Hold[1, 2, 3, 4, 5, 6, 7, 8, 9, Nothing, 11, 12, 13, 14, 15]

Length@%


15 <- The point here is Nothing doesn't affect the computation of Length.

b = b


{1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15} <- The right hand side was evaluated, and the result of that evaluation was assigned to b. We can then see that b has indeed changed:

OwnValues[b]


{HoldPattern[b] :> {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15}}

• These extra investigations are helpful. I am not clear of the effect on PackedArrays. Is that also worth exploring?
– Hugh
Mar 13, 2023 at 20:10