Merge lp://staging/~smspillaz/compiz-libcompizconfig/ccs-object into lp://staging/~compiz-team/compiz-libcompizconfig/0.9.8

Proposed by Sam Spilsbury
Status: Superseded
Proposed branch: lp://staging/~smspillaz/compiz-libcompizconfig/ccs-object
Merge into: lp://staging/~compiz-team/compiz-libcompizconfig/0.9.8
Diff against target: 690 lines (+613/-1)
6 files modified
CMakeLists.txt (+1/-0)
include/ccs.h (+101/-1)
src/CMakeLists.txt (+3/-0)
src/main.c (+179/-0)
tests/CMakeLists.txt (+56/-0)
tests/test-ccs-object.cpp (+273/-0)
To merge this branch: bzr merge lp://staging/~smspillaz/compiz-libcompizconfig/ccs-object
Reviewer Review Type Date Requested Status
Sam Spilsbury Needs Fixing
Alan Griffiths Pending
Review via email: mp+104864@code.staging.launchpad.net

This proposal supersedes a proposal from 2012-05-04.

Description of the change

This is all about bug 990690.

!! - It probably isn't a good idea to test this branch in isolation, as it is part of a pipeline to get compiz-libcompizconfig under test. If you want to test the result of this work, you should probably look at testing

lp:~smspillaz/compiz-libcompizconfig/setting-mock
lp:~smspillaz/compiz-compizconfig-python/compiz-compizconfig-python.setting-api
lp:~smspillaz/compiz-compizconfig-gconf/compiz-compizconfig-gconf.adapt-to-new-interfaces

.. that's all !!

This branch introduces some preliminary work in a series of branches to get libcompizconfig under test. In order to test the objects properly, we need to abstract away their interfaces into replacable structs so you can test the interaction between the various classes.

This would be awkward to do correctly if we didn't have a suitable object system to handle interface implementation, referencing, private storage etc.

As such, a new struct CCSObject is introduced. It is similar in design to GObject, but with a much smaller feature set centered mostly around the handling of interfaces and composition / indirection. A type registrar is also included (also very simple).

Tests are included.

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

I know it is common (and may be a project style) but there is no advantage to having different names to refer to the same thing in different namespaces. That is not:

    typedef struct _CCSObject CCSObject;

    struct _CCSObject
    {
    ...
    };

but:

    typedef struct CCSObject
    {
    ...
    } CCSObject;

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> I know it is common (and may be a project style) but there is no advantage to
> having different names to refer to the same thing in different namespaces.
> That is not:
>
> typedef struct _CCSObject CCSObject;
>
> struct _CCSObject
> {
> ...
> };
>
> but:
>
> typedef struct CCSObject
> {
> ...
> } CCSObject;

Actually, it doesn't seem that client code should be interested in the members of [_]CCSObject, so why not a completely opaque type? Vis:

    typedef struct CCSObject CCSObject;

in the header. And move the definition to the .c file.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

I don't like the style of coding in ccsObjectAddInterface() - if either realloc fails then the object is hosed. Admittedly FALSE is returned to inform the caller, but I'd prefer the object to remain viable and just the call to fail. Anything else can cause nasty surprises in client code. (Admittedly, if realloc fails there are probably worse problems to deal with.)

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> I don't like the style of coding in ccsObjectAddInterface() - if either
> realloc fails then the object is hosed. Admittedly FALSE is returned to
> inform the caller, but I'd prefer the object to remain viable and just the
> call to fail. Anything else can cause nasty surprises in client code.
> (Admittedly, if realloc fails there are probably worse problems to deal with.)

Forgot to mention: the cost of calling realloc in ccsObjectRemoveInterface probably outweighs any saving of memory that results.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> > I know it is common (and may be a project style) but there is no advantage
> to
> > having different names to refer to the same thing in different namespaces.
> > That is not:
> >
> > typedef struct _CCSObject CCSObject;
> >
> > struct _CCSObject
> > {
> > ...
> > };
> >
> > but:
> >
> > typedef struct CCSObject
> > {
> > ...
> > } CCSObject;
>
> Actually, it doesn't seem that client code should be interested in the members
> of [_]CCSObject, so why not a completely opaque type? Vis:
>
> typedef struct CCSObject CCSObject;
>
> in the header. And move the definition to the .c file.

I think the struct can't be opaque because of the way that we actually access the object data (eg, casting it to a CCSObject * and accessing the data in the CCSObject in the first part of the struct).

As for realloc - I agree and had similar concerns, and will change that.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

ccsObjectInit is only used by the test harness which ignores the return code, so the intended use is unclear. Surely a better return value would be a pointer to the initialised object?

ccsObjectRemoveInterface assigns pointers "interfaces" and "interface_types" to NULL without first freeing the memory referenced.

ccsObjectAddInterface assigns pointers "interfaces" and "interface_types" without first freeing the memory referenced.

struct _CCSObjectAllocationInterface (again, no need for the "_") has members realloc, malloc, calloc - these are reserved names.

Actually, talking of reserved names: names that begin with an underscore and a capital are reserved, which is another reason for not using these names in the struct namespace. (I still see no point in having different names (e.g. _CCSObject) in the struct namespace.)

The tests imply that the intended usage is to cast a pointer to some other structure (represented by "TestingObjectWrapper") to CCSObject* before passing that to ccsObjectXXX. If this is not the intended usage the tests are inappropriate. If it is intended there's negative value in these taking a pointer to the CCSObject as a parameter, they may as well take void* in the same way as ccsObjectInit does. It's a waste of the type-safety features of C.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Let me suggest a way that the client code could be eg "ccsObjectRef(to);"...
...
Bool ccsObjectRef_(CCSObject *object);
#define ccsObjectRef(obj) ccsObjectRef_(&obj->object)
...
No nasty casts, and type safe. At the cost of requiring a member named "object" of CCSObject type.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> ccsObjectInit is only used by the test harness which ignores the return code,
> so the intended use is unclear. Surely a better return value would be a
> pointer to the initialised object?

