`Char` and `broadcastable`

A related question: Is it intentional that broadcastable is not explicitly defined for Char in broadcast.jl? Instead the default method for iterables is used. String in contrast is treated as a scalar, as discussed above.

It doesn’t need to be — like Number, a Char can act as a 0-dimensional array. (IIRC it used to be that Char was a subtype of Integer so it got its behavior then, and kept it when it was split off into its own type.)

I’m sorry, I don’t fully understand. The current definitions include broadcastable(x::Number) = x and broadcastable(x::Char) = collect(x). It seems to me that Char is the only plain bits type for which broadcastable calls collect. (This once threw me off when implementing broadcasting for a custom type.) Do you think this is correct or a bug?

Sorry, I must have misremembered — it must be that Char is missing some method after all that would allow it to work with broadcast without the collect? I’m not sure what it is, since Char supports size and getindex and axes similar to Number. What happens if you remove that method and try to broadcast?

The code

import Base.Broadcast: broadcastable
broadcastable(x::Char) = x
['a','b'] .* 'd'

results in

ERROR: MethodError: no method matching getindex(::Char, ::CartesianIndex{0})

So it appears to be getindex that doesn’t work.

Seems like a bug (a missing method), since a zero-argument getindex works for Char.

You’re right. If you create such a method for getindex, then it works:

import Base: getindex
getindex(x::Char, ::CartesianIndex{0}) = x

import Base.Broadcast: broadcastable
broadcastable(x::Char) = x

['a','b'] .* 'c'  # works

Is it worth filing this on GitHub?

3 Likes

Seems like it. (If nothing else, it would give a cleaner way to broadcast using Char, without allocating a temporary array with collect.)

4 Likes

I’ve created a PR.

2 Likes