I'm afraid that while I read through the other email, it's not really reasonable to expect people to read through this twice with slight differences. If you want to edit things, you should probably just follow your original post with clarifications.
On Fri, May 30, 2014 at 7:11 AM, <[email protected]> wrote: > (Repost, the first one was not clear) > > Hi everyone. > > I was thinking for some time about dimensionful arrays or variables in > general. (I really *really* *really* don't know whether the idea is sane. > Actually it tends to create more problem than it solves for what I've > tried.) > > Dimensionful variables would be a variable which refer to data and a > physical unit. This can easily be implemented using composite types: > type DimensionfulArray{T<:Number} > data::AbstractArray{T} > unit::String > end > > This approach is not great: > > 1. DimensionfulArray does not inherit from AbstractArray so that every > functions should be redefined as Foo(x::DimensionfulArray) = Foo(x.data).. > 2. Foo(x::DimensionfulArray) = Foo(x.data) would return a plain array > while type stability is often wanted. > 3. Letting the "unit" attribute directly accessible is not a really > good practice. But to my knowledge, nothing can be done about that. > 4. With this approach a lot of *if*s have to be used in functions to > test for unit content. > > As an alternative, there is the plain inheritance approach that would be: > type DimensionfulArray{T<:Number} <: AbstractArray{T} > but is not working because well, I can only declare abstract types this > way, not concrete types. Otherwise it would be great as this would let me > declare <Unit>{T} <: AbstractArray: the "unit" field would be avoided > altogether with the need for *if*s as one subtype would correspond to one > unit. > > http://grollchristian.wordpress.com/2014/01/22/julia-inheriting-behavior/ had > the exact same problem for DataFrames and solved this by using composite > types and boilerplate code. > > On the other hand, the discussion https://groups.google.com/ > forum/#!topic/julia-users/jlJrMTo_L1M was about subtyping concrete types > but Stefan redirected to https://groups.google.com/forum/#!msg/julia-dev/ > p9bV6rMSmvY/cExeSb-cMBYJ which is about inheritance in general and > delegation in particular as a solution to this problem. I liked the idea, > but it's just a pain to implement. > > Then I came to know https://groups.google.com/forum/#!topic/julia-users/ > Wwn3KHmmm9I, where John crafted a first implementation of what would > become the @delegate macro which is now in a RFC process in > https://github.com/JuliaLang/julia/pull/3292. This is a great solution. > The comment https://github.com/JuliaLang/julia/pull/3292# > issuecomment-34450100 in particular was of a great interest for me as it > would allow automated delegation. > With a little bit of extra work and imagination, I might be able to write > a brand new composite type like: > > type DimensionfulAndRankfulArray{T<:Number} > @delegate data::AbstractArray{T} > @delegate rank::Int for <, >, ==, !=, <=, >= > unit::String > end > > But as stated in https://github.com/JuliaLang/julia/pull/3292# > issuecomment-34551204, the macro system is limited in what it can do: for > instance, methods declared after type declaration with the @delegation > macro would not work with the delegated type as the macro has no way to > know that a new usable method is declared afterwards. With my limited > knowledge of the problem, I see at least 3 ways to solve the problem: > > - Either let it as it is now with its inconsistencies. > - Either include delegate in the language and perform delegation at > type declaration time and at method declaration time (as a compilation > hook). > - Or *tell *the compiler at type declaration time that, in our case, > any method written for AbstractArray is gonna work with your RankfulArray > because of delegation (trait-like approach with delegation :)) > > type RankfulArray{T<:Number} <: AbstractArray > delegate data::AbstractArray{T} > delegate rank::Int for <, >, ==, !=, <=, >= > end > > This could be further simplified as: > > type RankfulArray{T<:Number} > delegate data::AbstractArray{T} > rank::Int > end > if there is one and only one delegation in the type definition: in > practice, because of the delegation, there is no obvious way to distinguish > AbstractArray behavior and RankfulArray behavior. > > This would look a lot like concrete type inheritance though. > > > > > > As an extra and almost unrelated enhancement, being able to declare type > preservation for some methods would be awesome, something like: > type in_eV{T<:Number} > delegate data::AbstractArray{T} preserve +, - > end > which would mean that i*n_eV([1,2,3]).^2* would return *Array([1,4,9])* > but *in_eV([1,2,3]) + 2* would return *in_eV([3,4,5]).* > > This could be extended to preserve the type for any method: > type in_eV{T<:Number} > delegate data::AbstractArray{T} preserve > end >