Indeed, future merges will introduce proper constructors (but this is not trivial right now).

>
> ccsObjectRemoveInterface assigns pointers "interfaces" and "interface_types"
> to NULL without first freeing the memory referenced.
>
> ccsObjectAddInterface assigns pointers "interfaces" and "interface_types"
> without first freeing the memory referenced.

They use realloc, so I don't see why this is a problem ?

>
> struct _CCSObjectAllocationInterface (again, no need for the "_") has members
> realloc, malloc, calloc - these are reserved names.

ack.

>
> Actually, talking of reserved names: names that begin with an underscore and a
> capital are reserved, which is another reason for not using these names in the
> struct namespace. (I still see no point in having different names (e.g.
> _CCSObject) in the struct namespace.)

Right, we should evaluate this elsewhere

>
> The tests imply that the intended usage is to cast a pointer to some other
> structure (represented by "TestingObjectWrapper") to CCSObject* before passing
> that to ccsObjectXXX. If this is not the intended usage the tests are
> inappropriate. If it is intended there's negative value in these taking a
> pointer to the CCSObject as a parameter, they may as well take void* in the
> same way as ccsObjectInit does. It's a waste of the type-safety features of
> C.

Right, this sucks, but we're introspecting the state of the object. Mabye we can get rid of the casts and just do to->object.foo

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> > ccsObjectRemoveInterface assigns pointers "interfaces" and "interface_types"
> > to NULL without first freeing the memory referenced.
> >
> > ccsObjectAddInterface assigns pointers "interfaces" and "interface_types"> >
> > without first freeing the memory referenced.
>
> They use realloc, so I don't see why this is a problem ?

Ah, I wrongly assumed you were using a function with different semantics to avoid the problems discussed earlier (i.e. invalidating the object on failed realloc).

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

ccsObjectRemoveInterface_ doesn't use realloc, so it just overwrites the pointer. I think that will leak.

ccsObjectAddInterface does use realloc (I was wrongly assuming that you'd addressed the earlier discussion of invalidating the object on failed operation). Invalidating the object and returning FALSE will cause nasty surprises in client code.

Is there really value in CCSObjectAllocationInterface?

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

These macros can lead to surprising results in user code:

86 +#define ccsObjectRef(o) \
87 + ((o)->object).refcnt++;
88 +
89 +#define ccsObjectUnref(o, freeFunc) \
90 + ((o)->object).refcnt--; \
91 + if (!((o)->object).refcnt) \
92 + freeFunc (o)

Example of problem:

  if (false) ccsObjectUnref(o, f);

will call f(o).

Rewrite as:
86 +#define ccsObjectRef(o) \
87 + do { ((o)->object).refcnt++ } while(false)
88 +
89 +#define ccsObjectUnref(o, freeFunc) \
90 + do { ((o)->object).refcnt--; \
91 + if (!((o)->object).refcnt) \
92 + freeFunc (o) } while(false)

PS It feels awkward to require freeFunc as a parameter, but I don't have a cleaner alternative suggestion just now.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Bad example.

  if (false) ccsObjectUnref(o, f);

is OK.

But...

  if (true) ccsObjectUnref(o, f);
  else printf("surprise");

is a good example (i.e. broken).

437. By Sam Spilsbury

Free interfaces once objects are removed

438. By Sam Spilsbury

Fix potential macro problems

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Keeping old status

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

>ccsObjectRemoveInterface_ doesn't use realloc, so it just overwrites the pointer. I think that will leak.

Fixed as discussed

> ccsObjectAddInterface does use realloc (I was wrongly assuming that you'd addressed the earlier discussion of invalidating the object on failed operation). Invalidating the object and returning FALSE will cause nasty surprises in client code.

Not an issue as discussed on irc. (realloc (foo, sizeof (whatever)); doesn't invalidate foo if realloc fails)

> Is there really value in CCSObjectAllocationInterface?

Yes, for mocking allocation failures. Feel crap having to inject it, but there isn't much of an alternative

> Bad example.

> if (false) ccsObjectUnref(o, f);

> is OK.

> But...

> if (true) ccsObjectUnref(o, f);
> else printf("surprise");

> is a good example (i.e. broken).

Fixed as discussed

> PS It feels awkward to require freeFunc as a parameter, but I don't have a cleaner alternative suggestion just now.

If / when we add proper constructor / destructor semantics this will go away :) (That's a larger change though that should be done later)

439. By Sam Spilsbury

Lose the ;

440. By Sam Spilsbury

Added a free thread

441. By Sam Spilsbury

Also test for free

Unmerged revisions

441. By Sam Spilsbury

Also test for free

440. By Sam Spilsbury

Added a free thread

439. By Sam Spilsbury

Lose the ;

438. By Sam Spilsbury

Fix potential macro problems

437. By Sam Spilsbury

Free interfaces once objects are removed

436. By Sam Spilsbury

Don't use reserved name

435. By Sam Spilsbury

Make the CCSObject API a bit more typesafe

434. By Sam Spilsbury

Don't reallocate all the time. Also handle realloc failures better

433. By Sam Spilsbury

Added a simple type registrar

432. By Sam Spilsbury

Added a ccsObjectFinalize function which frees everything in CCSObject storage

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches