Namespace funnyqt.polyfns

Polymorphic functions dispatching on types of model elements.

Other Namespaces

Show/Hide
funnyqt.bidi
Bidirectional transformations (BX).
funnyqt.coevo.tg
Co-Evolution transformations on TGraphs.
funnyqt.edn
Printing/persisting and reading/loading query results and transformation traces as EDN.
funnyqt.emf
Core functions for accessing and manipulating EMF models.
funnyqt.extensional
Specify models extensionally.
funnyqt.generic
Generic protocols extended upon many different types, and generic functions.
funnyqt.in-place
In-place transformation stuff.
funnyqt.model2model
Rule-base out-place transformations similar to ATL or QVTo.
funnyqt.pmatch
Graph Pattern Matching on arbitrary models.
funnyqt.query
Generic query functions like regular path expressions & quantified expressions.
funnyqt.query.emf
EMF-specific query functions
funnyqt.query.tg
TG-specific query functions
funnyqt.relational
Relational Model Querying.
funnyqt.tg
Core functions for accessing and manipulating TGraphs.
funnyqt.utils
Generic utility functions, e.g., for signaling errors, debugging, and profiling,
funnyqt.visualization
Model visualization functions.
funnyqt.xmltg
Convert XML to DOM-like TGraphs.
Index Page
Alphabetic Var Index

Public Vars

Usage Documentation

Show/Hide
Polymorphic functions dispatching on types of model elements.

Every polyfn must be declared first, and then arbitrary many implementations
for several metamodel types may be provided.  A polyfn must have a model
element as first argument which is used to dispatch among implementations.

Every polyfn has to be declared once using `declare-polyfn`, and then
implementations for specific types map be provided using `defpolyfn`.  When a
polyfn is called, the most specific implementation for the model element type
is invoked.  In case of multiple inheritance, a class inheriting two different
implementations is an error.  It must provide an own implementation in order
to remove ambiguities.

Example
-------

Let's consider our metamodel has the types TypeA and TypeB, and a TypeC that
extends both TypeA and TypeB.  Furthermore, TypeD extends TypeC.  Lastly,
there's a TypeE with no inheritance relationships.

  ;; Declare a polyfn
  (declare-polyfn foo [elem ...]
    ;; Optional default behavior
    (str "Don't know how to handle " elem))

  ;; Define implementations for several types
  (defpolyfn foo TypeA [elem ...] ...)
  (defpolyfn foo TypeB [elem ...] ...)
  (defpolyfn foo TypeC [elem ...] ...)

Then, (foo objOfTypeA) invokes the first implementation, (foo objOfTypeB)
invokes the second implementation, both (foo objOfTypeC) and (foo objOfTypeD)
invoke the third implementation, and (foo objOfTypeE) invokes the default
behavior.  If no optional default behavior is specified, an exception is
thrown.

An impl can also be defined for many types at once.  In that case, a list of
types is provided:

  (defpolyfn foo (TypeX TypeY TypeZ) [elem ...] ...)
Back to top

Details of Public Vars

Function: build-polyfn-dispatch-table

Arglists:
=========

  (build-polyfn-dispatch-table polyfn-var cls)

Docstring:
==========

  No docs attached.
Back to top View Source

Macro: declare-polyfn

Arglists:
=========

  (declare-polyfn name doc-string? attr-map? [model-elem & more] & body)

Docstring:
==========

  Decares a polymorphic function dispatching on a model element type.
  `name` is the name of the new polyfn, an optional `doc-string` may be
  provided.  The argument list's first element must be the model element on
  whose type the dispatch is done.  Polymorphic functions for several metamodel
  types are provided later using `defpolyfn`.  If an optional `body` is
  provided, this is executed if no implementation for `model-elem`s type was
  added using `defpolyfn`.  The default behavior in that case (i.e., `body`
  omitted) is to throw an exception.

  By default, when a polyfn is called for the very first time a dispatch table
  is computed which maps metamodel classes to the implementation for that type.
  If the metamodel changes afterwards, then the dispatch table might be wrong
  and needs to be recomputed which will happen if one reset!s
  the ::polyfn-dispatch-table metadata atom to nil.  One can also omit building
  a dispatch table by adding :no-dispatch-table metadata to the polyfn name or
  by setting it to true in the polyfn's `attr-map`.  In that case, the
  implementation is computed with each call and never cached.
Back to top View Source

Macro: defpolyfn

Arglists:
=========

  (defpolyfn name type [model-elem & more] & body)
  (defpolyfn name (type1 type2 ...) [model-elem & more] & body)

Docstring:
==========

  Defines an implementation of the polyfn `name` for objects of type `type`
  or objects of `type1`, `type2`, etc.
  The polyfn has to be already declared using `declare-polyfn`.  `type` is a
  fully qualified type name that is used to check if the polyfn implementation
  is matching the type of `model-elem`.  The arity of the argument vector has
  to match the one of the corresponding `declare-polyfn`.
Back to top View Source

Function: find-polyfn-impl

Arglists:
=========

  (find-polyfn-impl polyfn-sym spec-map type)
  (find-polyfn-impl polyfn-sym spec-map orig-type type)

Docstring:
==========

  No docs attached.
Back to top View Source