Re: Taking the defs file issue

2000-11-16 Thread Marius Vollmer

Rob Browning [EMAIL PROTECTED] writes:

 Marius Vollmer [EMAIL PROTECTED] writes:
 
  I quite strongly disagree with this.  In my view, the functions
  exported to the Scheme side must not be not be `dangerous' in the
  sense that a pilot error can not lead to memory corruption, memory
  leaks or similar.
 
 Well, I suppose this depends on your perspective, and what you want.
 If you want to create a tool that lets you do from scheme the same
 things you can do from C with a given C API, and if you want to
 provide a way for people to *quickly* wrap *existing* C APIs without
 having to write a lot of additional glue code, then I think it's going
 to be *very* difficult to avoid the "dangerous" things you're talking
 about.

Yes, very true.  I guess my main point is that I don't want guile-gtk
to degrade when switrhcing to g-wrap.  That is, the work of avoiding
"dangerous" things has been done (more or less) and I don't want to
lose this.

Well, I might argue that providing a tool that makes it really easy to
do dangerous things is not a good thing, and that we at least should
put up warning signs all over the place that the quick solution is not
necessarily the best solution and that people should spend a moments
thought on how they can make the bindings safer etc.

 As you pointed out, you had to change Gtk+ to make it safe, and in
 general, requiring universal safety may often require the
 wrapper-spec-writer to add "safe functions" on top of an existing C
 API before publishing to scheme via g-wrap.

Yes, and the problem with Gtk+ was that you could not add these safe
functions on top of the existing API.  That would have been nice.

From a broader perspective, makeing an existing API safe for wrapping
from Scheme should almost always be a significant improvemt of the API
itself, independent from Scheme.  A non-trivial client of the API
should have most of the same problems that a Scheme binding has when
it comes to memory management (type issues are probably different).
For example, ref counting in Gtk+ was inadequate, not just for Scheme,
but for any non-trivial program.  You could just not rely on it
because it interacted badly with the functionality of the objects (for
GtkObjects) or wasn't there at all (for GdkFonts etc if I remember
right).

Cleaning up reference counting made the Gtk+ API better in my view,
independent from the fact that I needed the improvement for the Scheme
bindings.

Anyway, we can not always change existing APIs and I got lucky that
the Gtk+ people have listened to me, but I'd still like bring this
topic up.  I also see it as a kind of education.  There are just too
many crappy APIs out there that just don't need to be that way.  API
design is significantly harder than mere coding and I'm unhappy with
most of the APIs.  Just look at libc.  Horrors!  :-)

Ok, well, I guess I don't need to lecture you, but I couldn't help
myself.

 However, I still worry that it may be hard to come up with a safe and
 efficient scheme side interface for every C API without a lot of
 effort, and in some cases, just having the API might be better than
 having the perfect one.

Yes, but when the API allows a safe binding, g-wrap should be prepared
to generate one.  This is probably mostly an issue of documenting what
exactly a safe binding would be.  How to bridge the Scheme / C gap.  I
feel that for all my rambling, I should really sit down and write such
a thing...

___
gnucash-devel mailing list
[EMAIL PROTECTED]
http://www.gnumatic.com/cgi-bin/mailman/listinfo/gnucash-devel



Re: Taking the defs file issue

2000-11-15 Thread Rob Browning

Marius Vollmer [EMAIL PROTECTED] writes:

 Yes, very true.  I guess my main point is that I don't want
 guile-gtk to degrade when switrhcing to g-wrap.  That is, the work
 of avoiding "dangerous" things has been done (more or less) and I
 don't want to lose this.

Totally understandable.

 Well, I might argue that providing a tool that makes it really easy to
 do dangerous things is not a good thing, and that we at least should
 put up warning signs all over the place that the quick solution is not
 necessarily the best solution and that people should spend a moments
 thought on how they can make the bindings safer etc.

No argument here.  In the long run, I'd absolutely prefer the really
nice, really clean, really safe solution, though it might be nice to
have the lower-level dangerous stuff around if you ask for it
explicitly somehow (presuming there were cases where that would be
useful).

 Cleaning up reference counting made the Gtk+ API better in my view,
 independent from the fact that I needed the improvement for the
 Scheme bindings.
 
 Anyway, we can not always change existing APIs and I got lucky that
 the Gtk+ people have listened to me, but I'd still like bring this
 topic up.  I also see it as a kind of education.  There are just too
 many crappy APIs out there that just don't need to be that way.  API
 design is significantly harder than mere coding and I'm unhappy with
 most of the APIs.  Just look at libc.  Horrors!  :-)
 
 Ok, well, I guess I don't need to lecture you, but I couldn't help
 myself.

All true.  You're preaching to the choir here :

 Yes, but when the API allows a safe binding, g-wrap should be prepared
 to generate one.  This is probably mostly an issue of documenting what
 exactly a safe binding would be.  How to bridge the Scheme / C gap.  I
 feel that for all my rambling, I should really sit down and write such
 a thing...

Actually, this could be very helpful.  I'd also love to have better
documentation of related guile low-level issues like what do
GH_DEFER/ALLOW_INTS really do, and when do you need to use them?

Also perhaps a discussion of the changes that had to be made to Gtk+
with a commentary on why they helped would be really informative.

-- 
Rob Browning [EMAIL PROTECTED] PGP=E80E0D04F521A094 532B97F5D64E3930

___
gnucash-devel mailing list
[EMAIL PROTECTED]
http://www.gnumatic.com/cgi-bin/mailman/listinfo/gnucash-devel



Re: Taking the defs file issue

2000-11-13 Thread Marius Vollmer

Rob Browning [EMAIL PROTECTED] writes:

 This is because in general, I tend to favor this approach to one
 that tries to hide the allocation semantics.  Like it or not, when
 you're wrapping a C API, I think you generally *do* have to know
 (and care) about the allocation semantics, and I tend to feel that
 trying to automate them too much (beyond the "'cleanup 'no-cleanup"
 stuff we already have in g-wrap) is just going to hurt more than
 help.

I quite strongly disagree with this.  In my view, the functions
exported to the Scheme side must not be not be `dangerous' in the
sense that a pilot error can not lead to memory corruption, memory
leaks or similar.

