How do I retrieve the vectors of values by themselves (e.g., (67.28628518822661, -95.22204196033839) rather than JMtk15.MTKt_GeoCoord(67.28628518822661, -95.22204196033839)?
More generally, if a C function returns a complex structure, how do I retrieve the individual vectors without the type specification?
Shouldnât simply [region.geo.ctr.lat, region.geo.ctr.lon] give you the desired vector?
Not sure what you mean by âindividual vectorsâ and âwithout the type specificationâ here. Perhaps absolutely not what youâre asking for but FWIW:
julia> vectorize(x) = [getfield(x, f) for f in fieldnames(typeof(x))]
vectorize (generic function with 1 method)
julia> struct MTKt_GeoCoord
lat::Float64
long::Float64
end
julia> coord = MTKt_GeoCoord(rand(), rand())
MTKt_GeoCoord(0.5525629138140212, 0.05413709610407247)
julia> vectorize(coord)
2-element Vector{Float64}:
0.5525629138140212
0.05413709610407247
Thanks, @carstenbauer. I guess, my question may sound strange out of context. I know how to retrieve individual values from a structure, but when testing the function, I got this:
julia> @test region.geo.ctr.lat == 67.28628518822661
Test Passed
julia> @test region.geo.ctr.lon == -95.22204196033839
Test Passed
julia> @test region.hextent.xlat == 633462.5
Test Passed
julia> @test region.hextent.ylon == 307862.5
Test Passed
julia> @test region.geo.ctr == (67.28628518822661, -95.22204196033839)
Test Failed at REPL[304]:1
Expression: region.geo.ctr == (67.28628518822661, -95.22204196033839)
Evaluated: JMtk15.MTKt_GeoCoord(67.28628518822661, -95.22204196033839) == (67.28628518822661, -95.22204196033839)
ERROR: There was an error during testing
so my question was whether there is a native way to write the last test or whether I need to extract the vector using a function like the one you kindly provided to implement the testing.
Imagine you are in C and you had a MTKt_GeoCoord x with an array double y[2] ⌠would you compare them with x == y? No, because they are different types. Same thing in Julia â you are comparing a MTKt_GeoCoord with a tuple, so == returns false by default because they are different types.
Of course, Julia is much more flexible in this regard than C because you can define lots of new operations on a type to make things like this work. For example, if you want to make a MTKt_GeoCoord act like a vector, you can do:
using StaticArrays # the StaticArrays.jl package
# define a struct that can also act as a 2-component vector:
struct MTKt_GeoCoord <: FieldVector{2,Float64}
lat::Float64
lon::Float64
end
in which case you can do things like:
julia> ctr = MTKt_GeoCoord(67.2, -95.3)
2-element MTKt_GeoCoord with indices SOneTo(2):
67.2
-95.3
julia> ctr == [67.2, -95.3]
true
julia> ctr .+ 1
2-element MTKt_GeoCoord with indices SOneTo(2):
68.2
-94.3
Iâm confused about what you are trying to accomplish. What data structure do you want? A struct, an array, or a tuple? This depends on what sort of operations you want to perform.
Sorry if this appears to be confusing⌠As indicated earlier, the wrapper to the C function works fine (it generates the correct values), but the outcome does not seem to be suitable for direct comparisons in @test procedures, as pointed out before.
In the meantime, I have implemented your suggestion, and redefined the structures as follows:
struct MTKt_GeoCenter <: FieldVector{1, FieldVector{2, Float64}}
ctr::MTKt_GeoCoord
end
struct MTKt_Extent <: FieldVector{2, Float64}
xlat::Cdouble
ylon::Cdouble
end
struct MTKt_Region <: FieldVector{2, FieldVector{2, Float64}}
geo::MTKt_GeoCenter
hextent::MTKt_Extent
end
With those newly redefined types, the function outcome is
julia> region = jMtkSetRegionByPathBlockRange(path, start_block, end_block);
julia> region.geo
1-element JMtk15.MTKt_GeoCenter with indices SOneTo(1):
[67.28628518822661, -95.22204196033839]
julia> region.hextent
2-element JMtk15.MTKt_Extent with indices SOneTo(2):
633462.5
307862.5
and that, in turn, is suitable for testing:
julia> @test region.geo[1] == [67.28628518822661, -95.22204196033839]
Test Passed
julia> @test region.hextent == [633462.5, 307862.5]
Test Passed
So the next question is how to do the same when the structures contain different base types (those presumably cannot be mapped to a FieldVector), as in the last examples in my previous messageâŚ
Unless you truly need a nested arrays-of-arrays API for some reason, why not just construct instances of your structs for comparison in the tests and skip implementing a bunch of other stuff that it seems you want just so you can build tests? Nested arrays of arrays become hard to work with because thereâs no information to identify what they mean.
@Jeff_Emanuel: Thanks a lot for your input. Your approach also works:
julia> @test region.geo.ctr == JMtk15.MTKt_GeoCoord(67.28628518822661, -95.22204196033839)
Test Passed
though only if I explicitly include the prefix JMtk15 in front of MTKt_GeoCoord.
This puzzles me because the structure MTKt_GeoCoord is defined in a file included at the start of the project JMtk15, so why is it not defined after using JMtk15? Do I need to export the symbols defined in an included file? Apologies if this is a trivial questionâŚ
Yes, you should export the symbols from your module that should be available to users. Users can still qualify the unexported symbols with the module name. Those symbols might not be exported because they may be internal details or they may clash with common names. Essentials ¡ The Julia Language
I have read the manual (Essentials ¡ The Julia Language) multiple times and understood the first sentence âEvaluate the contents of the input source file in the global scope of module mâ to mean that include("file_h.jl") instructions would bring the contents of file_h.jl into the current scope. Similarly, I always encountered export keywords in the context of import and using files.
So, just two more questions to close that argument:
what is the practical difference, if any, between include("file") and using file?
why did my dozens of wrapper functions work so far without the need to export such included definitions?
include basically just executes the included file in place of the include statement. Itâs very coarse, like a #include in C. Modules provide a namespace for a unit of code. using loads the module and makes its exported symbols available in the calling namespace. using is somewhat like an import in Java or Go or other relatively recent (compared to C) languages. One noteworthy difference is that include can trample over existing names, but using will report a conflict. export is used to make a symbol in a module available to code that imports the module.
You donât use a file, you use a module.
Do you mean within the module or the client code? A module has free access to its own symbols. If in the client code, I suspect that you may have directly included the source file defining those functions.
I am not sure what is meant by âclient codeâ. Basically, I have a project with a unique module, called JMtk15. Within that project, I have a src directory containing Julia functions that are wrappers to the C functions, and a src/include subdirectory containing files with const, @enum and struct definitions such as the ones mentioned above (those statements are translated from the C .h files). So far, those files did not export any of the symbols, and were included at the start of the JMtk15 module.
When I execute, in the REPL, sequences of commands such as
using JMtk15
outputs = function(inputs)
or
using JMtk15
using Test
outputs = function(inputs)
@test outputs == expected_outputs
things work smoothly (again without any of the included definitions being explicitly exported). Thatâs why I always thought that those structure definitions were available as soon as using JMtk15 had been executedâŚ
Client would be any code that uses your module. What you describe sounds proper except for the absence of export. I canât explain why it worked without export.