This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Interoperating w/ C++ (was Re: structs, records, SMOBs etc.)


Jim Blandy <jimb@red-bean.com> writes:

> One of Guile's primary goals is to interoperate smoothly with C and
> C++ code.  This is more important than performance, for example.  So
> this property will not go away.

Speaking of interoperating with C++, I have a design question about
wrapping C++ objects.  I've found it really easy to wrap C++ objects
with guile (see the template file I include below which I've used to
make it especially easy), but I'm concerned about the grunt work in
rewrapping subclasses.  

In particular, suppose I have a class Foo that I've already got wrapped
nicely in guile so I have primitives (make-foo), (foo? FOO), and the
SMOB functions all taken care of.  Now I want to change some of the
dynamic behaviour of class Foo by public inheritance and override: i.e.,
class Bar: public Foo { ... }.  My concern is that I now need to re-wrap 
the derived class to maintain type-safety.

One possible solution is to keep the base class's SMOB identifier in the
derived class.  Then I'd just need to add new (make-bar) and (bar? BAR)
primitives, where the latter would do a (foo? BAR) and use C++'s RTTI to 
see if a downcast is safe.

Alternatively, I could avoid using C++'s virtual function mechanism at
all, and have C-style callbacks and hooks in the C++ class instead of
using the language-level features.

Does anybody have any experience, wisdom, or thoughts on this matter?

Thanks,
Greg

Here's my C++->guile wraper template file -- comments are welcome and
appreciate -- I use this with an auto-insert mode with Emacs.  (Sorry
for the length of this).

//// $Id: new-type-skeleton.cc,v 1.3 1998/07/19 22:01:22 gjb Exp $
//// Skeleton to use for creating a new type for GUILE
//// (C) 1998, By Greg J. Badros -- 18 July 1998
// SCMTYPE: %[SCMTYPE (e.g., cl_variable -- a C identifier)? %]
// SCM object name: %[SCM object name (e.g., cl-variable -- a Scheme id)? %]
// Wrapped type name: %[Wrapped Type Name (e.g., ClVariable)? %]
// Hungarian Tag: %[Hungarian tag name (e.g, clv)? %]
// By %U
// %d

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <guile/gh.h>

#include <assert.h>
#include "scwm.h"

#define %F_IMPLEMENTATION
#include "%b.h"

#ifdef __cplusplus
extern "C" {
#endif

#define NEW(x) ((x *) safemalloc(sizeof(x)))
#define NEWC(c,x) ((x *) safemalloc((c)*sizeof(x)))
#define FREE(x) free(x)

inline SCM SCM_BOOL_FromF(bool f) { return (f? SCM_BOOL_T: SCM_BOOL_F); }
inline bool FUnsetSCM(SCM scm) { return (scm == SCM_UNDEFINED || scm == SCM_BOOL_F); }


//// %3 wrapper
#undef SCMTYPEID
#define SCMTYPEID scm_tc16_%1

long SCMTYPEID;

inline bool FIs%3Scm(SCM scm) 
{ return SCM_NIMP(scm) && SCM_CAR(scm) == (SCM) SCMTYPEID; }

inline %3 *P%4FromScm(SCM scm)
{ return (%3 *)(SCM_CDR(scm)); }

SCM
mark_%1(SCM scm)
{
  SCM_SETGC8MARK(scm);
  return SCM_BOOL_F;
}

size_t
free_%1(SCM scm)
{
  %3 *p%4 = P%4FromScm(scm);
  delete p%4;
  return 0;
}

int
print_%1(SCM scm, SCM port, scm_print_state *pstate)
{
  strstream ss;
  %3 *p%4 = P%4FromScm(scm);
  ss << "#<%2" << *p%4 << ">" << ends;
  scm_puts(ss.str(), port);
  return 1;
}

SCWM_PROC (%1_p, "%2?", 1, 0, 0,
           (SCM scm))
#define FUNC_NAME s_%1_p
{
  return SCM_BOOL_FromF(FIs%3Scm(scm));
}
#undef FUNC_NAME

SCWM_PROC (make_%1, "make-%2", 0, 0, 0,
           ())
#define FUNC_NAME s_make_%1
{
  int iarg = 1;

%@
#if 0 // FIXME
  if (!FUnsetSCM(scm)) {
    if ( ) {
      scm_wrong_type_arg(FUNC_NAME, iarg++, scm);
    } else {
      sz = gh_scm2newstr(scm,NULL);
      p = PFromScm(scm);
    }
  }
#endif

  %3 *p%4 = new %3();

  SCM answer;

  SCM_DEFER_INTS;
  SCM_NEWCELL(answer);
  SCM_SETCAR(answer, (SCM) SCMTYPEID);
  SCM_SETCDR(answer, (SCM) p%4);
  SCM_ALLOW_INTS;

  return answer;
}
#undef FUNC_NAME


#if 0 // PRIMITIVE FUNCTION TEMPLATE
SCWM_PROC (, , 0, 0, 0,
           ())
#define FUNC_NAME s_
{
  return SCM_UNDEFINED;
}
#undef FUNC_NAME
#endif


MAKE_SMOBFUNS(%1);

void
init_%b()
{
  REGISTER_SCWMSMOBFUNS(%1);

#ifndef SCM_MAGIC_SNARFER
#include "%b.x"
#endif
}

#ifdef __cplusplus
} // extern "C"
#endif