[MOAB-dev] Incomplete types versus void * in ITAPS interfaces
Onkar Sahni
osahni at scorec.rpi.edu
Mon Sep 8 08:40:55 CDT 2008
I am not going into all benefits of the inheritance as I am certainly not
the right person but will provide some examples... (I mentioned both
overloading and inheritance etc.).
One thing I didn't make it clear is that I was thinking from
user/application point of view so print_EntInfo() example was not good.
// overloading functions by users in C++
userComputeScalarIntegral(iBase_FaceHandle,...)
userComputeScalarIntegral(iBase_RegionHandle,...)
Now may be it does make much sense as iMesh doesn't really let you do
anything special with iBase_FaceHandle (like
iMesh_F_numEdges(iBase_FaceHandle...)) or iBase_RegionHandle (like
iMesh_F_numFaces(iBase_RegionHandle,...)).
// inheritance by users in C++
class userElementIntegrator() {
eval(iBase_RegionHandle);
eval(iBase_EntityHandle);
}
userElememtIntegrator::eval(iBase_RegionHandle rgn_hdl) {
// only 3D supported as of now
... user code to compute element (3D) matrix
}
userElememtIntegrator::eval(iBase_EntityHandle ent_hdl) {
// only 3D supported as of now
user_error();
}
By the way, iMesh already exposes implementation details. Infact ones
which I do not really like:
alloc=0;
iMesh_getEntAdj(...,alloc,...);
if(alloc)
free(...); // oops
- Onkar
> On Sun 2008-09-07 16:21, Tim Tautges wrote:
>> I don't think that's quite what I had in mind, based on Jed's question.
>> I see the struct pointers still as proxies for what the handles really
>> are down in the implementations; thus, my question about whether we
>> really need to define the private structure or just reference it. The
>> only thing I see us doing with these *'s is casting them to what our
>> handles really are, in the implementation. Using private struct *'s
>> simply allows us to differentiate between the various types of handles,
>> rather than using void* for all of them. That's what gives us the
>> compile time type checking.
>
> Exactly, you never need to define the private structure because you
> never dereference it. If you try to dereference it, the compiler will
> throw an error saying you are dereferencing an incomplete type instead
> of an error saying you are dereferencing void. Of course if it is
> convenient for your implementation, you are welcome to define the
> struct/class internally (then you can dereference it internally). Or
> you can just cast it as is currently done.
>
> Onkar, what is the benefit of the inheritance? You can already
> determine type/topology through the interface so print_EntInfo() is
> easily defined without any inheritance. Since you will normally have a
> plain iBase_EntityHandle, how do you get a more specific type? For
> instance, suppose I call iMesh_getEntities(...,iBase_VERTEX,...). Now I
> want to specialize them so I can call some function which requires an
> iBase_VertexHandle. To avoid casting the pointer to a more specialized
> type myself (this exposes implementation at some level), the interface
> would need a function to do this. (In debugging mode, it should
> probably confirm that the types really do match so the cast makes
> sense.) I'm not sure if this level of extra type-checking is
> beneficial.
>
>
> The following is a tangent to explain how to map the inheritance to C,
> if it was really thought to be useful. I'll take PETSc as an example.
>
> /* private */
> struct _p_PetscObject {
> struct _PetscOps *bops; /* base class virtual functions */
> /* other parent class stuff */
> };
> struct _p_Mat {
> struct _p_PetscObject hdr;
> struct _MatOps *ops; /* virtual functions for Mat interface */
> ... /* Mat specific stuff */
> };
>
> /* public */
> typedef struct _p_PetscObject *PetscObject;
> typedef struct _p_Mat *Mat;
>
> /* user */
> Mat A;
> Vec b;
> PetscObjectCompose((PetscObject)A,"special vector",(PetscObject)b);
>
>
> Since the first part of struct _p_Mat consists of the fields in
> _p_PetscObject, you get inheritance with full virtual functions. You
> cannot do protected inheritance per-se since the Mat implementation
> needs to be able to see _p_PetscObject. However, you can have a
> convention that you never dereference Mat.hdr, instead operating through
> the PetscObject interface (this is the case in PETSc). Note that we
> never cast the other way, that is, you never see
>
> PetscObject obj;
> ... /* somehow obj now points to a matrix */
> MatMult((Mat)obj,...);
>
> since this is generally not safe (and exposes implementation at least to
> the extent that PetscObject and Mat are just pointers).
>
> Our case is much lighter weight, but if you want inheritance, we can have
>
> /* interface */
> typedef struct iBase_EntityHandle_Private *iBase_EntityHandle;
> typedef struct iBase_VertexHandle_Private *iBase_VertexHandle;
>
> /* user */
> iBase_EntityHandle *ents;
> iBase_VertexHandle *verts;
> iMesh_getEntities(...,iBase_VERTEX,...,&ents,...);
> iBase_castToVtxArr(...,ents,...,&verts,...);
> iMesh_setVtxArrCoords(mesh,verts,...,coords,...);
> iMesh_setArrData(mesh,(iBase_EntityHandle*)verts,...,data,...); // also
> safe
>
> This is all `safe' but I'm not sure it's worth it. I think it might be
> hard to avoid ever needing to cast the other way (which feels like a bad
> thing to do).
>
> To come back to Onkar's suggestion, in C it would be spelled
>
> print_VertexInfo(iBase_VertexHandle,...);
> print_RegionInfo(iBase_RegionHandle,...);
>
> There isn't really more power in the C++ version (just cosmetics and you
> can use templates to generate code for many specialized cases) since the
> type needs to be statically determined at compile-time, hence it is
> actually less flexible than
>
> print_EntInfo(iBase_EntityHandle,...)
>
> which just calls iMesh_getEntType/Topo(). To get this version to do
> something special without calling iMesh_getEntType/Topo() we need
> virtual functions which means storing an extra pointer for every entity
> (in C or C++).
>
> Jed
>
More information about the moab-dev
mailing list