# Trying to write a convert() for a complicated type

**URL:** <https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419>\
**Category:** General Usage\
**Created:** [January 6, 2024, 1:20am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419 "2024-01-06T01:20:32Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![GlenHenshaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/glenhenshaw/32/5269_2.png) [@GlenHenshaw](https://discourse.julialang.org/u/GlenHenshaw)\
**Post date:** [January 6, 2024, 1:20am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/1 "2024-01-06T01:20:33Z")

</div>

Stepping back into Julia after a year’s absence.

I’m using RigibBodyDynamics to model a double pendulum. Simulating the system should return an array of system states, ideally an `Array{Float64}` or similar. The type that is actually returned is a

```
SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}}

```

which I’m sure there was a good reason for using, but it can’t just be dropped into functions where one would normally use a `Vector{}`, such as for instance `plot()`.

So I’m trying to write a `convert()` that turns it into an actual vector, and I cannot for the life of me get the type matching system to match my function.

What I’ve done is define:

```
convert(::Vector{Float64}, x::Vector{SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}}}) = mapreduce(permutedims, vcat, x)

convert(::Float64, x::SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}}) = x[1][:]

```

but when I try to force an implicit conversion, it fails:

```
julia> typeof(qs)
Vector{SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}} (alias for Array{SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Array{Float64, 1}}, 1})

julia> typeof(X)
Vector{Float64} (alias for Array{Float64, 1})

julia> append!(X, qs)
ERROR: MethodError: Cannot `convert` an object of type SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}} to an object of type Float64

Closest candidates are:
  convert(::Type{Float64}, ::Measures.AbsoluteLength)
   @ Measures ~/.julia/packages/Measures/PKOxJ/src/length.jl:12
  convert(::Type{T}, ::T) where T<:Number
   @ Base number.jl:6
  convert(::Type{T}, ::Gray) where T<:Real
   @ ColorTypes ~/.julia/packages/ColorTypes/1dGw6/src/conversions.jl:113
  ...

```

Interestingly, defining something like

```
conv(x::Vector{SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}}}) = mapreduce(permutedims, vcat, x)
conv (generic function with 3 methods)

julia> conv(qs)
15002×2 Matrix{Float64}:
 0.718177 0.310706
 0.716825 0.314462
 0.715472 0.318206
 0.714121 0.321928
 0.712759 0.325665
 0.711398 0.329381
 0.710036 0.333088

```

ie doing an explicit conversion, works.

What am I doing wrong?

---

<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 6, 2024, 1:36am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/2 "2024-01-06T01:36:31Z")

</div>

