VFunc Alley - VFunc G-Golf support.
For completion, this section exposes the definition of the <vfunc> class and vfunc syntax, involved in the G-Golf integration of the (GLib Object System) VFunc. From a (strict) user point of view however, these are actually G-Golf internals and, unless you are interested of course, might be ignored.
In the GObject documentation, the terminology (mostly) used is
virtual public|private method
or simply virtual
method
. In the GI (GObject Introspection) documentation however,
the structure representing a virtual method is named a
GIVFuncInfo
and the description says it represents a virtual
function. The GI core functionality also uses the vfunc
or
vfunc-info
prefix, infix or postfix terms, depending on the
context.
Welcome to the VFunc G-Golf Alley.
Let’s first recap :-) GObject (the GLib Object System) offers different ways to define object and interface methods and extend them, well introduced and described in the GObject Tutorial:
Of those four, virtual public methods and virtual private methods maybe overridden, through the use of a mechanism that involves the creation of a C closure and the setting of its pointer in the corresponding GObject or Interface class struct.
In G-Golf, this is implemented by the define-vfunc syntax, which must be used to define a VFunc (virtual method). From a user perspective, define-vfunc is very much like define-method (See Methods and Generic Functions in The GNU Guile Reference Manual).
Here is an example, which defines a GObject subclass that inherits the GdkPaintable interface, then overrides the get_flags VFunc, one of its numerous virtual methods:
(define-class <solitaire-peg> (<gobject> <gdk-paintable>) (i #:accessor !i #:init-keyword #:i) (j #:accessor !j #:init-keyword #:j)) (define-vfunc (get-flags-vfunc (self <solitaire-peg>)) '(size contents))
The only difference, from a user point of view and as you can see in the example above, is that define-vfunc imposes one (or two, depending on the context) additional constraint(s) to the VFunc name, fully described in the define-vfunc definition.
The base class of all virtual method.
It is an instance of <class>
.
Superclasses are:
<method>
Class Precedence List:
<vfunc>
<method>
<object>
<top>
Direct slots are:
specializer
#:accessor !specializer
name
#:accessor !name
g-name
#:accessor !g-name
long-name-preifx
#:accessor !long-name-preofx
gf-long-name?
#:accessor !gf-long-name?
info
#:accessor !info
callback
#:accessor !callback
All direct slots are initialized automatically and immutable (to be precise, they are not meant to be mutated, see GOOPS Notes and Conventions, ’Slots are not Immutable’).
Defines a vfunc (a specialized method) for the generic function generic with parameters parameters and body body ....
generic is a generic function, and the following constraints apply to the generic function name:
-vfunc
postfix23. -vfunc
postfix25.
If generic is a variable which is not yet bound to a generic
function object, the expansion of define-vfunc
will include a
call to define-generic
.
Each parameter must be either a symbol or a two-element list
(symbol class)
. The symbols refer to variables in
the body forms that will be bound to the parameters supplied by the
caller when calling this method. The classes, if present, specify
the possible combinations of parameters to which this method can be
applied.
body … are the bodies of the vfunc definition.
Makes a vfunc (a specialized method) whose specializers are defined by the classes in parameters and whose procedure definition is constructed from the parameter symbols and body forms.
The parameter and body parameters should be as for define-vfunc.
Returns the content of their respective slot for inst (a <vfunc> instance).
In G-Golf, from a user perspective, the next-vfunc concept and mechanism is to the GObject virtual method system what the next-method concept and mechanism is to the GOOPS (compute applicable) method system.
If a vfunc refers to ‘next-vfunc’ in its body, that vfunc will call the corresponding ‘immediate parent’ virtual function. The exact ‘next-vfunc’ implementation is only known at runtime, as it is a function of the vfunc specializer argument.
G-Golf implements ‘next-vfunc’ by binding it as a closure variable.
An effective virtual method is bound to a specific ‘next-vfunc’ by
the internal %next-vfunc-proc
, which returns the new closure.
Let’s look at an excerpt form the animated-paintable.scm example, which specializes the GObject finalize virtual method, and as the GNOME team would say, needs to ‘chain-up’:
(define-vfunc (finalize-vfunc (self <nuclear-animation>)) (g-source-remove (!source-id self)) ;; This vfunc must 'chain-up' - call the <nuclear-animation> parent ;; finalize virtual method. (next-vfunc))
This is because most of the cases, in the upstream lib,
the VFunc is a virtual public method, that is, both a method and a VFunc
exist that use the same name. When that happens, the upstream lib method
normally has the same arity and definition (spec), and it ’just’ calls
the VFunc - however, it is (unfortunately) not guaranteed to always be
the case, hence all GI lang bindings impose a specific VFunc naming
convention. Pygobject for example imposes to use a do-
prefix. In
G-Golf, we opted for a -vfunc
postfix.
It
must be prefixed using the scheme representation name of the GObject or
Interface that owns the Vfunc, followed by -
(hyphen),
i.e. gdk-paintable-get-flags-vfunc is the valid define-vfunc long name
for the get_flags virtual method of the GdkPaintable interface.
Otherwise, it would be impossible to deternine which iface or gobject class struct the *-vfunc user code is meant to override. Consider (define-class <foo> (<gobject> <bar> <baz>)), with both <bar> and <baz> defining a get_flags VFunc: in this context (define-vfunc (get-flags-vfunc (self <foo>))...) is an invalid definition, as it is not possible for G-Golf to deternine if it is the <bar> or the <baz> iface class struct VFunc that must be overridden. In such cases, the user must pass a method long name, i.e. (define-vfunc (bar-get-flags-vfunc (self <foo>)) ...) or (define-vfunc (baz-get-flags-vfunc (self <foo>)) ...).