caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "David McClain" <dmcclain1@mindspring.com>
To: "Brian Hurt" <bhurt@spnz.org>
Cc: <caml-list@inria.fr>
Subject: Re: [Caml-list] C++ Throws
Date: Fri, 27 Aug 2004 17:22:40 -0700	[thread overview]
Message-ID: <001901c48c95$25df1850$0201000a@dylan> (raw)
In-Reply-To: <Pine.LNX.4.44.0408271818480.5809-100000@localhost.localdomain>

[-- Attachment #1: Type: text/plain, Size: 3433 bytes --]

The main reason I was looking for a higher level generic mechanism for
catching C++ throws is the desparate lack of functional closures in C++. If
there were such a thing, then it would easy to wrap all the lower level
calls in a safe try-catch block which has the closure passed to it...

Alas, I sat down and invented a poor-man's functional closure system for
C++, along the lines of CAMLparam1, etc....

The world is welcome to this... (attached) It is intended for use in OCaml
C++ interface stubs, hence the use of value parameters in the closure
classes.

An example of its use is here:
// -----------------------------------------------------------
extern "C"
void foreign_array_blit_ml_to_f(value varr1, value voff1,
value varr2, value voff2, value vnel)
{
    VClosure5(clos,
        varr1,voff1,varr2,voff2,vnel,
        {
            long off1 = Long_val(VClArg(voff1));
            long nel = Long_val(VClArg(vnel));
            foreign_array fsrc(FOREIGN_DOUBLE, 1, &nel,
            (void*)((double*)VClArg(varr1) + off1),
            foreign_array::STATIC);
            long off2 = Long_val(VClArg(voff2));
            foreign_array *pdst = pdata(VClArg(varr2));
            array_blit(&fsrc, 0, pdst, off2, nel);
        },
        &varr1);
    safe_call(clos);
}
// -----------------------------------------------------------

- DM

----- Original Message ----- 
From: "Brian Hurt" <bhurt@spnz.org>
To: "David McClain" <David.McClain@Avisere.com>
Cc: <caml-list@inria.fr>
Sent: Friday, August 27, 2004 16:24
Subject: Re: [Caml-list] C++ Throws


> On Fri, 27 Aug 2004, David McClain wrote:
>
> > I now see that OCaml is not converting anything, per se... Apparently
> > when the throw handler detects an unhandled condition it decides to
> > call abort(), against which there is no defense.
>
> I don't know what precisely is going on here, but Ocaml interfaces to C,
> which doesn't know anything about exceptions.  You might try something
> like (sorry, I'm no C++ guru):
>
> extern "C" value foo(value c);
>
> value foo(value C) {
>     /* normal Ocaml wrapper code for C */
>     try {
>         /* exception throwing code for C++. */
>     }
>     with (Exception e) {
>         /* Translate the C++ exception to an Ocaml exception */
>     }
> }
>
> The big difference between a C++ function and C function is the name
> mangling.  I doubt Ocaml could find a C++ function for linking after it
> was name mangled.  So the extern "C" tells C++ to not namemangle the
> function name.
>
> There is no way I know of to determine what exceptions a function call
> might throw.
>
> > So there appears to be something relatively complex going on across the
> > foreign function interface with OCaml and C. This override is what
> > frustrates the attempts to create a generic C++ exception handler.
>
> I think you also have a C/C++ interface problem (and yes, Virginia, they
> do exist).
>
> -- 
> "Usenet is like a herd of performing elephants with diarrhea -- massive,
> difficult to redirect, awe-inspiring, entertaining, and a source of
> mind-boggling amounts of excrement when you least expect it."
>                                 - Gene Spafford
> Brian
>
> -------------------
> To unsubscribe, mail caml-list-request@inria.fr Archives:
http://caml.inria.fr
> Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ:
http://caml.inria.fr/FAQ/
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>

[-- Attachment #2: TClosure.h --]
[-- Type: application/octet-stream, Size: 2598 bytes --]

// TClosure.h -- Simulation of Functional Closures in C++
// DM/MCFA  08/04
//
#ifndef __TCLOSURE_H__
#define __TCLOSURE_H__

extern "C" {
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/fail.h>
#include <caml/custom.h>
#include <caml/intext.h>
};

class TClosure
{
public:
  TClosure() {};
  virtual ~TClosure() {};
  
  virtual void operator()() = 0;
};

#ifdef __TClosure_Instantiate__
void safe_call(TClosure &closure)
{
  try {
    closure();
  } catch(const char* msg) {
    failwith((char*)msg);
  }
}
#else
extern void safe_call(TClosure &closure);
#endif

// ------------------------------------------------
// Internal macros
//
#define __VClosureHead()				\
  struct closure: public TClosure			\
  {							\
    value *m_pparm;					\
    value  m_result;					\
    closure(value *pparm)				\
      :m_pparm(pparm)					\
      {}						\

#define __VClosureArgs1(arg)			\
  enum {arg};

#define __VClosureArgs2(arg1,arg2)		\
  enum {arg1,arg2};

#define __VClosureArgs3(arg1,arg2,arg3)		\
  enum {arg1,arg2,arg3};

#define __VClosureArgs4(arg1,arg2,arg3,arg4)	\
  enum {arg1,arg2,arg3,arg4};

#define __VClosureArgs5(arg1,arg2,arg3,arg4,arg5)	\
  enum {arg1,arg2,arg3,arg4,arg5};

#define __VClosureTail(name,body,env)			\
  void operator()()					\
  { body }						\
  } name(env);

// ------------------------------------------------------
// API Level Macros

#define VClosure(name,body,env)	     \
  __VClosureHead()		     \
    __VClosureTail(name,body,env)

#define VClosure1(name,arg,body,env) \
  __VClosureHead()		     \
    __VClosureArgs1(arg)		     \
       __VClosureTail(name,body,env)

#define VClosure2(name,arg1,arg2,body,env)	\
  __VClosureHead()				\
    __VClosureArgs2(arg1,arg2)			\
       __VClosureTail(name,body,env)

#define VClosure3(name,arg1,arg2,arg3,body,env)	\
  __VClosureHead()				\
    __VClosureArgs3(arg1,arg2,arg3)		\
       __VClosureTail(name,body,env)

#define VClosure4(name,arg1,arg2,arg3,arg4,body,env)	\
  __VClosureHead()					\
    __VClosureArgs4(arg1,arg2,arg3,arg4)			\
       __VClosureTail(name,body,env)

#define VClosure5(name,arg1,arg2,arg3,arg4,arg5,body,env)	\
  __VClosureHead()						\
    __VClosureArgs5(arg1,arg2,arg3,arg4,arg5)			\
       __VClosureTail(name,body,env)

#define VClArg(name)             m_pparm[name]
#define VClReturn(val)           m_result = val;
#define VClResult(closure_name)  closure_name.m_result

#endif // __TCLOSURE_H__

// -- end of TClosure.h -- //

      parent reply	other threads:[~2004-08-28  0:20 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-08-27 22:31 David McClain
2004-08-27 23:24 ` Brian Hurt
2004-08-28  0:11   ` David McClain
2004-08-28  1:40     ` skaller
2004-08-28  4:13       ` David McClain
2004-08-28  4:55         ` David Brown
2004-08-28  7:44           ` Ville-Pertti Keinonen
2004-08-28  7:48           ` Radu-Mihail Obada
2004-08-28  8:17         ` Xavier Leroy
2004-08-28  9:24           ` skaller
2004-08-28  9:31         ` skaller
2004-08-28  0:22   ` David McClain [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='001901c48c95$25df1850$0201000a@dylan' \
    --to=dmcclain1@mindspring.com \
    --cc=bhurt@spnz.org \
    --cc=caml-list@inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).