# Rant: I hate that it's possible to iterate over an integer

**URL:** <https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645>\
**Category:** New to Julia\
**Created:** [March 9, 2022, 6:09pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645 "2022-03-09T18:09:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ForceBru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forcebru/32/21389_2.png) [@ForceBru](https://discourse.julialang.org/u/ForceBru)\
**Post date:** [March 9, 2022, 6:09pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/1 "2022-03-09T18:09:49Z")

</div>

Maybe this’ll be helpful to new users like myself. I’ve been writing Julia every day for about a year now. (and still considering myself new because I still haven’t had the time to learn the type system properly, for example), but I’m still getting bitten by this every once in a while.

Take a look at this code:

```julia
const AM = AbstractMatrix{T} where T

function expectations(P::AM{<:Real}, M::AM{<:Real}, V::AM{<:Real})
	a = @views sum(
		@. P[k, :] * M[k, :]
		for k ∈ size(P, 1)
	)
	sigma = @views sum(
		@. P[k, :] * sqrt(V[k, :])
		for k ∈ size(P, 1)
	)

	(; a, sigma)
end;

```

This code is supposed to compute expectations of some random variables _for each row_ in the matrices `P` (each column is a discrete probability distribution), `M` and `V`.

To me, it looks completely fine, and it also runs and outputs something that looks reasonable… sometimes.

Other times, however, it randomly returns some garbage that makes zero sense, depending on the order of rows in the input matrices, even though it’s supposed to be summing over them, so the order shouldn’t matter! Guess why?

Because `for k ∈ size(P, 1)` does **not** iterate over a range from one to `size(P, 1)`, as I intended!!! In fact, it iterates over _one single integer_ `size(P, 1)`, which boils down to selecting just _one_ last row of each matrix instead of summing over all rows. That’s super confusing!

Why would iterating _over an integer_ (as opposed to an array or a tuple of one integer) work at all without producing any errors?! I guess it works like this so that code like `Int(2.0)` and `Int.(2.0)` (notice broadcasting) produces the same result. So, this kind of makes sense, but it also just made me waste several hours (seriously) debugging my code and surrounding libraries because I was absolutely sure I most definitely couldn’t have messed up this simple `for` loop.

Yet it was exactly what I messed up.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [March 9, 2022, 6:19pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/2 "2022-03-09T18:19:32Z")

</div>

> I hate that it’s possible to iterate over an integer

Then you might be willing to do evil things:

```julia
import Base.iterate
iterate(t::T) where T<:Number = @assert false

v = 1
for i in size(v, 1)
end

```

---

<div class="post-metadata">

**Author:** ![ForceBru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forcebru/32/21389_2.png) [@ForceBru](https://discourse.julialang.org/u/ForceBru)\
**Post date:** [March 9, 2022, 6:35pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/3 "2022-03-09T18:35:59Z")

</div>

Right, and then you hit me with this:

> [@goerch](#):
>
> ```julia
> v = 1
> for i in size(v, 1)
> end
> 
> ```

Why would computing the `size` of a single number work? A size of something that is _not_ a collection? Turns out, `1234[1]` also “works” and evaluates to the number `1234` itself. Apparently, Julia treats numbers as arrays because numbers obey the collections “interface”:

- Indexing works: `1234[1] == 1234`
- Computing the length works: `length(1234) == 1`
- Computing the size works: `size(1234, 1) == 1`

However, _a number is not a collection_, IMO.

* * *

I just quickly tried some stuff out, and it looks like all primitive types behave as this kind of “collections of one element”:

```julia
julia> 1234[1], length(1234)
(1234, 1)

julia> true[1], length(true)
(true, 1)

julia> 'c'[1], length('c')
('c', 1)

julia> 1234.56[1], length(1234.56)
(1234.56, 1)

```

Okay, so Julia seems to be copying R here. Same thing in R:

```r
> c(1234[1], length(1234))
[1] 1234 1
> c(TRUE[1], length(TRUE))
[1] 1 1
> c('c'[1], length('c'))
[1] "c" "1"
> c(1234.56[1], length(1234.56))
[1] 1234.56 1.00

```

Yeah, it sort of makes sense, but at the same time leads to very subtle bugs like this one…

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [March 9, 2022, 6:42pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/4 "2022-03-09T18:42:46Z")

</div>

Yes, it is not ideal. Since I tripped on this, I have been using `(1,)` instead of just `1` in broadcast, so as to be more explicit, and also because if the behavior is changed in Julia 2.0 (one can hope) then my code changes would be minimal.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 9, 2022, 6:46pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/5 "2022-03-09T18:46:01Z")

</div>

> [@ForceBru](#):
>
> ```julia
> a = @views sum(
> @. P[k, :] * M[k, :]
> for k ∈ size(P, 1)
> )
> 
> ```

As a side note, you can do this faster using:

```julia
[sum(P[k, j] * M[k, j] for k ∈ 1:size(P, 1)) for j in 1:size(P,2) ]

```

because in the former you are allocating a new array in the bradcasting operation for every iteration of the `1:size(P,1)` loop:

```julia
julia> P = rand(100,100); M = rand(100,100);

julia> function test1(P,M)
          @views sum(@. P[k, :] * M[k, :] for k ∈ 1:size(P, 1) )
       end
test1 (generic function with 1 method)

julia> function test2(P,M)
          [sum(P[k, j] * M[k, j] for k ∈ 1:size(P, 1)) for j in 1:size(P,2) ]
       end
test2 (generic function with 1 method)

julia> test1(P,M) ≈ test2(P,M)
true

julia> @btime test1($P,$M);
  17.619 μs (199 allocations: 174.12 KiB)

julia> @btime test2($P,$M);
  9.282 μs (1 allocation: 896 bytes)

```

or _much_ faster with:

```julia
julia> using LoopVectorization

julia> function test3(P,M)
          r = zeros(size(P,1))
          @turbo for j in axes(P,2)
              for k in axes(P,1)
                  r[j] += P[k,j]*M[k,j]
              end
          end
          return r
       end
test3 (generic function with 1 method)

julia> @btime test3($P,$M);
  1.530 μs (1 allocation: 896 bytes)

```

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [March 9, 2022, 7:00pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/6 "2022-03-09T19:00:48Z")

</div>

Interestingly, VS Code linter shares your opinion:

![image](https://global.discourse-cdn.com/julialang/original/3X/2/f/2f31d60b64393a1a55febe861a80fea5f12018cd.png)

---

<div class="post-metadata">

**Author:** ![JonasWickman](https://avatars.discourse-cdn.com/v4/letter/j/9de0a6/32.png) [@JonasWickman](https://discourse.julialang.org/u/JonasWickman)\
**Post date:** [March 9, 2022, 8:35pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/7 "2022-03-09T20:35:17Z")

</div>

Coming from a Matlab background I’ve never felt this was strange (though I admit I sometimes have made the same mistake)

For reference, using this pattern might help avoid future headaches:

```julia
P = [1 2 3
     4 5 6
     7 8 9]
k = 2
for i ∈ axes(P,2)
    println(P[k,i])
end

```

Outputs:

```julia
4
5
6

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [March 9, 2022, 9:02pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/8 "2022-03-09T21:02:16Z")

</div>

Numbers are scalars. If someone were to ask me “how many dimensions does a scalar have?”, I would answer that “a scalar has 0 dimensions”, not that the question is ill-posed (i.e. an error). Would you agree with that?

I think if we can agree that scalars are zero dimensional and that numbers are scalars, then this behaviour under iteration is pretty unambiguous and natural.

The length of a container is product of the size of all of it’s dimensions. The product of an empty list (zero dimensions) is `1`. Hence, zero dimensional objects should have one element. What is that element in the case of a number? The number itself!

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [March 9, 2022, 9:08pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/9 "2022-03-09T21:08:04Z")

</div>

> [@lmiq](#):
>
> or _much_ faster with:

Something else I want to highlight there is:

```julia
julia> using LoopVectorization

julia> function test3(P,M)
          r = zeros(size(P,1))
          @turbo for j in axes(P,2)
              for k in axes(P,1)

```

that you used `axes` instead of `1:size`.  
`axes` is much better and should be preferred as a rule. The two main advantages: support for `OffsetArray`s and avoiding bugs like the one this thread is about!  
(Also pointed out by JonasWickman above.)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 9, 2022, 9:13pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/10 "2022-03-09T21:13:30Z")

</div>

> [@ForceBru](#):
>
> `for k ∈ size(P, 1)`

While your main point stands, you should never use `size` in places like this. Always `axes` or `eachindex` or `pairs`.

---

<div class="post-metadata">

**Author:** ![ForceBru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forcebru/32/21389_2.png) [@ForceBru](https://discourse.julialang.org/u/ForceBru)\
**Post date:** [March 9, 2022, 9:14pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/11 "2022-03-09T21:14:11Z")

</div>

True, I actually didn’t know about `axes`

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [March 9, 2022, 9:19pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/12 "2022-03-09T21:19:37Z")

</div>

> [@Mason](#):
>
> I would answer that “a scalar has 0 dimensions”.

Hm, corresponds to my intuition. But can we eliminate the special cases for

```julia
dims(t::T) where {T} = 0
dims(t::Array{T, N}) where {T, N} = N

@show dims(1)
@show dims([1;])
@show dims([1;;])
@show dims([1;;;])

```

then? Also

```julia
@show Array{Int, 0}(1)
@show Int <: Array{Int, 0}

```

are questionable…

---

<div class="post-metadata">

**Author:** ![ForceBru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forcebru/32/21389_2.png) [@ForceBru](https://discourse.julialang.org/u/ForceBru)\
**Post date:** [March 9, 2022, 9:27pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/13 "2022-03-09T21:27:14Z")

</div>

Yes, this looks totally reasonable. However, it seems strange from the point of view of… programming, I guess? I’m used to iterating over _collections_, but a single number isn’t really a collection, as opposed to an array that contains one number. At the same time, it kind of _is_ a collection because of the scalar/vector/matrix/tensor analogy.

Other languages (excluding Julia and R as mentioned in one of my previous comments) don’t treat numbers or other primitive types as collections of one element, and this makes perfect sense to me.

* * *

Python:

```python
>>> for i in 1:
... ...
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable

```

It explicitly tells me that it doesn’t make sense to iterate over a single integer.

* * *

[Rust](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=81d5d3f3c1db3460e407191f25002173):

```rust
fn main() {
    for i in 1 {
        println!("hey");
    }
}

```

Error message:

```nohighlight
error[E0277]: `{integer}` is not an iterator
 --> src/main.rs:2:14
  |
2 | for i in 1 {
  | ^ `{integer}` is not an iterator
  |
  = help: the trait `Iterator` is not implemented for `{integer}`
  = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
  = note: required because of the requirements on the impl of `IntoIterator` for `{integer}`

```

It also explicitly tells me that it doesn’t make sense to iterate over an integer.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [March 9, 2022, 9:27pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/14 "2022-03-09T21:27:23Z")

</div>

> [@goerch](#):
>
> Hm, corresponds to my intuition. But can we eliminate the special cases for
> 
> ```julia
> dims(t::T) where {T} = 0
> dims(t::Array{T, N}) where {T, N} = N
> 
> @show dims(1)
> @show dims([1;])
> @show dims([1;;])
> @show dims([1;;;])
> 
> ```

I don’t really understand the point you’re trying to make here. Could you elaborate?

> [@goerch](#):
>
> `@show Int <: Array{Int, 0}`

Why would this be true? We have lots of zero dimensional containers. E.g. `Ref`:

```julia
julia> ndims(Ref(1))
0

julia> size(Ref(1))
()

julia> [x for x in Ref(1)]
0-dimensional Array{Int64, 0}:
1

```

yet it’s not an `Array`

```julia
julia> Ref{Int} <: Array{Int, 0}
false

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [March 9, 2022, 9:30pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/15 "2022-03-09T21:30:55Z")

</div>

> [@ForceBru](#):
>
> [Rust](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=81d5d3f3c1db3460e407191f25002173):
> 
> ```julia
> fn main() {
> for i in 1 {
> println!("hey");
> }
> }
> 
> ```
> 
> Error message:
> 
> ```julia
> error[E0277]: `{integer}` is not an iterator
> --> src/main.rs:2:14
> |
> 2 | for i in 1 {
> | ^ `{integer}` is not an iterator
> |
> = help: the trait `Iterator` is not implemented for `{integer}`
> = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
> = note: required because of the requirements on the impl of `IntoIterator` for `{integer}`
> 
> ```
> 
> It also explicitly tells me that it doesn’t make sense to iterate over an integer.

Well, Rust doesn’t tell you that it doesn’t make sense, it tells you that this is an error because the `Iterator` trait hasn’t been implemented for `{integer}`. In julia, we _have_ [implemented that trait](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration).

```julia
julia> Iterators.IteratorEltype(Int)
Base.HasEltype()

julia> iterate(1)
(1, nothing)

```

I guess I just don’t find the argument persuasive that we should do what other languages do here. If you multiply two matrices in Python and a bunch of other languages with `*` it does elementwise multiplication, which is frankly insane IMO.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [March 9, 2022, 9:32pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/16 "2022-03-09T21:32:10Z")

</div>

> [@Mason](#):
>
> I don’t really understand the point you’re trying to make here. Could you elaborate?

This doesn’t work without `dims(t::T) where {T} = 0` so numbers are not zero dimensional arrays…  
OTOH zero dimensional array are at least not syntactically invalid, so how to instantiate one and what does that mean?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [March 9, 2022, 9:33pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/17 "2022-03-09T21:33:29Z")

</div>

> [@goerch](#):
>
> This doesn’t work without `dims(t::T) where {T} = 0` so numbers are not zero dimensional arrays…  
> OTOH zero dimensional array are at least not syntactically invalid, so how to instantiate one and what does that mean?

Numbers aren’t zero dimensional arrays because they’re not arrays. Arrays are not the only containers in the language.

They are zero dimensional objects though.

```julia
help?> ndims
search: ndims RoundingMode ENDIAN_BOM

  ndims(A::AbstractArray) -> Integer

  Return the number of dimensions of A.

  See also: size, axes.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> A = fill(1, (3,4,5));

  julia> ndims(A)
  3

julia> ndims(1)
0

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [March 9, 2022, 9:40pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/18 "2022-03-09T21:40:33Z")

</div>

> [@goerch](#):
>
> OTOH zero dimensional array are at least not syntactically invalid, so how to instantiate one and what does that mean?

I don’t think there’s any real intended way to make them, but here’s one thing you can do: make a list comprehension iterating over a number!

```julia
julia> A = [x for x in 1]
0-dimensional Array{Int64, 0}:
1

```

Now you have a zero dimensional array containing that number, and you can do whatever you want with it:

```julia
julia> A[1]
1

julia> ndims(A)
0

julia> A[1] = 2;

julia> A
0-dimensional Array{Int64, 0}:
2

```

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 9, 2022, 9:48pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/19 "2022-03-09T21:48:49Z")

</div>

But

```julia
julia> a = 1
1                                                                 
                                                                  
julia> axes(a, 1)
Base.OneTo(1)                                                     
                                                                  
julia> 

```

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [March 9, 2022, 9:51pm UTC](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645/20 "2022-03-09T21:51:18Z")

</div>

Does `axes` really help?

```julia
julia> a = 1
1       
julia> for k in size(a, 1)
       println(k)
       end
1                                                                 
                                                                  
julia> for k in axes(a, 1)                                        
       println(k)                                                 
       end                                                        
1                                                                 
                                                                  
julia> 

```

[Next page](https://discourse.julialang.org/t/rant-i-hate-that-its-possible-to-iterate-over-an-integer/77645.md?page=2)
