# Why does \`1 \* String\[\]\` return a Vector{Union{}}?

**URL:** <https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049>\
**Category:** New to Julia\
**Created:** [October 17, 2023, 4:01am UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049 "2023-10-17T04:01:22Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [October 17, 2023, 4:01am UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/1 "2023-10-17T04:01:22Z")

</div>

```julia
1 * ["a"] # gives error
1 * String[] # returns Vector{Union{}}

```

Why is the second allowed?

---

<div class="post-metadata">

**Author:** ![Syx\_Pek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/syx_pek/32/6364_2.png) [@Syx\_Pek](https://discourse.julialang.org/u/Syx_Pek)\
**Post date:** [October 17, 2023, 4:52am UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/2 "2023-10-17T04:52:47Z")

</div>

We can ask Julia which method implements it

```julia
julia> @which 1 * String[]
*(A::Number, B::AbstractArray)
     @ Base arraymath.jl:21

```

This makes sense as the idea is c \cdot v for c \in \mathbb k and v a vector would then become a component-wise multiply, useful when you implement your own types.

Hopefully this explains why it is allowed, but another question would be should such behaviour be considered wrong.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [October 17, 2023, 5:31am UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/3 "2023-10-17T05:31:56Z")

</div>

I understand that a scalar times a vector is essentially a component-wise multiplication. (I think it calls broadcast?). But my question is, why is the operation `*` between an `Int64` and a `Vector{String}` allowed when `*(::Int64, ::String)` is not defined?

You can not do, for example, `1 * "a"` because `*(::Int64, ::String)` is not defined. And this is the error you get when you try `1 * ["a"]` as well. That makes sense. So then why allow `1 * String[]`?

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [October 17, 2023, 5:52am UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/4 "2023-10-17T05:52:31Z")

</div>

> [@sadish-d](#):
>
> But my question is, why is the operation `*` between an `Int64` and a `Vector{String}` allowed when `*(::Int64, ::String)` is not defined?

`*` between `Int64` and `Vector{String}` is defined. It will try to broadcast the multiplication across the vector. `*(Int64, String)` does not exists to trying to call it will result in a `MethodError`. But here is the catch: Since your vector is empty, no such call occurs, so no error is thrown!

You can also see this from the type of the resulting `Vector{Union{}}`. `Union{}` means there are no possible types that could fit into this vector which is a consequence of `*(Int64, String)` not being defined.

Perhaps, we could also see this case as an instance of “everything is true of the elements of the empty set”.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [October 17, 2023, 2:02pm UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/5 "2023-10-17T14:02:29Z")

</div>

Ok, the type of `String[]` is getting ignored there. `@assert eltype(String[]) == String`.

I don’t know if I like empty arrays. I tend to use them as default values. I’ll need to rethink them and make sure to treat them as special cases. It turns out that all elements of empty array are `true`, even when the array cannot hold `Bool`s:

`@assert all(String[])`

But all elements of the same, non-Boolean empty arrays are also false:

`@assert !any(String[])`

I don’t understand why the eltype gets ignored.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [October 17, 2023, 2:30pm UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/6 "2023-10-17T14:30:32Z")

</div>

Perhaps this topic can help:

> [@Behavior of all() and any() on empty vectors](https://discourse.julialang.org/t/behavior-of-all-and-any-on-empty-vectors/30963):
>
> This caught me by surprise: julia\> any(x-\>true, []) false julia\> all(x-\>true, []) true julia\> any(x-\>false, []) false julia\> all(x-\>false, []) true This seems like a bug - I think that all should never be true when any is false. But I’m guessing there’s a principled reason for this. Can anyone explain it to me?

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [October 17, 2023, 7:03pm UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/7 "2023-10-17T19:03:03Z")

</div>

Thanks, @Sukera. I had no doubt that people had put thought into the choice of behavior. But things are not any clearer to me. (And maybe that’s okay.) I suppose all programming languages have to deal with empty sets/arrays. There are two things that confuse me.

1. Why `all` and `any` and the like work on non-Boolean arrays at all. Probably for the same reason that `'a' + 1 == 'b'` and `1 == true`.

2. Why the need to return an answer when there isn’t one? Maybe `any([])` and `all([])` should be neither `true` nor `false`. I’d rather deal with an error there and implement an `if !isempty` to deal with the error than have some unexpected value floating around my program. And it’s not even that `all` and `any` necessarily return `Bool`. They return `missing` when the iterator contains missing values.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [October 17, 2023, 7:10pm UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/8 "2023-10-17T19:10:07Z")

</div>

> [@sadish-d](#):
>
> Why `all` and `any` and the like work on non-Boolean arrays at all. Probably for the same reason that `'a' + 1 == 'b'` and `1 == true`.

They only work in the empty case, because the empty case doesn’t care about the type; there is no logical predicate you can write that will make the `any` call return `true`, because it won’t ever be applied. Once you have a non-empty array, you do get an error:

```julia
julia> any(["foo"])
ERROR: TypeError: non-boolean (String) used in boolean context
Stacktrace:
 [1] _any
   @ Base ./reduce.jl:1228 [inlined]
 [2] _any
   @ Base ./reducedim.jl:1007 [inlined]
 [3] any(a::Vector{String})
   @ Base ./reducedim.jl:1005
 [4] top-level scope
   @ REPL[1]:1

```

> [@sadish-d](#):
>
> Why the need to return an answer when there isn’t one? Maybe `any([])` and `all([])` should be neither `true` nor `false`. I’d rather deal with an error there and implement an `if !empty` to deal with the error than have some unexpected value floating around my program.

But there is one - `any(f, vec)` is asking the question “of all the elements in `vec`, is there one that fulfills the predicate `f`?” and for an empty array the answer is `false`, because there is no example from `vec` you could provide to make that `true`. You can think of `any`/`all` as a `fold`, if you will, starting out with initial values of `false` and `true` respectively. If there are no elements to fold over, it’s just the initial value being returned.

> [@sadish-d](#):
>
> And it’s not even that `all` and `any` necessarily return `Bool`. They return `missing` when the iterator contains missing values.

That’s just a property of `missing` though, and unrelated to `any`/`all`. Your predicate is free to handle `missing` differently.

---

<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:** [October 17, 2023, 7:17pm UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/9 "2023-10-17T19:17:28Z")

</div>

The simplest mental model here is that `any` is true if there’s at least one true and `all` is false if there’s at least one false. Array element types don’t matter; it’s the values that do. In fact:

```julia
julia> all([false, "no errors!"])
false

julia> any([true, "no errors!"])
true

```

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [October 17, 2023, 10:08pm UTC](https://discourse.julialang.org/t/why-does-1-string-return-a-vector-union/105049/10 "2023-10-17T22:08:25Z")

</div>

> any(f, vec) is asking the question “of all the elements in vec, is there one that fulfills the predicate f?”

I like the framing as a mnemonic:

any(f, vec): There is an element in vec that fulfills the predicate f.  
all(f, vec): There is no element in vec that fails to fulfill the predicate f.

But again, this leads to the contradiction `(all(f, []) && !any(f, [])) == true`, as mentioned in the post linked earlier. And now that I think about it, `all(f, []) == all(!f, []) == true`.

So we’re just kicking the can down the road-- does the element of an empty set, the one that does not exist, fulfill or fail to fulfill a predicate?

I wrote this just to think through the issue a bit, and defaults are really sneaky when dealing with empty sets. I wanted to leave it here as a cautionary tale.

```julia
function allisodd(set::Vector)
    for element in set
        if isodd(element) == false # element fails to fulfill predicate
            return false
        end
    end

    return true
end
function noneisodd(set::Vector)
    for element in set
        if isodd(element) == true # element fulfills predicate
            return false
        end
    end

    return true
end

```

With this, we get `allisodd([]) == noneisodd([]) == true`

I’ll live with the mnemonic for now. Thanks for engaging.
