[Arjen Markus] (29 january 2021) Manfred Rosenberger (of [rattleCAD]
fame) and I discussed the API of the geometry package in [Tcllib].
Currently the package uses names like `calculateDistanceToLine` for
many of its procedures, the arguments being, respectively, a point and a
line.

''Note: this page is meant to discuss the ideas for an alternative API''

'''Description of the alternative'''

While descriptive, the names are long and may be difficult to
read/decypher. What is more, there is no flexibility in what object is
the most important: in some cases you can have a bunch of points for
which you need to determine the distance to a line, making the line
the more important of the two and in other cases you may find that some
point is the centre of the universe. Then the order of the
arguments would be preferably the other way around.

Another drawback of the current API: it is not easy to get an overview
of the procedures that are available for a particular type of object. At
best this can be done by searching for the procedures that have "point"
in their name. But it depends on the consistency of the names. For
instance a rectangle can be constructed via the proc `nwse`, a name
referring to the arguments, the nort-west and south-east corners.

A clear alternative could possibly be to use [TclOO] and create point
and line objects, each with their own set of methods. But that feels
as rather heavy. The geometrical objects we deal with are short-lived
and they are never extended in any way. Creating actual objects in the
object-oriented way would be overkill.

Manfred devised an alternative, based on [namespace ensemble]:

======tcl
# Minimal example

package require math::geometry

namespace eval ::math::geometry::line {
    namespace ensemble create -parameter line
    namespace export distanceToPoint

    namespace import ::math::geometry::*

    proc distanceToPoint {line p} {
        ::math::geometry::calculateDistanceToLine $p $line
    }
}

namespace path ::math::geometry

set line  [list 0 0 1 0]
set point [list 1 1]
puts "Distance: [line $line distanceToPoint $point]"
======

By using the `-parameters` option of the [namespace ensemble] command we
can emphasize the importance of the first argument - it is the
central geometrical object.

Unfortunately, this becomes awkward for commands to "create" a new
geometrical object:

======tcl
   set point [point $x create $y]
======

For this type of commands we could use either of these:

======tcl
   set p [create point $x $y]  ;# "create" a separate ensemble

   point p create $x $y ;# the first argument the name of a variable
======

So, basically, that is the idea:

   * Group the commands into separate ensembles
   * Provide alternatives where the "primary" object is the first argument
   * Reuse all the code in the geometry package and only/mostly provide wrappers to get a light-weight, object-oriented, API

'''Discussion'''

Is this a useful idea?

[APN] I like the idea behind ensembles but as a *personal* preference, I much prefer all the command and subcommand tokens to come at the beginning. So,

======tcl
point create p $x $y
======

Also, not sure performance matters here but ensembles are slower to invoke than procedure calls (i.e. `point create` vs `point::create`). This is of course a nit, and I use ensembles all the time anyways.

[AM] Thanks for your comments - and the remark about performance. That would certainly be of interest, but we should measure the consequences of this particular style before we dismiss it :).
[AM] (4 february 2021) I tested this using the following little program":
======tcl
# chkensemble.tcl --
#     Check properties of ensembles
#
package require math::geometry

namespace eval ::math::geometry::line {
    namespace ensemble create -parameter line
    namespace export distanceToPoint

    namespace import ::math::geometry::*

    proc distanceToPoint {line p} {
        ::math::geometry::calculateDistanceToLine $p $line
    }
}

#namespace eval ::math::geometry {
#    namespace export line
#}

#namespace import ::math::geometry::*
namespace path ::math::geometry

set line  [list 0 0 1 0]
set point [list 1 1]
puts "Distance - ensemble: [time {line $line distanceToPoint $point} 1000000]"
puts "Distance - direct:   [time {line::distanceToPoint $line $point} 1000000]"
======
The result was:

======none
Distance - ensemble: 2.083693 microseconds per iteration
Distance - direct:   1.711088 microseconds per iteration
======
So using an ensemble is slower, by 20%, at least in this experiment, but the nice thing is that you can use either interface.




<<categories>>Category Tcllib