# Why isn't there a non-! version of deleteat!()?

**URL:** <https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355>\
**Category:** New to Julia\
**Tags:** abstractvector\
**Created:** [December 2, 2024, 12:50pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355 "2024-12-02T12:50:17Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![francisbarton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francisbarton/32/205194_2.png) [@francisbarton](https://discourse.julialang.org/u/francisbarton)\
**Post date:** [December 2, 2024, 12:50pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/1 "2024-12-02T12:50:17Z")

</div>

I just used the following bit of code in an Advent of Code puzzle, to sequentially alter a vector by removing one of its elements in turn:

```julia
deleteat!(copy(r), i) for i in 1:length(r)

```

I believe I had to use `copy()` here, because the only available version of `deleteat()` is the modifying version with `!`.

I get that there are various workarounds to this, but my n00b question is just simply: _why_ would there be only a modifying function in base Julia, and no ‘standard’ version of the function available? (I think there are lots of other functions that seem to only have `!` versions, too).

Why doesn’t Julia want me to do

```julia
deleteat(r, i) for i in 1:length(r)

```

?

I’m used to being able to do this in R with `[` and a negative index, like this:

```julia
lapply(seq_along(x), \(i) x[-i])

```

but I don’t think Julia supports negative indices like this?

Thanks!

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 2, 2024, 12:56pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/2 "2024-12-02T12:56:07Z")

</div>

