On Wednesday, 4 February 2015 18:30:06 UTC, Josh Langsfeld wrote: > > I'm very much enjoying thinking about this and considering what might be > the most Julian approach > > > I thought one problem with not having "proper" inheritance is that this > doesn't really help? Even small variations across AbstractAtoms types > require a full implementation? > > Actually, I don't think there's any substantial difference with Julia's > inheritance model. Because if the concrete types share field names, methods > can still access those fields even when they only know they have an > abstract type. And if the fields are different, then any inheritance model > would require a new implementation. The only difference is that in the case > of same-name fields, the declarations must be repeated for each concrete > type, which a fairly mild tax given that a macro can do it easily. >
If I read this correctly, then what you are saying is that I am allowed to assume that my concrete abstract subtypes will contain certain fields, and if they don't then too bad for them, they need to go and re-implement some of the structure that I provide for AbstractAtoms. > This was my initial thought as well. The problem with that is that the > Atom and Calculator, NeighbourList and Preconditioner objects are "linked": > when Atoms is updated, then a "message" is sent to Calculator, > Preconditioner and NeighbourList so that they can update themselves also. > The Calculator, NeighbourList and Preconditioner objects in fact store > additional data that is dependent on the data stored in Atoms. > > > Because the same issues arise for NeighbourLists, for Preconditioners > and potentially other objects that will be linked to Atoms type objects. > > If you don't even know which objects will be linked when get_forces is > first called, then I don't think you have any choice but to dispatch twice. > First on the type of atoms, and second on the type of the internal > variables, just as you did in your Option 1 code. But I think you can avoid > the clunkiness by being a bit more fastidious about defining an interface > for AbstractCalculator, AbstractPreConditioner, etc... and use those > interface methods instead of just forwarding everything to a more > specialized version of get_forces. That is, you might have something like > getparam1(::AbstractCalculator) and then get_forces can directly send it > a.calc without worrying exactly what type it is. But if the other object > implementations are so different that no interface is possible, then yeah, > I think you just have to write a different method for each possible > combination of types. > How about this then; in this case a new AbstractAtoms sub-type or a new AbstractCalculator sub-type would not need to implement the "interface" get_forces(a), but only the get_forces(a, c). type Atoms <: AbstractAtoms X calc neigs precon end get_forces(a::AbstractAtoms) = get_forces(a, a.calc) or even, as Avik Sengupta suggests, if an AbstractCalculator `c` has a field c.atoms, with a.calc.atoms == a, then I could even call get_forces(a::AbstractAtoms) = get_forces(a.calc) function get_forces(a::AbstractAtoms, c::AbstractCalculator) ta = typeof(a); tc = typeof(c) error("get_forces(::$ta, ::$tc) has not been implemented") end Thanks, I really appreciate this discussion. Christoph