String macro is likely the wrong approach. You should simply use a function like f(a, b) = Quantity{a, dimension(b), typeof(b)}.
As for why the macro is not working, you are assuming the name of the type parameter (which is REALLY bad for readability) and if you really want to do that, you have to pretend it is user input by escaping the Float symbol.
String macro is likely the wrong approach. You should simply use a function like f(a, b) = Quantity{a, dimension(b), typeof(b)} .
Thanks. This proposal works and is a more compact representation:
using Unitful
quantity(a,b) = Quantity{a, dimension(b), typeof(b)}
mutable struct Data4{Float}
length::quantity(Float,u"m")
end
d4 = Data4{Float64}(2.0u"mm")
@show d4.length
As for why the macro is not working, you are assuming the name of the type parameter (which is REALLY bad for readability) and if you really want to do that, you have to pretend it is user input by escaping the Float symbol.
I did not get this suggestion to work. Maybe I misunderstood you (I used esc(Float) instead of Float):
using Unitful
macro Float_str(str)
return :( Quantity{esc(Float), dimension(@u_str($str)), typeof(@u_str($str))} )
end
mutable struct Data3{Float}
length::Float"m"
end
d3 = Data3{Float64}(2.0u"mm")
@show d3.length
The above code fragement gives the same error.
(Your first proposal is clearer from a computer science point of view. If there are many declarations with units, the form length::Float"m" is nicer to read as length::quantity(Float,u"m"))
Besides @yuyichao’s points, there’s a typo in your second string macro. […]
No, this is not a typo: The goal is to use the type defined as parameter in the struct struct Data3{Float}, so using Float in the macro and not a concrete type, such as Float64.
He means you should interpolate esc(:Float) into the expression. e.g.
julia> using Unitful
julia> macro Float_str(str)
:(Quantity{$(esc(:Float)), dimension(@u_str($str)), typeof(@u_str($str))})
end
@Float_str (macro with 1 method)
julia> mutable struct Data3{Float}
length::Float"m"
end
julia> d3 = Data3{Float64}(2.0u"mm")
Data3{Float64}(0.002 m)
But yeah, prt of why I got confused is that this macro is very specialized, it’s written assuming that the user has defined a variable Float outside of the macro, which is usually a bad idea.
The symbol is represented as a literal Float currently and you need to replace it with the esc of the symbol (i.e. esc(:Float)). To get it in the expression, use $(...) to splice that in, i.e. replace Float with $(esc(:Float)).
Thanks very, very much for all your suggestions. My questions are resolved. Let me summarize:
The Julia idiomatic way is
using Unitful
Quantity(a,b) = Quantity{a, dimension(b), typeof(b)}
mutable struct Data4{Float <: AbstractFloat}
length::Quantity(Float,u"m")
end
d4 = Data4{Float64}(2.0u"mm")
@show d4.length
Nicer to read, but hard to understand the implementation behind it with the (bad) assumption that a type Float is defined outside of the macro (so the macro only works under this assumption):
using Unitful
macro Float_str(str)
return :( Quantity{$(esc(:Float)), dimension(@u_str($str)), typeof(@u_str($str))} )
end
mutable struct Data3{Float <: AbstractFloat}
length::Float"m"
end
d3 = Data3{Float64}(2.0u"mm")
@show d3.length
Yes that’s correct. The second approach is also only bead because you want to make the macro name match the type parameter name. Making it @quantity(Float, "m") or quantity"Float,m" would not have this issue. (though for the second version you’d have to do some parsing with the string macro, which is basically true for all string macros…)