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
