# Makie (and Julia) do not automatically typecast obvious numerical representations

**URL:** <https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148>\
**Category:** Visualization\
**Tags:** type, makie\
**Created:** [January 24, 2022, 10:25pm UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148 "2022-01-24T22:25:49Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [January 24, 2022, 10:25pm UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/1 "2022-01-24T22:25:49Z")

</div>

I have experienced that Julia is not very generous with automatic typecasting (or type conversion).  
e.g.

```julia
f(x::Int) = x
f(1.0)
ERROR: MethodError: no method matching f(::Float64)
Closest candidates are:
  f(::Int64) at REPL[4]:1
Stacktrace:
 [1] top-level scope
   @ REPL[5]:1

```

Although I understand that this is a design choice, sometimes it can be a pain.

For example using the Makie package I discovered that the following yields an error

```julia
using GLMakie
a = Vector{Any}([1,2,3,4,5])
barplot(a)
ERROR: `Makie.convert_arguments` for the plot type Combined{Makie.barplot, Tuple{Vector{Any}}} and its conversion trait PointBased() was unsuccessful.

The signature that could not be converted was:
::Vector{Any}

Makie needs to convert all plot input arguments to types that can be consumed by the backends (typically Arrays with Float32 elements).
You can define a method for `Makie.convert_arguments` (a type recipe) for these types or their supertypes to make this set of arguments convertible (See http://makie.juliaplots.org/stable/documentation/recipes/index.html).

Alternatively, you can define `Makie.convert_single_argument` for single arguments which have types that are unknown to Makie but which can be converted to known types and fed back to the conversion pipeline.
...

```

I understand that the first one is a design choice of the language, with consistency being one of the advantages.

But in the second case, the package usability could probably be increased if such conversions could be automatically handled. I would guess for example that implementing a Any =\> Float64 conversion would deal with the majority of the error cases in the Makie package.

---

<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:** [January 24, 2022, 10:30pm UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/2 "2022-01-24T22:30:17Z")

</div>

This is pretty fundamental to how dispatch works in Julia and isn’t something that can really be changed. If you write `f(x::Int)`, you are telling the language that you only want this method to be called for `Int` arguments — the argument types act as a kind of filter.

> [@PSA: Julia is not at that stage of development anymore](https://discourse.julialang.org/t/psa-julia-is-not-at-that-stage-of-development-anymore/44872):
>
> You heard about this brand new exciting programming language called Julia and have some suggestions for how it should work. Wonderful! We’re happy to have you here and help you learn the language and listen to your ideas! However, please be aware that “new” is a relative term. Yes, Julia is newer than, say, C, which was first created in 1972 and standardized in 1989. It is not, however, new in the sense that it is still being freely designed and changed in arbitrary ways. Julia development start…

Definitely library authors should try to accept the widest applicable type signatures in their APIs, but you will typically still have to pay more attention to types than in, e.g. Python.

If there is a specific set of functions in Makie that you think should accept `Vector{Any}`, you can file an issue there, but this isn’t something that’s going to change at the language level.

---

<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:** [January 24, 2022, 11:33pm UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/3 "2022-01-24T23:33:03Z")

</div>

One alternative is for you to turn the question around: “Why is my code lugging around a `Vector{Any}`, and how can I fix it?”

`Vector{Any}` is commonly a sign that something went wrong somewhere (unless you are quite experienced), and that your program will be slow and bug prone. The most common source of these vectors are, as far as I’ve seen, that a vector was initialized as `a = []`.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 25, 2022, 3:24am UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/4 "2022-01-25T03:24:49Z")

</div>

I completely agree that we should have a flexible and extensible mechanism for doing conversion of arguments to the expected type when calling a function. Let’s think through a possible design for this feature.

We need some way of expressing what types should be converted to what other types and in what circumstances. After all, we definitely can’t convert floating point values to integers everywhere—if we did that, we couldn’t have different implementations for integers and floats, which is something one often needs. And sometimes you would want to convert a float to a complex number or something else rather than an integer. So we do need something with some flexibility for this—in particular, we would need to include the function that the rule applies to since that determines whether a float should be converted to an integer, say, or a complex number, or a rational or whatever. Then we’d need some kind of pattern specifying the kinds of arguments that the conversion rule applies to. And finally we’d need to specify how to do the conversion itself. Sometimes it might just be calling `convert` but sometimes it might be something a bit more complex. It might even involve an interaction between multiple arguments in a non-trivial way, so to be flexible enough we’d want to include how to re-invoke the function. But I think those three criteria should be sufficient for this feature.

Ok, now that we have the design requirements, let’s give it a syntax. We can put the function first, then the pattern that matches the arguments, and then the rule for how to convert the arguments and pass them back to the function. So maybe something like this:

```julia
f(x::Real) = f(Int(x))

```

Nice! That’s a pretty clear, concise way to express an automatic argument conversion for `f`. It captures all the essential factors quite minimally and it wouldn’t only work when you call `f` with a floating point argument, but also with any numeric value that is a subtype of the `Real` abstraction. I think this feature might be pretty useful in general.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [January 25, 2022, 3:25am UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/5 "2022-01-25T03:25:24Z")

</div>

Ideally, `Vector{Any}` is just a performance issue, not a correctness one. That’s why [YASGuide](https://github.com/jrevels/YASGuide#programming-guidelines) at least suggests one shouldn’t dispatch on things like `AbstractVector{<:Number}`, since that doesn’t actually represent “any `AbstractVector` whose elements are all `<:Number`“.

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [January 25, 2022, 11:30am UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/6 "2022-01-25T11:30:00Z")

</div>

The specific for running into this problem was using `hcat` to handle more conveniently my data structure, using Matrix indexing.  
Assume I have the following generator

```julia
ge = (ns for ns in [("one",1), ("two", 2), ("three", 3)])
ma = vcat([[n;;s] for (n,s) in ge]...)
3×2 Matrix{Any}:
 "one" 1
 "two" 2
 "three" 3

```

in order to do something like this:

```julia
barplot(ma[:,1], axis=(xticks= (1:3, ma[:,2]),))

```

but it doesn’t work because all elements are reduced to the type of the Matrix, i.e. `Any`.  
Then I also tried using a Matrix{Union{Int, String}}:

```julia
ma2 = Matrix{Union{String, Int}}(ma)
3×2 Matrix{Union{Int64, String}}:
 1 "one"
 2 "two"
 3 "three"

```

but **this didn’t do the trick**.

In the end I use a normal Vector of Vectors and broadcast the `getindex` function:

```julia
ns = [[n, s] for (n,s) in ge]
3-element Vector{Vector{Any}}:
 ["one", 1]
 ["two", 2]
 ["three", 3]

```

which although it’s of type Any, the inner vectors still hold their types:

```julia
getindex.(ns,2)
3-element Vector{Int64}:
 1
 2
 3

```

so plotting with Makie is possible:

```julia
barplot(getindex.(ns,2), axis=(xticks= (1:3, getindex.(ns,1)),))

```

I was thinking of Julia as of just not being super fast if someone didn’t care about the types,  
but I see that there can be several implications.

> [@stevengj](#):
>
> Definitely library authors should try to accept the widest applicable type signatures in their APIs, but you will typically still have to pay more attention to types than in, e.g. Python.

Thanks everybody for the answers !

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [January 25, 2022, 11:46am UTC](https://discourse.julialang.org/t/makie-and-julia-do-not-automatically-typecast-obvious-numerical-representations/75148/7 "2022-01-25T11:46:16Z")

</div>

It can be generally more convenient to use a table instead of a matrix here:

```julia
tbl = [(label=ns[1], val=ns[2]) for ns in [("one",1), ("two", 2), ("three", 3)]]
barplot(getproperty.(tbl, :val), ... whatever ...)

# or
using Tables
tbl = [(label=ns[1], val=ns[2]) for ns in [("one",1), ("two", 2), ("three", 3)]] |> columntable
barplot(tbl.val, ... whatever ...)

```
