# \`map\` should be more consistent

**URL:** <https://discourse.julialang.org/t/map-should-be-more-consistent/132559>\
**Category:** General Usage\
**Tags:** linearalgebra, map\
**Created:** [September 22, 2025, 10:14am UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559 "2025-09-22T10:14:55Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [September 22, 2025, 10:14am UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/1 "2025-09-22T10:14:55Z")

</div>

Dear all,

I wonder if it is proper to amend this behavior?

```julia
julia> map(_ -> 0, 0)
0

julia> struct Nvmber end

julia> Base.ndims(::Nvmber) = 0

julia> Base.length(::Nvmber) = 1

julia> Base.iterate(f::Nvmber) = (f, missing) # The `missing` here can be anything      

julia> Base.iterate(f::Nvmber, state) = nothing

julia> map(_ -> Nvmber(), Nvmber())
1-element Vector{Nvmber}:
 Nvmber()

julia> map(_ -> Nvmber(), 1)
Nvmber()

```

Note that `0` (or any numbers) is a ~~**point** in a Vector Space~~ scalar having `ndims(⋅) = 0`. So the outcome in the first line is `0`, which is **also** of `ndims` zero. So `map` is a “closed” operator on the number field (is this the correct term?).

But this pattern is not preserved in the penultimate command, where it returns a `Vector`—having `ndims(⋅) !== 0`, hence the `map` is no longer a “closed” operator. (The last command is correct, though, in terms of preserving `ndims`)

_Conclusion_: preserving `length` is not enough:

```julia
julia> length(0) == length([0]) == 1
true

```

since clearly `0` is very different from `[0]`. `map` should also preserve `ndims`, Maybe also preserving `axes` whenever applicable:

```julia
julia> axes(0)
()

julia> axes([0])
(Base.OneTo(1),)

```

Is there anyone willing to make a related pull request to amend this somehow? Thanks very much.

**PS** The original link is [here](https://discourse.julialang.org/t/is-there-a-reason-to-use-expression-i-think-its-redundant/131829/9), wherein are some discussions.  
By the way, I also found this (an 2018 link)[[Inconsistent behavior of map](https://discourse.julialang.org/t/inconsistent-behavior-of-map/14733)].

---

<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:** [September 22, 2025, 11:12am UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/2 "2025-09-22T11:12:15Z")

</div>

I agree this is undesirable. `map`’s generic method should be returning a container of the same `size` as the input, so here the sensible generic fallback would have likely been an `Array{Nvmber, 0}`.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [September 22, 2025, 12:45pm UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/3 "2025-09-22T12:45:12Z")

</div>

The issue here is just that the default `IteratorSize` for any type is `HasLength()`. If you overload `IteratorSize` and `size`, `map` indeed returns a 0d array:

```julia-auto
julia> Base.IteratorSize(::Nvmber) = Base.HasShape{0}()

julia> Base.size(::Nvmber) = ()

julia> map(_ -> Nvmber(), Nvmber())
0-dimensional Array{Nvmber, 0}:
Nvmber()

```

---

<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:** [September 22, 2025, 12:54pm UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/4 "2025-09-22T12:54:09Z")

</div>

Ah of course, I always forget about this annoying situation with `size` / `length` being totally independant of the defaults for `IteratorSize`

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [September 22, 2025, 1:21pm UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/5 "2025-09-22T13:21:49Z")

</div>

> [@simeonschaub](#):
>
> returns a 0d array

🥲Well, this probably isn’t what an user want either. A 0d array is strange in practice. I guess just the scalar is better. I’ll have to admit that it’s somewhat inconsistent. But I think this special method  
`map(f, x::Number, ys::Number...) = f(x, ys...)`  
makes more sense. And it’s much more straightforward.

```julia
julia> map(_ -> Nvmber(), Nvmber())
Nvmber()

julia> map((_, _) -> Nvmber(), Nvmber(), Nvmber())
Nvmber()

```

resembling

```julia
julia> map(_ -> 2, 1)
2

julia> map((_, _) -> 2, 1, 3)
2

```

Anyway, thank you.

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [September 22, 2025, 6:35pm UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/6 "2025-09-22T18:35:57Z")

</div>

There are options for what to return for `()`-shaped objects by default:

- a 0d array
- a `Ref`
- a scalar

Out of them, a 0d array probably follows the principle of least astonishment, because for non-empty-shaped collections `map` returns a correspondingly-shaped array. A `Ref` would probably work just as good with less overhead, though.

A scalar, I think, does add inconsistency, and special-casing numbers breaks an invariant `shape(map(f, x)) == shape(x)` if `f` returns a collection.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [September 22, 2025, 11:38pm UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/7 "2025-09-22T23:38:03Z")

</div>

Numbers are indeed very special

```julia
julia> import JuMP

julia> x = JuMP.@variable(JuMP.Model()) # a decision scalar
_[1]

julia> x[]
ERROR: MethodError: no method matching getindex(::JuMP.VariableRef)

julia> 1[] # a scalar number supports this
1

julia> map(y -> y[], x)
ERROR: MethodError: no method matching getindex(::JuMP.VariableRef)

julia> map(y -> y[], 1)
1

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [September 23, 2025, 1:31am UTC](https://discourse.julialang.org/t/map-should-be-more-consistent/132559/8 "2025-09-23T01:31:32Z")

</div>

Well, as long as I don’t use `map` on a zero-`ndims` object, I think the existing behavior is okay.  
Maybe the behavior I want is `broadcast`.  
Close this topic.