> [@francisbarton](#):
>
> but I don’t think Julia supports negative indices like this?

There are packages that will do this, e.g. see InvertedIndices.jl or the `@delete` macro from Accessors.jl.

See also previous discussions:

- [Equivalent of np.delete?](https://discourse.julialang.org/t/equivalent-of-np-delete/122642)
- [Elegant way of exclusive indexing](https://discourse.julialang.org/t/elegant-way-of-exclusive-indexing/76894)
- [Matrix indexing](https://discourse.julialang.org/t/matrix-indexing/70057)
- [Accessing every elements of an array except a certain range](https://discourse.julialang.org/t/accessing-every-elements-of-an-array-except-a-certain-range/55173)

---

<div class="post-metadata">

**Author:** ![francisbarton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francisbarton/32/205194_2.png) [@francisbarton](https://discourse.julialang.org/u/francisbarton)\
**Post date:** [December 2, 2024, 1:11pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/3 "2024-12-02T13:11:30Z")

</div>

Thank you @stevengj - I haven’t even started to explore the world of Julia packages yet! Good to know.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [December 2, 2024, 1:48pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/4 "2024-12-02T13:48:23Z")

</div>

Note, if you’re only deleting from the front or the back of an array (repeatedly, even for any order of interleaving such), then you may consider using a `view`, that only makes it look like you deleted anything. (`push!`, and `pushfirst!`, even, are also often fast, i.e. with a constant factor. See `sizehint!`.)

But in general if you `delete!` from or `insert!` **info** an array anywhere else it’s inherently a mutating operation, and `!` signals that.

Even for:

> [@stevengj](#):
>
> the `@delete` macro from [Accessors.jl](https://juliahub.com/ui/Packages/General/Accessors).

I.e. there `!` is not used, since you make a _copy_ that is then _mutated_ (at least conceptually), so not having `!` is correct, but somewhat misleading if you think non-mutation is inherently faster. `deleteat!` can be faster than it, because it doesn’t need to copy everything, maybe only shift a few elements, at worst half of them.

> [@francisbarton](#):
>
> I don’t think Julia supports negative indices like this?

It doesn’t since it is slower, means inherently a conditional test.

It’s of course good to explore packages, please do, and make PRs to Julia docs if you feel something missing or can be clarified, e.g. if they should propose some package to look at. In general Julia is fast~~[est]~~ [EDIT: sorry, need to heavily qualify fastest, to the point of best not saying it…, what I meant to say Julia is always fast, and _with some exceptions_ as fast as possible, not meaning outside code can never be as fast] with what you get in the standard library. There are some exceptions, e.g. for Rationals and BigFloat, but no other types I recall (at least not the primitive ones). Well there are also faster String types available (for e.g. limited sized-strings, same as the faster fixed-sized arrays live in different packages), but eventually Julia’s should have short-string optimization, as part of Julia’s default String (IMHO).

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 2, 2024, 3:55pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/5 "2024-12-02T15:55:18Z")

</div>

> [@Palli](#):
>
> In general Julia is fast[est] with what you get in the standard library.

No. The **whole point of Julia is that the standard library is not privileged** — user defined types and functions can be just as fast as “built-in” ones.

There are lots of packages implementing high performance functions, _often_ beating compositions of stdlib functions!

The simple fact is that the standard library is finite. There are plenty of useful functions it doesn’t contain. And there are downsides to including something in the standard library as opposed to a package. Not only can package development be more rapid, but packages are more free to explore different APIs than the standard library (which is locked in by backwards compatibility for all 1.x releases).

It’s not clear what the best API for “negative” indexing is so this is a good topic for packages.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [December 2, 2024, 4:09pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/6 "2024-12-02T16:09:20Z")

</div>

I think it’s also worth noting that the verbs **delete** and **pop** read to me — at an English language level — as being _very_ mutation-y. And they frequently _are_ the names of the mutating operations in other languages.

It’s somehow easier for me to take a non-mutating verb and making it mutating with a `!` than it is to go the other way.

---

<div class="post-metadata">

**Author:** ![francisbarton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francisbarton/32/205194_2.png) [@francisbarton](https://discourse.julialang.org/u/francisbarton)\
**Post date:** [December 2, 2024, 5:18pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/7 "2024-12-02T17:18:51Z")

</div>

Thanks everyone, very helpful answers. And not too scary - this is the “New to Julia” section after all!

I don’t know whose answer to mark as a solution, but of course I take @stevengj 's point that the Base library has to have finite limits.  
Which is as good an answer to my “why?” question as any.

For what it’s worth, the motivation behind the question is really trying to smooth out the differences between my R-shaped mental model and the way things are in Julia. On the whole I have found it pretty easy to move across, so far.

I was thinking that the modifying functions with `!` would tend to be variants of other ‘vanilla’ functions that don’t have the `!`. But that is not the case.

In R, as I put in my example above, I can iterate over `x` to produce various versions of `x[-i]` but x will still be the same. I now know some more ways to replicate that in Julia - thanks again.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [December 3, 2024, 3:12pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/8 "2024-12-03T15:12:38Z")

</div>

One of my favorite things about Julia is how easy it is to make a new `AbstractArray` to perform some specific functionality. Just take a quick look at [the array interface](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array) and then you can implement your own in just a few lines:

```julia
struct VectorExcept{T, V<:AbstractVector{T}} <: AbstractVector{T}
	v::V
	except::Int
	# TODO: constructor should check `Base.require_one_based_indexing(v)`
end

# here I treat out-of-bounds `except` as nothing excepted
Base.IndexStyle(::Type{<:VectorExcept}) = IndexLinear()
Base.size(x::VectorExcept) = (size(x.v,1) - (1 <= x.except <= size(x.v,1)),)
Base.getindex(x::VectorExcept, i::Int) = getindex(x.v, i + (1 <= x.except <= i))
Base.setindex!(x::VectorExcept, y, i::Int) = setindex!(x.v, y, i + (1 <= x.except <= i))

```

```julia-repl
julia> VectorExcept(11:16, 2)
5-element VectorExcept{Int64, UnitRange{Int64}}:
 11
 13
 14
 15
 16

julia> [VectorExcept(1:4, i) for i in 1:4]
4-element Vector{VectorExcept{Int64, UnitRange{Int64}}}:
 [2, 3, 4]
 [1, 3, 4]
 [1, 2, 4]
 [1, 2, 3]

```

This doesn’t even need to make a new array. It just reads the original one while pretending that one of the entries has been deleted. But just note that mutating the `VectorExcept` will mutate the underlying array too. Maybe I shouldn’t have provided `setindex!`?

---

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [December 6, 2024, 12:29pm UTC](https://discourse.julialang.org/t/why-isnt-there-a-non-version-of-deleteat/123355/9 "2024-12-06T12:29:41Z")

</div>

In [this thread](https://discourse.julialang.org/t/elegant-way-of-exclusive-indexing/76894/41) i posed a related question, and also arrived at the conclusion that we need a non-mutating version of `deleteat!`. That thread goes into quite a lot of detail showing how users might be tempted to implement this themselves, which to me showcases the “danger” of not providing this functionality out of the box.

While I agree that it is weird to have a non-mutating version of `deleteat!`, just conceptually, there is no argument against it’s usefullness, which I think should come first. Especially given Julia’s strong conventions around using a bang to indicate mutation.
