Right now, there is no mechanism for doing the delegation I described earlier beyond simple macros like those I wrote up a long time ago.
For your use case, you would really want a method that wraps a given type in a new immutable type and then delegates all methods to the contained type unless they are explicitly overriden. Currently, that's not possible without a lot of legwork. Since it seems like you mostly want to guarantee invariant properties of your data, you can just write functions that don't break those invariants when operating a standard DataFrame and then call them. The compiler won't give you provable guarantees that those invariants are never broken, but your code still will respect them. If the compiler gets new abilities, you could then easily upgrade your methods to refer to a new type that imposes the desired invariants. -- John On Jan 2, 2014, at 2:00 PM, Christian Groll <[email protected]> wrote: > Recapturing, it hence seems like julia does not support this feature - > although I must admit that I did not get all the details in the answers ;-) > > Still, however, I would like to find some reasonable workaround to this > problem. In my opinion, the dataframe type should probably really cover > almost all cases of data storage in statistics / data analysis. Nevertheless, > I would very much like to be able to allow for some distinction between > different datasets. Hence, ideally I would like to have a type that behaves > almost exactly like a dataframe, while I am still able to overload certain > methods. For example, if I know that my dataset contains time series data, a > visualization plot(df::dataframe) should look different than a visualization > for geographic data on a map. Also, different datasets come with different > constraints: portfolio weights must sum to 1, correlations must be between -1 > and 1, and so forth. Isn't there any way to reasonably implement this without > each time starting a new type from scratch? > > I was only calling it subtype because I somewhere stumbled upon the advice > that it could work with subtyping the AbstractDataFrame type, but I didn't > get this running. Any tips on whether / how this would work? > > Alternatively, I also found somewhere else a code snippet of John Myles White > about a redirect or delegate macro: > macro redirect(t, comp, fname) > t = esc(t) > comp = esc(comp) > fname = esc(fname) > quote > ($fname)(a::($t), args...) = ($fname)(a.($comp), args...) > end > end > > This at least could be a starting point to give a new type the behavior of a > dataframe. Is there any update on this macro? > > At last, I still do not get the memory problem with subtyping composite types > for my exact case. The subtypes that I would like to have do NOT have any > additional fields compared to their parent. They only shall help to allow > function dispatch and implementation of some constraints. A Portfolio type > still is nothing else than a dataframe, only that its values sum up to one. > You definitely need not further explain the memory issues here to me, because > I most likely do not understand them anyways. But are you really sure that > such a Portfolio type would have different memory requirements than a > dataframe? In effect, it should be nothing different, but only one special > case of all possible dataframes. > > On Thursday, 2 January 2014 16:53:18 UTC+1, Stefan Karpinski wrote: > On Thu, Jan 2, 2014 at 10:01 AM, Mauro <[email protected]> wrote: > Only abstract types can be subtyped (and if I recall correctly this is going > to stay that way for some type-theory-reason). > > It's not for a type theory reason – if anything, it's the opposite of a type > theory reason. If Float64 can be subtyped, then then an Array{Float64} can > hold objects of arbitrary size. Thus, you can't represent it as inline data, > but rather have to store the array as pointers to boxed, heap-allocated > values. Not only is this horribly inefficient (200% storage overhead on > 64-bit machines), but it completely destroys interoperability with BLAS, > FFTW, etc. > > Some o.o. languages have allowed declaring types to be "final" as a way of > dealing with this issue (you also need immutability and/or value types to > fully solve the array storage problem). After a few decades of real-world > o.o. programming, however, the best practice that's emerged is that you > should only subtype intentional supertypes – types that are very carefully > designed to be subtypeable. Where a classically o.o. language might do Ac :> > Bc, where Ac and Bc are both concrete and Ac is a supertype of Bc, in Julia > you would have Aj' :> Aj, Bj where the abstract aspect of Ac is distilled > into the purely abstract type, Aj', while the concrete aspect of Ac is > implemented by Aj, which is a sibling of Bj instead of its parent. I've found > that while this requires a slight shift in thinking, the resulting designs > tend to be much better: the abstract behavioral aspect of Aj' is completely > separated from any implementation concerns since you're not allowed to mix > them. >