This goal might not be always possible to reach, but one should try
very hard before giving up.  I would even go so far as to require that
the C API be changed so that it can be safely wrapped.  (I did this
with Gtk+, incidentally.)

Guile-gtk is not just the automatic generation of glue code.  This is
actually the easy part.  The hard part is to know what code to
generate and how to make sure that it behaves in a sane way.

[ When I say that generating glue is easy I only meant that in the
  context of guile-gtk.  Designing something more ambitious like
  g-wrap is quite challenging. ]

For example, when you have a pointer-token object in Scheme land, how
do you make sure that the pointer in the token stays valid as long as
it can be used from Scheme?  If you can't guarantee this, you should
not export the pointer to Scheme at all.  It must not be possible to
use a invalid pointer-token in Scheme code, even in buggy Scheme code.
A bug in Scheme should never have uncontrollable consequences like
memory corruption.

Taking you GtkWindow* example, how to you propose to handle the
life-time of GtkWindow structures?  Do you also export gtk_object_ref
and gtk_object_unref to Scheme and expect Scheme programmers to use
them?  I don't think that this would be very welcome.

Anyway, the guts and most of the smarts of guile-gtk are actually in
guile-gtk.c (and in Gtk+ itself), not in build-guile-gtk.  We pretty
much know what glue code we want to generate and it would be nice if
we could use a external tool to do so, but the generated code glue
itself and the `feel' of the resulting Scheme API should pretty much
stay the same.  There is room for improvement, of course, especially
when it comes to composite types and multiple return values, but the
quality of the Scheme API must not decrease.  For example, it is
important that guile-gtk knows about the type hierarchy of the
GtkObject types in Gtk+ so that it can do proper type checking.

 How do you handle varargs from guile?  Robert and I tried to figure
 out a way to do that last week and came to the conclusion that it
 wasn't possible without some non-portable assembly nonsense (or
 similar) since C doesn't have anything remotely like "apply" for
 va_lists; ISTR Robert actually found something in the C FAQ about
 this.

You could try libffi or libffcall (I think).  I once did bindings for
libffi but they have rotten away I'm afraid.

 Overall, as I somewhat suggested above, and bearing in mind that I
 haven't yet *fully* grokked what you're proposing since I don't have
 as much familiarity with gtk, gnome, and the current state of
 guile-{gnome,gtk} as you do, it sounds like your current .defs
 proposal goes far beyond what g-wrap was intended to do, covering
 quite a bit more ground.

[small voice] Lest there be a misunderstanding, I don't know fully
what to think of the defs proposal.  The last time I read it, I found
it to be quite superficial and vague.  I'm not pushing for anything in
this department.  In fact, I'm quite happy sitting on an island with
guile-gtk, knowing that it works quite well as it is, and waiting for
whatever ransom might come... ;)

 On the issue of "wrapping C structures in more detail" -- right now
 g-wrap presumes the C API is "function rich".  By that I mean that it
 presumes that you can do everything you need with a structure or other
 C datatype via the functional API.

Yes, and trivial accessor functions could be generated by g-wrap.
Structure members should be exported as functions to Scheme (there is
pretty much no choice anyway), but the needed accessors functions need
not be written by hand.  An interesting thing would be to merge this
with GOOPS, somehow.

___
gnucash-devel mailing list
[EMAIL PROTECTED]
http://www.gnumatic.com/cgi-bin/mailman/listinfo/gnucash-devel



Re: Taking the defs file issue

2000-11-12 Thread Christopher Browne

On 12 Nov 2000 18:56:28 CST, the world broke into rejoicing as
Rob Browning [EMAIL PROTECTED]  said:
 Marius Vollmer [EMAIL PROTECTED] writes:
  I quite strongly disagree with this.  In my view, the functions
  exported to the Scheme side must not be not be `dangerous' in the
  sense that a pilot error can not lead to memory corruption, memory
  leaks or similar.

 Well, I suppose this depends on your perspective, and what you want.
 If you want to create a tool that lets you do from scheme the same
 things you can do from C with a given C API, and if you want to
 provide a way for people to *quickly* wrap *existing* C APIs without
 having to write a lot of additional glue code, then I think it's
 going to be *very* difficult to avoid the "dangerous" things you're
 talking about.

