Re: [julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner


On Wednesday, 4 February 2015 20:02:43 UTC, Josh Langsfeld wrote:
>
> On Wed, Feb 4, 2015 at 2:29 PM, Christoph Ortner  > wrote:
>
> 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.
>>
>
> Basically, if you know all subtypes of AbstractAtoms have a field 'num' 
> then 'getnumatoms(a::AbstractAtoms) = a.num' will work fine and will only 
> error if any new subtype doesn't have the field. However, if the 
> AbstractAtoms structure relies on that field existing and it doesn't make 
> sense to have it for a certain subtype, then the structure has to be 
> refactored to rely on methods instead, which can be (NOT must be) 
> reimplemented by the subtypes.
>

Yes, I see that - I was primarily concerned whether this was "good style".

 

> 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).
>>
>
> That would certainly work, though ideally there would be no need to 
> defined the interface to be coupled like that. There should be an 
> abstraction of all calculator types that would provide whatever methods 
> get_forces needs to do its thing. Or maybe it's reversed with specific 
> Calculator types able to depend on AbstractAtoms only. Either way, you 
> wouldn't need a get_forces(a,c) method for every possible type a and c can 
> take.
>

Indeed, most Calculators need no more than AbstractAtoms type information, 
but need to know nothing about which subtype.

After this discussion, I think this is the way I will go. Thanks a lot.
 Christoph


Re: [julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
On Wed, Feb 4, 2015 at 2:29 PM, Christoph Ortner  wrote:

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.
>

Basically, if you know all subtypes of AbstractAtoms have a field 'num'
then 'getnumatoms(a::AbstractAtoms) = a.num' will work fine and will only
error if any new subtype doesn't have the field. However, if the
AbstractAtoms structure relies on that field existing and it doesn't make
sense to have it for a certain subtype, then the structure has to be
refactored to rely on methods instead, which can be (NOT must be)
reimplemented by the subtypes.

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).
>

That would certainly work, though ideally there would be no need to defined
the interface to be coupled like that. There should be an abstraction of
all calculator types that would provide whatever methods get_forces needs
to do its thing. Or maybe it's reversed with specific Calculator types able
to depend on AbstractAtoms only. Either way, you wouldn't need a
get_forces(a,c) method for every possible type a and c can take.


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner
> thought one problem with not having "proper" inheritance is that this 
doesn't really help?

>
> I meant more about commonality of behaviour. 
>

I think this goes exactly in the direction that I discuss in the last post? 
I just "assume" for the Abstract versions of the different types how they 
will behave, and if they don't behave that way, then whoever wrote the 
extension (likely me anyhow) will need to overload the relevant methods. (?)

Thanks,
   Christoph



