VFunc Alley

VFunc Alley - VFunc G-Golf support.


_ SPECIAL NOTES _

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.


Class

<vfunc>

Syntaxes and Accessors

define-vfunc
vfunc
!specializer
!name_______
!g-name_______
!long-name-prefix
!gf-long-name?
!info__
!callback

Special Form

next-vfunc

Description

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.

Class

Class: <vfunc>

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’).

Syntaxes and Accessors

Syntax: define-vfunc (generic parameter …) body …

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:

  • the generic function name is valid if it is the scheme representation of a VFunc (name) that exists for at least one of the instance specializer superclasses, followed by the -vfunc postfix23.

  • if more then one instance specializer superclasses has a VFunc name, then the scheme name must be a so-called long name24, followed by the -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.

Syntax: vfunc (parameter …) body …

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.

Accessor: !specializer inst
Accessor: !name inst
Accessor: !g-name inst
Accessor: !long-name-prefix inst
Accessor: !gf-long-name? inst
Accessor: !info inst
Accessor: !callback inst

Returns the content of their respective slot for inst (a <vfunc> instance).

Next-vfunc

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))

Footnotes

(23)

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.

(24)

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.

(25)

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>)) ...).