The "guarantee of lack of danger" would be well and good as a
requirement if the bulk of the system were written in Scheme, and we
had a few bits of C tacked on the side.

Reality is that a sizable bulk of GnuCash is in C, which is one of the
ultimate examples of a system where errors can and do lead to memory
corruption and memory leaks.
--
(concatenate 'string "cbbrowne" "@ntlug.org") http://www.hex.net/~cbbrowne/
"In my opinion MS is a lot better at making money than it is at making
good operating systems." -- Linus Torvalds

___
gnucash-devel mailing list
[EMAIL PROTECTED]
http://www.gnumatic.com/cgi-bin/mailman/listinfo/gnucash-devel



Re: Taking the defs file issue

2000-11-12 Thread Rob Browning


(I've included gnucash-devel at this point because several of the
 people there should be seeing this discussion, and until I get the
 g-wrap list set up, which should be in about a week and a half,
 gnucash-devel is the de-facto g-wrap devel list.  I'll also CC your
 previous mail there.)

Ariel Rios [EMAIL PROTECTED] writes:

 (module module-name
   (submodule-of module-name)) ;; submodule is optional
 
 Ex: (module Gtk)
 Ex: (module Rgb
   (submodule-of Gdk))
 
 modules are later referred to with a list of module names, like 
 (Gdk Rgb) or (Gtk)
 
 Object and boxed type definitions automatically create a submodule.
 For example, GtkCList creates the module (module CList (submodule-of
 (Gtk))) which is referred to as module (Gtk CList).

OK, so this is a bit more complex than what I'd gathered from just
looking at the current .defs files.

 (type
  (alias some-unique-identifier)
  (in-module module-name)   ;; optional, gchar* is not in a module
  (gtk-type-id gtk-type-system-id) ;; optional, absent if this is not
   ;; in the type system
  (is-parametric boolean)  ;; optional default to #f
  (in-c-name name-of-symbol-in-C)
  (out-c-name name-of-symbol-in-C)
  (inout-c-name name-of-symbol-in-C))

What exactly does "parametric" mean in this context?

 Ex: (type
  (alias string)
  (gtk-type-id GTK_TYPE_STRING)

Hmm.  gtk-type-id doesn't sound like something that g-wrap would
normally care about, at least not directly since it's very GTK/GNOME
specific.  Is this just used to refer to the macro that should be used
for coercions?

  (in-c-name "const gchar*")
  (out-c-name "gchar**")  ;; actually I'm not sure how strings work out/inout
  (inout-c-name "gchar*"))

How are these used?

After looking at the rest of this document without (admittedly) having
enough time to *carefully* understand everything, though I think I
have a good overall idea of what's going on, it looks like your .defs
file is trying to capture a lot more information than g-wrap does (at
least currently).

Since g-wrap's approach is (I think?) much simpler (and more limited),
perhaps it would be easier for me to summarize g-wrap's approach and
then you (collectively) can tell me whether or not g-wrap's likely to
be of use to you -- either by being enhanced to cover what you need,
or perhaps by being used as a lower-level, more primitive backend that
you generate output for.

Here goes:

From the user's perspective g-wrap knows about three "types of type"
for a wrapped function's arguments and return values (actually four if
you include the enum support I'm about to add): simple-types,
complex-types and pointer-tokens.

Simple types are those for which it's sufficient to just tell g-wrap
how to identify and convert instances of the type.  Usually this means
only types where memory allocation semantics are irrelevant: numeric
types, characters, const-strings, etc.  As an example of a
simple-type, here's how we just added support for "long long" to
g-wrap:

  (add-type 'long-long "long long"  
;; fn-convert-to-scm 
(lambda (x) (list "gh_longlong2scm(" x ")"))
;; fn-convert-from-scm 
(lambda (x) (list "gh_scm2longlong(" x ")"))
;; fn-scm-is-a
(lambda (x) (list "gh_exact_p(" x ")")))

These add-type calls can be added to g-wrap's built in type spec, or
the user can put them in their own files.

complex-types are those that can still be converted to/from a guile
type, but for which memory allocation issues are important.  In those
cases, you have to tell g-wrap, in addition to the above information,
both how to clean up (deallocate) an instance of the type and whether
or not cleaning up those values should be the default for instances of
the type that are passed as arguments, and for instances returned as
return values.  The default can also be overridden on a
per-wrapped-function signature basis.

As an example, here's how you could define a hypothetical type
representing "strings that should be considered to be owned by the
caller", meaning that g-wrap should, by default, "clean up" the C-side
temporary that it creates to use as a parameter to a C-side function
call, or the C-side "temporary" that's received the return value from
the C-side function call.  Also, as you can see from the C-side
conversion code given in the definition below, the new type,
caller-owned-string, also accepts and returns #f as a representation
of the NULL string.

  (add-new-type 
   'caller-owned-string
   (make-complex-c-type
"const char*"
;;fn-convert-to-scm 
(lambda (x) (list "((" x ") ? gh_str02scm(" x ") : SCM_BOOL_F)"))
;;fn-convert-from-scm 
(lambda (x)
  (list "(((" x ") == SCM_BOOL_F) ? NULL : gh_scm2newstr(" x ", NULL))"))
;;fn-scm-is-a
(lambda (x)
  (list "((" x " == SCM_BOOL_F) || "
"(SCM_NIMP(" x ")  SCM_STRINGP(" x ")))"))
;; c-cleanup-arg-default?
#t
;; 

[Ariel Rios ariel@arcavia.com] Taking the defs file issue

2000-11-12 Thread Rob Browning


Ok guys,

Attached I send the current defs file proposal. I'm ccing also the
gnome-bindings list
for it might be of interest to discuss possible modifications with them
to this
proposal.

ariel


The overall syntax is:

 (type-of-thing-being-defined  name-used-to-refer-to-this-thing
   (attribute-name  attribute-value-depending-on-the-attribute)
   (attribute-name  attribute-value-depending-on-the-attribute)
   (attribute-name  attribute-value-depending-on-the-attribute))

Some definitions can have a c-declaration field that gives the C code
we parsed to arrive at the definition. The c-declaration is a quoted
string because it can contain parentheses and such.

Defined types and their attributes:

===
(module module-name
  (submodule-of module-name)) ;; submodule is optional

Ex: (module Gtk)
Ex: (module Rgb
  (submodule-of Gdk))

modules are later referred to with a list of module names, like 
(Gdk Rgb) or (Gtk)

Object and boxed type definitions automatically create a submodule.
For example, GtkCList creates the module (module CList (submodule-of
(Gtk))) which is referred to as module (Gtk CList).

===

(type
 (alias some-unique-identifier)
 (in-module module-name)   ;; optional, gchar* is not in a module
 (gtk-type-id gtk-type-system-id) ;; optional, absent if this is not
  ;; in the type system
 (is-parametric boolean)  ;; optional default to #f
 (in-c-name name-of-symbol-in-C)
 (out-c-name name-of-symbol-in-C)
 (inout-c-name name-of-symbol-in-C))

Ex: (type
 (alias string)
 (gtk-type-id GTK_TYPE_STRING)
 (in-c-name "const gchar*")
 (out-c-name "gchar**")  ;; actually I'm not sure how strings work out/inout
 (inout-c-name "gchar*"))

 (type
 (alias list)
 (gtk-type-id GTK_TYPE_POINTER)
 (is-parametric #t)
 (in-c-name "GList*")
 (out-c-name "GList**")
 (inout-c-name "GList**"))


 ;; This one would be implied by the (object) def for GtkWidget I
 ;; think - (type) is only required for types that are not implied
 ;; by other definitions, such as int/boolean/etc.
 
(type
 (alias GtkWidget)
 (in-module (Gtk))
 (gtk-type-id GTK_TYPE_WIDGET)
 (in-c-name "GtkWidget*")
 (inout-c-name "GtkWidget*")
 (out-c-name "GtkWidget**"))

"Type" bindings are automatically assumed for objects, boxed types,
etc. as defined below.

The alias field is used to refer to the type later on.

Whenever a type alias can be used, it is also possible to use the
keyword "native", which implies that the type in question is too
C-specific to represent. Then a c-declaration will typically be
available for use.

C types containing [] or () are function pointers or arrays. For
arrays that don't specify a size, we just treat them as pointers. For
function pointers, we need special (type) syntax/attributes of some
kind, but since there basically aren't any of these right now in the
libs we care about we can just ignore them. For arrays that specify a
size ditto, you would handle them by adding an (array-size) attribute
or something or using the "native" keyword and skipping the (type)
stuff.

===
(object object-name
   (in-module module-name-list)
   (parent object-name optional-module-name-if-different)
   (abstract boolean-is-abstract-class) ;; omit for default of #f
   (c-name name-of-the-object-in-C)
   (field (type-and-name type-alias-of-struct-field name-of-struct-field)
  (access read-or-write-or-readwrite)))
   

Ex: (object Widget
  (in-module (Gtk))
  (parent Object)  ;; could say (parent Object (Gtk))
  (abstract #t)
  (c-name GtkWidget)
  (field (type-and-name GdkWindow* window) (access read)))

An "object" declaration automatically implies the type definition:

(type
  (alias concat-module-elements-and-object-name)
  (in-c-name pointer-to-c-name)
  (out-c-name pointer-to-pointer-to-c-name)
  (inout-c-name pointer-to-c-name))

Ex: 
 (type (alias GtkWidget) 
   (in-c-name GtkWidget*) 
   (out-c-name GtkWidget**) 
   (inout-c-name GtkWidget*))

It also implies a module that is the name broken into parts:
 (module CTree
   (submodule-of Gtk))

===

(function function-name
  (in-module module-name-list) ;; "static methods" go in their
   ;;  object's module
  (is-constructor-of object-type-alias) ;; optional, marks a constructor
  (c-name function-name)
  (return-type return-value-type) ;; defaults to void
  (caller-owns-return boolean-value) ;; defaults to #f
  (can-return-null boolean-value) ;; defaults to #t
  (parameter in-or-out-or-inout 
  (type-and-name parameter-type-alias parameter-name)
  (type-parameter name-of-contained-type) ;; optional, requires parametric type
  (c-declaration "c-type-and-name")) ;; c-declaration only required
 ;; if the type alias is "native"
  (varargs #t) ;; has varargs at the end
)

Ex:
  (function init
(in-module (Gdk Rgb)
(c-name