> [@GlenHenshaw](#):
>
> What I’ve done is define:
> 
> `convert(::Vector{Float64}, `

Did you remember to `import Base: convert` first? Or define it as `Base.convert(...) = ...`?

---

<div class="post-metadata">

**Author:** ![GlenHenshaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/glenhenshaw/32/5269_2.png) [@GlenHenshaw](https://discourse.julialang.org/u/GlenHenshaw)\
**Post date:** [January 6, 2024, 1:49am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/3 "2024-01-06T01:49:21Z")

</div>

I had forgotten to do that, but it doesn’t fix the problem unfortunately.

---

<div class="post-metadata">

**Author:** ![GlenHenshaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/glenhenshaw/32/5269_2.png) [@GlenHenshaw](https://discourse.julialang.org/u/GlenHenshaw)\
**Post date:** [January 6, 2024, 2:11am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/4 "2024-01-06T02:11:26Z")

</div>

Here’s the complete code. I apologize that it’s a little messy.

```
  using RigidBodyDynamics
  using LinearAlgebra
  using StaticArrays
  using MatrixEquations
  
  import Base: convert, OneTo

  convert(::Array{Float64}, x::Vector{SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}}) = mapreduce(permutedims, vcat, x)
  convert(::Float64, x::SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}) = x[1][:]
  convert(::Float64, x::Vector{SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}}) = mapreduce(permutedims, vcat, x)
  
  # The code below creates a pendulum mechanism
  g = -9.81
  world = RigidBody{Float64}("world")
  doublependulum = Mechanism(world; gravity = SVector(0, 0, g))
  
  axis = SVector(0., 1., 0.)
  I_1 = 0.333
  c_1 = -0.5
  m_1 = 1.
  frame1 = CartesianFrame3D("upper_link")
  inertia1 = SpatialInertia(frame1,
      moment = I_1*axis*axis',
      com = SVector(0, 0, c_1),
      mass=m_1)
  
  upperlink = RigidBody(inertia1)
  shoulder = Joint("shoulder", Revolute(axis))
  before_shoulder_to_world = one(Transform3D, frame_before(shoulder), default_frame(world))
  
  attach!(doublependulum, world, upperlink, shoulder, joint_pose = before_shoulder_to_world)
  # The mechanism is now defined
 
  state = MechanismState(doublependulum)
  set_configuration!(state, shoulder, 0.3)
  set_velocity!(state, shoulder, 1.)
  
  X = Vector{Float64}()
  
  for i in 1:1000
      ts, qs, vs = simulate(state, 15., Δt = 1e-3);
      append!(X, qs)
  end

```

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [January 6, 2024, 2:39am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/5 "2024-01-06T02:39:29Z")

</div>

```julia
convert(::Float64, x::Vector{SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}}) = mapreduce(permutedims, vcat, x)

```

what is this actually supposed to do? it appears to return a `Matrix{Float64}` but I imagine you wanted `Float64` ?

---

<div class="post-metadata">

**Author:** ![GlenHenshaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/glenhenshaw/32/5269_2.png) [@GlenHenshaw](https://discourse.julialang.org/u/GlenHenshaw)\
**Post date:** [January 6, 2024, 2:47am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/6 "2024-01-06T02:47:05Z")

</div>

Sigh. I’m having a bit of trouble making sense of the errors Julia is giving me. What I _want_ to do is `append!(X, qs)` and have the language do the right implicit conversion to allow that call to succeed. I would have thought that this would first entail converting `qs` to a `Vector{Float64}`, and then executing the `append!`.

But the actual error I’m getting is that Julia doesn’t know how to convert a `SegmentedVector` to a `Float64`. NOT a `Vector{Float64}`:

```
ERROR: MethodError: Cannot `convert` an object of type SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}} to an object of type Float64

```

…which means that, for reasons I can’t understand, Julia _thinks_ it needs to convert `qs` to a `Float64` in order to `append!` it to `X` (which is of type `Vector{Float64}`). Or at least that’s how I’m reading it. I really don’t understand that.

But, to figure out a solution, I’ve tried to throw the kitchen sink at the problem. I’ve attempted to write `convert()` functions that do what _I_ think is the right thing – converting a `SegmentedVector` to a `Vector{Float64}` – but also defining conversions from a `Vector{SegmentedVector}` to a `Vector{Float64}`, and (attempting to address the actual error I’m seeing) converting a `SegmentedVector` to a `Float64`. Or at least to get the type dispatch to call that routine.

Note that a `SegmentedVector` is not a scalar, so it can’t really be converted to one. I know that code won’t work, but I can’t even get Julia to recognize the correct function prototype.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [January 6, 2024, 4:11am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/7 "2024-01-06T04:11:30Z")

</div>

is it important to you that you specifically use `convert` for this purpose? e.g. the call succeeds if you change it to `append!(X, reduce(vcat, qs))` without defining any additional `convert` dispatches

---

<div class="post-metadata">

**Author:** ![GlenHenshaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/glenhenshaw/32/5269_2.png) [@GlenHenshaw](https://discourse.julialang.org/u/GlenHenshaw)\
**Post date:** [January 6, 2024, 4:29am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/8 "2024-01-06T04:29:41Z")

</div>

Not particularly, I just thought it would be the most elegant solution.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [January 6, 2024, 6:00am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/9 "2024-01-06T06:00:21Z")

</div>

If you actually want to plot it (using Plots.jl), the best way is to write a `@recipe`. For your type it looks like that should be

```julia
@recipe function f(::Type{SegmentedVector}, x::SegmentedVector)
    return x[1][:]
end

```

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [January 6, 2024, 6:21am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/10 "2024-01-06T06:21:05Z")

</div>

> [@GlenHenshaw](#):
>
> What I’ve done is define:
> 
> ```julia
> convert(::Vector{Float64}, x::Vector{SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}}}) = mapreduce(permutedims, vcat, x)
> 
> convert(::Float64, x::SegmentedVector{JointID, Float64, Base.OneTo{JointID}, Vector{Float64}}) = x[1][:]
> 
> ```

This is type piracy, because you own neither `Base.convert` nor `RigidBodyDynamics.SegmentedVector`. The only time you should define a `convert` method is if you’ve created your own type and you want your type to be implicitly converted to another type inside constructors, `push!`, and `append!`.

`SegmentedVector` is an `AbstractVector`, so you should be able to treat it like any other vector you’ve worked with in the past.

---

<div class="post-metadata">

**Author:** ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)\
**Post date:** [January 6, 2024, 7:37am UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/11 "2024-01-06T07:37:31Z")

</div>

> [@GlenHenshaw](#):
>
> ` convert(::Float64, x::SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}) = x[1][:]`

A call to `convert` passes a type (not an instance of that type) as the first argument, e.g. `convert(Float64, x)`. When defining a convert method you should specify the first argument as accepting a type and not an instance the type:

```julia
convert(::Type{Float64}, x::SegmentedVector{JointID, Float64, OneTo{JointID}, Vector{Float64}}) = x[1][:]

```

See:  
[https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Defining-New-Conversions](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/#Defining-New-Conversions)

---

<div class="post-metadata">

**Author:** ![GlenHenshaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/glenhenshaw/32/5269_2.png) [@GlenHenshaw](https://discourse.julialang.org/u/GlenHenshaw)\
**Post date:** [January 6, 2024, 7:59pm UTC](https://discourse.julialang.org/t/trying-to-write-a-convert-for-a-complicated-type/108419/12 "2024-01-06T19:59:38Z")

</div>

This is fantastic. I did not know about type piracy, but when pointed out it makes sense. I’ll do this as suggested. And thanks for the explanations about plots recipes (which I had never heard of) and how convert works. This community is one of the things that makes Julia great.
