New() function for Arrays

I struggle with writing a proper constructor for my struct PERK. What gives my trouble is the usage of new() with my member arrays. The code looks like this:

abstract type PERKTYPE end

struct PERK <: PERKTYPE
    NumStages::Int

    ACoeffs::Array{BigFloat}
    c::Array{BigFloat}
  
    function PERK()

      ACoeffsFile = open("some/existing/file.txt", "r")
      NumStages = countlines(ACoeffsFile)
      close(ACoeffsFile)
      #println(NumStages)

      ACoeffs = Array{BigFloat}(undef, NumStages, 2)
      
      # Fille ACoeffs with data from file, omitted here

      c = Array{BigFloat}(undef, NumStages)
      for i in 1:NumStages
        c[i] = (i-1)/(2*(NumStages-1))
      end

      new(NumStages) # Fine
      new(ACoeffs, c) # Not working if un-commented

    end # PERK()
  end # struct PERK

I get the error

ERROR: LoadError: MethodError: Cannot `convert` an object of type Matrix{BigFloat} to an object of type Int64
Closest candidates are:
  convert(::Type{T}, ::LLVM.GenericValue) where T<:Signed at ~/.julia/packages/LLVM/gE6U9/src/execution.jl:27
  convert(::Type{T}, ::LLVM.ConstantInt) where T<:Signed at ~/.julia/packages/LLVM/gE6U9/src/core/value/constant.jl:89
  convert(::Type{T}, ::Ptr) where T<:Integer at ~/Software/julia-1.7.2/share/julia/base/pointer.jl:23
  ...
Stacktrace:
 [1] PERK()
   @ Trixi ~/.../methods_PERK.jl:26

What is going on here? Of course, I am not interested in any conversion of my arrays at all.

new instantiates properties in order, leaving the next as undef

Your struct takes

Int, Array{BigFloat}, Array{BigFloat}

So your new must be one of

new()
new(::Int)
new(::Int, ::Array{BigFloat})
new(::Int, ::Array{BigFloat}, ::Array{BigFloat})

Your conversion is attempting to convert ACoeffs to NumStages

4 Likes

I think I tried listing all my members, but probably not in correct order - thanks anyway!

BTW, Array{BigFloat} is an abstract type, which is generally discouraged in struct definitions, for performance reasons. Consider whether Array{BigFloat, 1}or Array{BigFloat, 2} are appropriate for your case.

Also, it seems like your constructor should not be an inner constructor, but an outer one, that is, it should be defined outside the struct block, and not use new(). In your current code, you have overwritten the default inner constructor, so you cannot use explicit construction with actual input arguments.

Example:

struct Foo
    x::Int
    y::Float64
    Foo() = new(1, 1.0)
end

julia> Foo()
Foo(1, 1.0)

julia> Foo(2, 3.1)
ERROR: MethodError: no method matching Foo(::Int64, ::Float64)

If you use an outer constructor instead:

struct Bar
    x::Int
    y::Float64
end
Bar() = Bar(1, 1.0)

julia> Bar()
Bar(1, 1.0)

julia> Bar(2, 3.1)
Bar(2, 3.1)
4 Likes