On 20 May 2013 15:01, Anders Logg <[email protected]> wrote:
> On Mon, May 20, 2013 at 02:49:36PM +0100, Garth N. Wells wrote:
>> On 20 May 2013 14:33, Anders Logg <[email protected]> wrote:
>> > On Mon, May 20, 2013 at 01:09:20PM +0100, Garth N. Wells wrote:
>> >> On 20 May 2013 12:44, David Ham <[email protected]> wrote:
>> >> > Hi all,
>> >> >
>> >> > I'm writing Dolfin-compatible wrappers for PyOP2 as previously 
>> >> > advertised at
>> >> > FEniCS '13, which is causing me to bump into one of the "interesting" 
>> >> > quirks
>> >> > of the Python Dolfin API. Lots of things which would appear to 
>> >> > naturally be
>> >> > properties are actually methods and have to be called to be accessed. 
>> >> > For
>> >> > one among many, many examples, consider the value_size method of a 
>> >> > Function.
>> >> > This is accessed with:
>> >> >
>> >> > f.value_size()
>> >> >
>> >> > while
>> >> >
>> >> > f.value_size
>> >> >
>> >> > would seem more natural. Given the existence of the @property decorator 
>> >> > in
>> >> > standard Python which translates the former into the latter, this is
>> >> > particularly mysterious. Is there a reason why this is done in Dolfin?
>> >> >
>> >>
>> >> A few of us discussed this in January.  I agree that the latter is 
>> >> cleaner.
>> >>
>> >> First point, the Python interface is largely generated automatically,
>> >> so that's our starting position. We would save on C++ code and get the
>> >> syntax ' f.value_size' in many cases by not accessing member data via
>> >> functions. I like skipping the function, and have been doing so lately
>> >> with new code. The issue we discussed in January was backwards
>> >> compatibility - we could make a lot of C++ changes to get the syntax
>> >> 'f.size', but users would have to update their code (this point
>> >> bothers me less than it does others :)).
>> >>
>> >> In some cases we need a method, e.g.  to get the size of a vector from
>> >> a linear algebra backend. Storing the size in a wrapper is error
>> >> prone.
>> >>
>> >> In summary, the reason for the interface in some parts is
>> >> history/convention (with no technical reason), and in other cases it's
>> >> a method for technical reasons. We could move more towards direct
>> >> access to member data.
>> >
>> > I don't agree with these conlusions.
>> >
>> > The reasons for the use of methods are:
>> >
>> > 1. Tradition: following some C++ guidelines we read 10 years back that
>> > member data should never be accessed directly.
>> >
>>
>> It's done at times in the STL, e.g std::pair.
>
> Yes, this is a good example of where it makes sense.
>
>> > 2. Safety: Being able to access member variables means they can be
>> > changed from the outside (for a non-const object). This might lead to
>> > all kinds of unwanted behavior. A member variable can rarely be
>> > changed safely without changing a whole bunch of other data.
>> >
>>
>> If the data must be hidden, then it can be hidden behind a function.
>> Otherwise, if the object is const, then member data cannot be changed
>> and only const functions can be called on the data.
>> Something that would make things cleaner around the code would be to
>> let more objects have immutable data (e.g., not allow Vector
>> resizing), which allows some member data to be made const.
>
> How does one disallow changing a member variable in C++ except making
> it private (as we do now) or making it const (which means not even the
> class itself can change the value)?
>

Which is what I said - " If the data must be hidden, then it can be
hidden behind a function.", i.e. make it private, and which is what we
do now.

>> At present we have annoying code duplication in numerous classes to
>> provide const and non-const access functions.
>
> Agree.
>
>> > 3. Consistency: Sometimes, there is no member data to be accessed but
>> > it gets computed or extracted by the accessor function. This means if
>> > we moved to more access of member data, there would be mix of both and
>> > it would be confusing and inconsistent.
>> >
>>
>> This is a major plus to accessing data directly. It makes explicit
>> that accessing a data member involves no computation.
>
> This is why we try to name those functions compute_foo rather than
> foo.
>

We try, but we don't always succeed :).

>> > On top of theses strong reasons (2 + 3), we would also break the
>> > interface.
>>
>> Which is a drawback.
>
> Just to be clear, I agree with both of you that foo.bar is prettier
> than foo.bar() and therefore an interesting proposal, if it can be
> done in a safe and consistent way.
>

I think we're on the same page here.

This topic is at the forefront of my mind because of some fixing of
circular dependencies in MeshDomain/MeshData - we have classes and
members functions to basically give access to a std::map. It would be
simpler just to make the map a member of Mesh.

Garth


> --
> Anders
_______________________________________________
fenics mailing list
[email protected]
http://fenicsproject.org/mailman/listinfo/fenics

Reply via email to