[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner


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


 


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
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.

> 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.


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Avik Sengupta


On Wednesday, 4 February 2015 17:46:58 UTC, Christoph Ortner wrote:
>
> On Wednesday, 4 February 2015 16:59:14 UTC, Avik Sengupta wrote:
>
>> I don't understand your domain of course, but the way I'd do this would 
>>> be a slight variant of OPTION 1
>>>
>>> get_forces(a::AbstractAtom) = error("All AbstractAtom subtypes should 
>>> implement get_forces")
>>> get_forces(a::Atom) = get_forces(a.calc)
>>>
>>>
>> this is indeed what I've done at the moment. Good to hear that this is 
>> not completely idiotic. 
>>
>  
> Ok, actually this is slightly different - so I don't understand why this 
> would help? Is it just the fact that not all implementations of 
> AbstractAtoms need to have a field `calc`?
>
>
Well, yes, that is one reason, but that may or may not be true in your 
case.  Mainly, the idea is to ensure that if some subtype fails to 
implement its get_forces method, then the error message will be explicit 
about what should be fixed. 

> thought one problem with not having "proper" inheritance is that this 
doesn't really help?

I meant more about commonality of behaviour. 
 


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner
On Wednesday, 4 February 2015 16:59:14 UTC, Avik Sengupta wrote:

> I don't understand your domain of course, but the way I'd do this would be 
>> a slight variant of OPTION 1
>>
>> get_forces(a::AbstractAtom) = error("All AbstractAtom subtypes should 
>> implement get_forces")
>> get_forces(a::Atom) = get_forces(a.calc)
>>
>>
> this is indeed what I've done at the moment. Good to hear that this is not 
> completely idiotic. 
>
 
Ok, actually this is slightly different - so I don't understand why this 
would help? Is it just the fact that not all implementations of 
AbstractAtoms need to have a field `calc`?

Many thanks,
Christoph  


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner
I don't understand your domain of course, but the way I'd do this would be 
a slight variant of OPTION 1

>
>> get_forces(a::AbstractAtom) = error("All AbstractAtom subtypes should 
>> implement get_forces")
>> get_forces(a::Atom) = get_forces(a.calc)
>>
>>
> this is indeed what I've done at the moment. Good to hear that this is not 
> completely idiotic. 
>

Ok, actually this is slightly different - so I don't understand why this 
would help?

Many thanks,
Christoph 

>  
>


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner


On Wednesday, 4 February 2015 16:59:14 UTC, Avik Sengupta wrote:
>
> I don't understand your domain of course, but the way I'd do this would be 
> a slight variant of OPTION 1
>
> get_forces(a::AbstractAtom) = error("All AbstractAtom subtypes should 
> implement get_forces")
> get_forces(a::Atom) = get_forces(a.calc)
>
>
this is indeed what I've done at the moment. Good to hear that this is not 
completely idiotic. 
 

> I think the point to ponder is, what amount of commonality does all 
> possible Atoms contain? 
>

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?
 


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner

Many thanks for the discussion.

On Wednesday, 4 February 2015 16:46:09 UTC, Josh Langsfeld wrote:
>
> For me, option 1 looks the most Julian. Maybe the clunkiness is arising 
> because the calc object shouldn't be a field of Atoms? Fields are just 
> suppose to store data, not logic or methods. 
>

Indeed, that is how I use them. But the Calculator stores, e.g., model 
parameters.
 

> If a certain subtype of AbstractAtoms always uses the same calc object, 
> then dispatching just on the atoms should be sufficient. 
>

Unfortunately, that is not the case.
 

> If it can vary, maybe it would be more elegant to associate them together 
> in some other way than a type field and then directly dispatch on both 
> values.
>

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.
 

> Also, for option 2, why couldn't you give both AbstractAtoms and its 
> subtypes just a single type parameter for the calculator?
>

Because the same issues arise for NeighbourLists, for Preconditioners and 
potentially other objects that will be linked to Atoms type objects.

I wonder whether I am making things too complicated here?


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Avik Sengupta
I don't understand your domain of course, but the way I'd do this would be 
a slight variant of OPTION 1

get_forces(a::AbstractAtom) = error("All AbstractAtom subtypes should 
implement get_forces")
get_forces(a::Atom) = get_forces(a.calc)

I think the point to ponder is, what amount of commonality does all 
possible Atoms contain? 

Regards
-
Avik

On Wednesday, 4 February 2015 15:16:02 UTC, Christoph Ortner wrote:
>
>
> I am trying to re-structure a molecular simulation code I've been working 
> on, to make it more readily extendable. I am puzzling over how to do this 
> most effectively in Julia, and would appreciate any thoughts from more 
> experienced Julia programmers. I am roughly trying to mimic the structure 
> of CAMPOS ASE ( a Python package ).
>
> The main type that contains the simulation state is 
>
>abstract AbstractAtoms
>
> The simplest sub-type is (here a simplified version)
>
> type Atoms
> X::Array{Float64, 2}#  positions of atoms
> calc #  calculator for computing 
> energies, forces, etc
> neigs   # neighbourlist
> precon # preconditioner
> end
>
> but there could be many other sub-types that store atom positions 
> differently, or live on manifolds, or contain information for continuum 
> mechanics boundary conditions, etc.
>
> I now need functions that depends on the type of the atoms object and on 
> the type of calculator object.  (for example). 
>
> OPTION 1:At the moment, my thinking is that I can do
>
>function get_forces(atoms::AbstractAtoms)
>return get_forces(atoms, atoms.calc)
>end
>
> and the type of `atoms` and of `atoms.calc` will then determine which 
> function is called. This feels a bit clunky to be honest, but looks like 
> the best way to go?
>
>
> OPTION 2:  Another thought that I had, was to define
>
>type Atoms{CT, NT, PT}
> X::Array{Float64, 2}#  positions of atoms
> calc::CT #  calculator for computing 
> energies, forces, etc
> neigs::NT   # neighbourlist
> precon::PT # preconditioner
> end
>
>function get_forces(atoms::Atoms{MyCalculator,NT,PT})
># . . .
>end
>
> and to determine the type of the calculator this way. The problem there is 
> that I cannot give AbstractAtoms the parameters {CT, NT, PT} because other 
> sub-types might use a different, possibly longer, possibly shorter list of 
> parameters.
>
>
> I'd be very grateful for any advise what sort of constructions would be 
> the most convenient / useful to try out here.
>
> Many thanks,
> Christoph
>
>
>
>
>
>

[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
Sorry, disregard that last sentence which was supposed to have been edited 
out.

On Wednesday, February 4, 2015 at 11:46:09 AM UTC-5, Josh Langsfeld wrote:
>
> For me, option 1 looks the most Julian. Maybe the clunkiness is arising 
> because the calc object shouldn't be a field of Atoms? Fields are just 
> suppose to store data, not logic or methods. If a certain subtype of 
> AbstractAtoms always uses the same calc object, then dispatching just on 
> the atoms should be sufficient. If it can vary, maybe it would be more 
> elegant to associate them together in some other way than a type field and 
> then directly dispatch on both values.
>
> Also, for option 2, why couldn't you give both AbstractAtoms and its 
> subtypes just a single type parameter for the calculator?
>
> and now it looks like proper Julian code where you pass objects to methods.
>
> On Wednesday, February 4, 2015 at 10:16:02 AM UTC-5, Christoph Ortner 
> wrote:
>>
>>
>> I am trying to re-structure a molecular simulation code I've been working 
>> on, to make it more readily extendable. I am puzzling over how to do this 
>> most effectively in Julia, and would appreciate any thoughts from more 
>> experienced Julia programmers. I am roughly trying to mimic the structure 
>> of CAMPOS ASE ( a Python package ).
>>
>> The main type that contains the simulation state is 
>>
>>abstract AbstractAtoms
>>
>> The simplest sub-type is (here a simplified version)
>>
>> type Atoms
>> X::Array{Float64, 2}#  positions of atoms
>> calc #  calculator for computing 
>> energies, forces, etc
>> neigs   # neighbourlist
>> precon # preconditioner
>> end
>>
>> but there could be many other sub-types that store atom positions 
>> differently, or live on manifolds, or contain information for continuum 
>> mechanics boundary conditions, etc.
>>
>> I now need functions that depends on the type of the atoms object and on 
>> the type of calculator object.  (for example). 
>>
>> OPTION 1:At the moment, my thinking is that I can do
>>
>>function get_forces(atoms::AbstractAtoms)
>>return get_forces(atoms, atoms.calc)
>>end
>>
>> and the type of `atoms` and of `atoms.calc` will then determine which 
>> function is called. This feels a bit clunky to be honest, but looks like 
>> the best way to go?
>>
>>
>> OPTION 2:  Another thought that I had, was to define
>>
>>type Atoms{CT, NT, PT}
>> X::Array{Float64, 2}#  positions of atoms
>> calc::CT #  calculator for computing 
>> energies, forces, etc
>> neigs::NT   # neighbourlist
>> precon::PT # preconditioner
>> end
>>
>>function get_forces(atoms::Atoms{MyCalculator,NT,PT})
>># . . .
>>end
>>
>> and to determine the type of the calculator this way. The problem there 
>> is that I cannot give AbstractAtoms the parameters {CT, NT, PT} because 
>> other sub-types might use a different, possibly longer, possibly shorter 
>> list of parameters.
>>
>>
>> I'd be very grateful for any advise what sort of constructions would be 
>> the most convenient / useful to try out here.
>>
>> Many thanks,
>> Christoph
>>
>>
>>
>>
>>
>>

[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
For me, option 1 looks the most Julian. Maybe the clunkiness is arising 
because the calc object shouldn't be a field of Atoms? Fields are just 
suppose to store data, not logic or methods. If a certain subtype of 
AbstractAtoms always uses the same calc object, then dispatching just on 
the atoms should be sufficient. If it can vary, maybe it would be more 
elegant to associate them together in some other way than a type field and 
then directly dispatch on both values.

Also, for option 2, why couldn't you give both AbstractAtoms and its 
subtypes just a single type parameter for the calculator?

and now it looks like proper Julian code where you pass objects to methods.

On Wednesday, February 4, 2015 at 10:16:02 AM UTC-5, Christoph Ortner wrote:
>
>
> I am trying to re-structure a molecular simulation code I've been working 
> on, to make it more readily extendable. I am puzzling over how to do this 
> most effectively in Julia, and would appreciate any thoughts from more 
> experienced Julia programmers. I am roughly trying to mimic the structure 
> of CAMPOS ASE ( a Python package ).
>
> The main type that contains the simulation state is 
>
>abstract AbstractAtoms
>
> The simplest sub-type is (here a simplified version)
>
> type Atoms
> X::Array{Float64, 2}#  positions of atoms
> calc #  calculator for computing 
> energies, forces, etc
> neigs   # neighbourlist
> precon # preconditioner
> end
>
> but there could be many other sub-types that store atom positions 
> differently, or live on manifolds, or contain information for continuum 
> mechanics boundary conditions, etc.
>
> I now need functions that depends on the type of the atoms object and on 
> the type of calculator object.  (for example). 
>
> OPTION 1:At the moment, my thinking is that I can do
>
>function get_forces(atoms::AbstractAtoms)
>return get_forces(atoms, atoms.calc)
>end
>
> and the type of `atoms` and of `atoms.calc` will then determine which 
> function is called. This feels a bit clunky to be honest, but looks like 
> the best way to go?
>
>
> OPTION 2:  Another thought that I had, was to define
>
>type Atoms{CT, NT, PT}
> X::Array{Float64, 2}#  positions of atoms
> calc::CT #  calculator for computing 
> energies, forces, etc
> neigs::NT   # neighbourlist
> precon::PT # preconditioner
> end
>
>function get_forces(atoms::Atoms{MyCalculator,NT,PT})
># . . .
>end
>
> and to determine the type of the calculator this way. The problem there is 
> that I cannot give AbstractAtoms the parameters {CT, NT, PT} because other 
> sub-types might use a different, possibly longer, possibly shorter list of 
> parameters.
>
>
> I'd be very grateful for any advise what sort of constructions would be 
> the most convenient / useful to try out here.
>
> Many thanks,
> Christoph
>
>
>
>
>
>