Loading...
Searching...
No Matches
myoo - The new TCL 'oo' extension with 'C' and 'theCompiler' support.

Introduction

myoo is a TCL extension used for Object-Oriented-Programming (OOP).

There are two versions of the myoo library ...

tclmyoo

tclmyoo - myoo tcl-api defined by only one page of code

tclmyoo only uses the tcl-standart-api-commands to implement myoo.

A CLASS is a cls array in the CLASS-NS :

  • The CLASS-NS always starts with ::
  • The CLASS-CONSTRUCTOR always return the CLASS-NS.
  • The CLASS-ATTRIBUTE is a variable in the CLASS-NS.
  • The METHOD (instance or class) is a proc in the CLASS-NS.
    • The CONSTRUCTOR is an exported proc called like CLASS-NAME with a INSTANCE-NS as first argument.
    • The DESTRUCTOR is an exported proc called like ~CLASS-NAME with a INSTANCE-NS as first argument.
    • The PUBLIC-METHOD is a proc with namespace export attribute.
    • The CLASS-METHOD is a proc without INSTANCE-NS as first argument.
    • The INSTANCE-METHOD is a proc wit INSTANCE-NS as first argument.
  • The SUPER-CLASS is the CLASS-NS of another class whose public methods are imported into the SUB-CLASS-NS.
    • The SUPER-CLASS-CONSTRUCTOR is called by the SUB-CLASS-CONSTRUCTOR as normal proc.

An INSTANCE is a my array in the INSTANCE-NS :

  • The INSTANCE-NS always starts with ::
  • The INSTANCE-CONSTRUCTOR always return the INSTANCE-NS
  • The INSTANCE-ATTRIBUTE is an element in the my array.
  • The INSTANCE-METHOD always has the INSTANCE-NS as first argument.
  • The INSTANCE-REF is created using namespace upvar INSTANCE-NS my otherVar

libmyoo

libmyoo - myoo c-api defined by only one page of code

libmyoo always loads tclmyoo first and then replaces the performance-relevant procedures with C code.

  • This approach ensures that new capabilities are quickly implemented in TCL, which can then be reprogrammed with C if required.
Note
Since all capabilities are available in TCL (tclmyoo) and in C (libmyoo), it is without restrictions possible to use the capabilities of myoo completely without libmyoo, which makes it easy, for example, to run the myoo code in the browser or in another specially secured environment.

Performance

Although tclmyoo and libmyoo each use only one page of code, it has been shown that the application performs better than the traditional tcloo.

  • The reason for the superiority of myoo lies in the completely different technology (reference-based) which is far superior to the approach of tcloo (command-based).

It should also be noted that translating an application written with tclmyoo into C-only code with the Tcl-2-C-Compiler is possible at any time.

  • This closes the skills-gap between rapid prototyping under TCL and final delivery as a C/binary application.

Goals

‍The central development goal for libmyoo was to implement Object-Oriented-Programming (OOP) in TCL with the minimal possible effort combined with the maximum possible execution speed.

Note
Python and GO Object-Oriented-Programming (OOP) design were used as template for myoo.
A brief overview of what's coming : tcloo versa myoo

The difference between tcloo and myoo :

  1. tcloo is command-based and myoo is reference-based.
  2. With tcloo there is a procedure in the namespace and with myoo there is an array (hash) in the namespace.
  3. While with tcloo the access to the instance-method is always an indirect-call via the instance-procedure, with myoo the access to the instance-method is always a direct-call of the method-procedure in the class-namespace.
  4. With tcloo the instance-object is always coded in C and linked to the instance-procedure, while with myoo the instance-object is located as an array in its own namespace and is therefore always accessible via TCL or C.

Initialization

  • main/Initialize.atl

The libmyoo is available as TCL loadable package :

 
# Load the the tcl extension with :
package require tclmyoox
> 1.0

# The package 'tclmyoox' has a private namespace called '::myooX'
print myooX
> myooX<namespace>
  | variables   | * : info : vars
  | ----------- | --------------------------------------------------------------------------------------------------
  | public-own  | CreateI : DestroyI : SuperI
  | ----------- | --------------------------------------------------------------------------------------------------
  | private-own | ClassIsN                        : ClassN                 : Create1N               : Create2N
  | <>          | Create3N                        : CtorN                  : DestroyN               : MakeN
  | <>          | NewN                            : RecompileN             : ResetN                 : SuperN
  | <>          | _ErrorCatch                     : _ErrorCatchCtorFailedN : _ErrorCatchDtorFailedN : _ErrorRaise
  | <>          | _ErrorRaiseCtorInvalidArgumentN
  | ----------- | --------------------------------------------------------------------------------------------------
 
details
  • All commands ending with 'N' are called from OUTSIDE the class or procedure definition and require a namespace as the FIRST argument.
  • All commands ending with 'I' are called INSIDE the class or procedure definition and are used for configuration etc.

Class

  • main/Class.atl

A class is a namespace with an array of name 'cls'

 
# Create the class of name ::MyClass :
# REMEMBER: The 'ClassN' command return the CLASS-NS.
::myooX::ClassN ::MyClass
> ::MyClass

# The CLASS-REF is initial filled with OO specific items :
print -list ::MyClass
> LIST
  | ::MyClass            : <namespace>
  |                      : variables : * : info : vars
  | -------------------- : ---------------------------------

# A more complex example using multiple classes
::myooX::ClassN ::AnotherClass {
  # A CLASS-attribute is just a normal namespace variable
  variable clsVar  "hallo"
  # ::MyClass is the super-class of ::AnotherClass
  SuperI ::MyClass
  # The constructor is called like the class
  proc AnotherClass { myNs someVal } {
    # Access the CLASS-variable
    variable clsVar
    # Make the INSTANCE-NS to a LOCAL-REF
    namespace upvar $myNs my my
    # intitialize the INSTANCE-ATTRIBUTE called 'val'
    set my(val) $someVal-$clsVar
  }
  # The destructor is called like the constructor but with '~'
  proc ~AnotherClass {} {
    # Free a ressource
  }
}
> ::AnotherClass

# A class is a 'singelton' and is located always in the CLASS-NS :
print -list ::AnotherClass
> LIST
  | ::AnotherClass       : <namespace>
  |                      : variables  : * : info : vars
  |                      : public-own : AnotherClass : ~AnotherClass
  | -------------------- : -----------------------------------------------

# A class can be modified from outside ...
proc ::MyClass::MyClass {otherArg} {
  # ...
}
> 

# but have to be recompiled afterwords.
::myooX::RecompileN ::MyClass
> ::MyClass

print ::MyClass
> ::MyClass<namespace>
  | variables  | * : info : vars
  | public-own | MyClass
 

Instance

  • main/Instance.atl

An instance is a namespace with an array of name 'my'

 
# An instance always require a class
::myooX::ClassN ::MyClass {
  proc MyClass { myNs someVal } {
    namespace upvar $myNs my my
    set my(val) $someVal-123
  }
  proc getVal {myNs} {
    namespace upvar $myNs my my
    set my(val)
  }
}
> ::MyClass


# ===========================================================================================
# create an instance

# By default a 'instance' created with 'NewN' is always located in the namespace of the class :
set myNs [::myooX::NewN ::MyClass abc]
> ::MyClass::MyClass-1

# It is an error if the arguments to 'NewN' are incompatible with the arguments of the class-constructor :
::myooX::NewN ::MyClass abc def
> error: in itpEvalDirect
[CtorN] call CTOR failed for instance '::MyClass::MyClass-2'.
  | wrong # args: should be "::MyClass::MyClass myNs someVal"
  |     while executing
  | "::MyClass::MyClass ::MyClass::MyClass-2 abc def"
    while executing
"::myooX::NewN ::MyClass abc def"
    invoked from within
"interp eval $itp $cmd"

# The namespace of ::MyClass has now a new child because 'NewN' create a annonymous instance :
print ::MyClass
> ::MyClass<namespace>
  | variables   | * : info : vars
  | children    | ::MyClass::MyClass-1
  | public-own  | MyClass
  | private-own | getVal

# It is also possible to create a NAMED-INSTANCE in the namespace of the CLASS or in the namespace specified :
::myooX::Create2N ::MyClass ::otto 998
> ::otto

# Same procedure as ...
print ::otto
> ::otto<namespace>
  | variables | * : info : vars
 

Instance with SUPER-class

Task : create and initialize an INSTANCE with SUPER-class

  • main/Instance-Super.atl
 
# first class
# load tcl-only extension
package require tclmyoox
> 1.0

# define the class (super-class)
::myooX::ClassN ::classA {
  # CLASS-ATTRIBUTE
  variable counter 0
  # ONLY export aProc (CTOR & DTOR are exported always)
  namespace export -clear aProc
  # CTOR
  proc classA {myNs name} {
    # access INSTANCE attribute
    namespace upvar $myNs my my
    # set INSTANCE-ATTRIBUTE
    set my(nameA) "(aVar:$name)"
  }
  # a method
  proc aProc {myNs} {
    # access INSTANCE attribute
    namespace upvar $myNs my my
    # access CLASS-ATTRIBUTE
    variable counter
    incr counter
    return "(aProc\[%$counter]:$my(nameA))"
  }
}
> ::classA

#second class
::myooX::ClassN ::classB {
  # CLASS-ATTRIBUTE
  variable counter 0
  # add super-class
  SuperI ::classA
  # constructor
  proc classB { myNs name } {
    # create LOCAL-REF
    namespace upvar $myNs my my
    # the pogrammer HAVE to call the CONSTRUCTOR of the SUPER-CLASS
    classA $myNs "(bCtor:$name)"
    # initialize INSTANCE-ATTRIBUTE
    set my(nameB) "(bVar:$name)"
  }
  # a method
  proc bProc {myNs} {
    # create LOCAL-REF
    namespace upvar $myNs my my
    # access CLASS-ATTRIBUTE
    variable counter
    # modify CLASS-ATTRIBUTE
    incr counter
    # always use the LOCAL-REF because it is already resolved
    return "(bProc\[%$counter]:[aProc $myNs]-|-$my(nameB))"
  }
}
> ::classB

# create an annonymous INSTANCE and return INSTANCE-NS
set myNs [::myooX::NewN ::classB veggi]
> ::classB::classB-1
# resolve INSTANCE-NS into a LOCAL-REF
namespace upvar $myNs my myR
> 

::classB::aProc $myNs           ; # call aProc with INSTANCE-NS
> (aProc[%1]:(aVar:(bCtor:veggi)))
::classB::bProc $myNs           ; # call bProc with INSTANCE-NS
> (bProc[%1]:(aProc[%2]:(aVar:(bCtor:veggi)))-|-(bVar:veggi))

::classB::aProc $myR(__NS__)    ; # call aProc with LOCAL-REF
> (aProc[%3]:(aVar:(bCtor:veggi)))
::classB::bProc $myR(__NS__)    ; # call bProc with LOCAL-REF
> (bProc[%2]:(aProc[%4]:(aVar:(bCtor:veggi)))-|-(bVar:veggi))

# 1. show the REFERENCE and the NAMESPACE of the LOCAL-REF
print -list myR $myR(__NS__)
> LIST
  | myR                  : <instance>
  |                      : __CLASS__ : ::classB
  |                      : __NAME__  : classB-1
  |                      : __NS__    : ::classB::classB-1
  |                      : nameA     : (aVar:(bCtor:veggi))
  |                      : nameB     : (bVar:veggi)
  | -------------------- : -----------------------------------
  | ::classB::classB-1   : <namespace>
  |                      : variables : * : info : vars
  | -------------------- : ---------------------------------

# 2. show the REFERENCE and the NAMESPACE of the INSTANCE-NS
print -list $myNs
> LIST
  | ::classB::classB-1   : <namespace>
  |                      : variables : * : info : vars
  | -------------------- : ---------------------------------

# 3. show the REFERENCE and the NAMESPACE of the INSTANCE-class
print -list $myR(__CLASS__)
> LIST
  | ::classB             : <namespace>
  |                      : variables   : * : info : vars
  |                      : children    : ::classB::classB-1
  |                      : public-own  : classB
  |                      : private-own : bProc
  |                      : private-imp : aProc : classA
  | -------------------- : --------------------------------------
 

Instance with EMBEDDED-class

Task : create an INSTANCE in the namespace of another INSTANCE

  • main/Instance-Embedded.atl
 
package require tclmyoox
> 1.0

# first class
::myooX::ClassN ::classA {
  # ONLY export aProc (CTOR & DTOR are exported always)
  namespace export -clear aProc
  # CTOR
  proc classA {myNs name} {
    namespace upvar $myNs my my
    # set INSTANCE-ATTRIBUTE
    set my(nameA) $name-in-A
  }
  # DTOR
  proc ~classA {myNs} {
    # cleanup
  }
  proc aProc {myNs} {
    namespace upvar $myNs my my
    return "aProc-|-$my(nameA)"
  }
}
> ::classA

#second class
::myooX::ClassN ::classB {
  # CTOR
  proc classB { myNs name } {
    namespace upvar $myNs my my
    # set INSTANCE-ATTRIBUTE
    set my(nameB) $name-in-B
    # create the EMBEDDED-INSTANCE with name 'embA' and class '::classA' into the NAMESPACE of instance 'my'
    # REMEMBER: if the CURRENT instance (my) is deleted the EMBEDDED instance (embA) is also deleted :
    CreateI $myNs ::classA embA ::classA $name-add-to-A
  }
  # DTOR
  proc ~classB { myNs } {
    namespace upvar $myNs my my
    # destroy the EMBEDDED instance
    # REMEMBER: 'embA' is the EMBEDDED-INSTANCE
    DestroyI $myNs $my(embA)
  }
  proc bProc { myNs } {
    namespace upvar $myNs my my
    return [::classA::aProc $my(embA)]-|-$my(nameB)
  }
}
> ::classB

# ======================================================================================
# ANNONYMOUS instance

# create annonymous INSTANCE
# REMEMBER: the ANNONYMOUS-INSTANCE is created in the NS of the class with 'cls(__NAME__)-__INDEX__' as name
set myNs [::myooX::NewN ::classB veggi]
> error: in itpEvalDirect
[CtorN] call CTOR failed for instance '::classB::classB-1'.
  | [CtorN] call CTOR failed for instance '::classB::classB-1::embA'.
  |   | wrong # args: should be "::classA::classA myNs name"
  |   |     while executing
  |   | "$cls(__CTOR__) $myNs {*}$argsL"
  |     while executing
  | "CtorN $clsNs [MakeN $clsNs $Xname $Xns] $args"
  |     (procedure "Create3N" line 2)
  |     invoked from within
  | "Create3N $clsNs $embName $myNs {*}$args"

# access a LOCAL-REF is faster than the INSTANCE-NS because it is already resolved.
namespace upvar $myNs my myR
> error: in itpEvalDirect
can't read "myNs": no such variable
    while executing
"namespace upvar $myNs my myR"
    invoked from within
"interp eval $itp $cmd"

# call "bProc" with INSTANCE-NS
time {::classB::bProc $myNs} 1000
> error: in itpEvalDirect
can't read "myNs": no such variable
    while executing
"::classB::bProc $myNs"
    invoked from within
"time {::classB::bProc $myNs} 1000"

# 1. show the REFERENCE and the NAMESPACE of the INSTANCE
# REMEMBER: the EMBEDDED-NAMESPACE 'embA' is now a CHILD-NAMESPACE of the INSTANCE
print -list myR $myR(__NS__)
> error: in itpEvalDirect
can't read "myR(__NS__)": no such variable
    while executing
"print -list myR $myR(__NS__)"
    invoked from within
"interp eval $itp $cmd"

# 2. show the REFERENCE and the NAMESPACE of the INSTANCE-class
# REMEMBER: the CLASS-ATTRIBUTE __INDEX__ is incremented by one
# REMEMBER: the INSTANCE-NAMESPACE 'classB-1' is now a CHILD-NAMESPACE of the class
print -list $myR(__CLASS__)
> error: in itpEvalDirect
can't read "myR(__CLASS__)": no such variable
    while executing
"print -list $myR(__CLASS__)"
    invoked from within
"interp eval $itp $cmd"

# 3. show the REFERENCE and the NAMESPACE of the embedded INSTANCE in 'classB'
print -list $myR(embA)
> error: in itpEvalDirect
can't read "myR(embA)": no such variable
    while executing
"print -list $myR(embA)"
    invoked from within
"interp eval $itp $cmd"

# To access the embedded INSTANCE a LOCAL-REF is also possible
namespace upvar $myR(embA) my embAR
> error: in itpEvalDirect
can't read "myR(embA)": no such variable
    while executing
"namespace upvar $myR(embA) my embAR"
    invoked from within
"interp eval $itp $cmd"

# same as above but use the LOCAL-REFERENCE
print -list embAR $embAR(__NS__)
> error: in itpEvalDirect
can't read "embAR(__NS__)": no such variable
    while executing
"print -list embAR $embAR(__NS__)"
    invoked from within
"interp eval $itp $cmd"

# delete the INSTANCE, call the __DTOR__
::myooX::DestroyN $myNs
> error: in itpEvalDirect
can't read "myNs": no such variable
    while executing
"::myooX::DestroyN $myNs"
    invoked from within
"interp eval $itp $cmd"

# the INSTANCE-ATTRIBUTE 'embA' and the EMBEDDED-NAMESPACE 'embA' are now deleted
print myR
> myR

# ======================================================================================
# NAMED instance

# every new INSTANCE is created by default in the NS of the class this also include the NAMED instance
set myNs2 [::myooX::Create2N ::classB otto something]
> error: in itpEvalDirect
[CtorN] call CTOR failed for instance '::classB::otto'.
  | [CtorN] call CTOR failed for instance '::classB::otto::embA'.
  |   | wrong # args: should be "::classA::classA myNs name"
  |   |     while executing
  |   | "$cls(__CTOR__) $myNs {*}$argsL"
  |     while executing
  | "CtorN $clsNs [MakeN $clsNs $Xname $Xns] $args"
  |     (procedure "Create3N" line 2)
  |     invoked from within
  | "Create3N $clsNs $embName $myNs {*}$args"
namespace upvar $myNs2 my myR2
> error: in itpEvalDirect
can't read "myNs2": no such variable
    while executing
"namespace upvar $myNs2 my myR2"
    invoked from within
"interp eval $itp $cmd"

# LOCAL-REF of the INSTANCE and CLASS of the INSTANCE
# REMEMBER: the CLASS-NS has now a new CHILD-NS with name "otto"
# REMEMBER: the CLASS-ATTRIBUTE __INDEX__ is only incremented if a new ANNONYMOUS-INSTANCE is created
print -list myR2 $myR2(__CLASS__)
> error: in itpEvalDirect
can't read "myR2(__CLASS__)": no such variable
    while executing
"print -list myR2 $myR2(__CLASS__)"
    invoked from within
"interp eval $itp $cmd"

# ======================================================================================
# ABSOLUT NAMED instance

# the new INSTANCE with NAMED-NS is created
# REMEMBER: '::hermann' is the NAMESPACE
::myooX::Create2N ::classB ::hermann other
> error: in itpEvalDirect
[CtorN] call CTOR failed for instance '::hermann'.
  | [CtorN] call CTOR failed for instance '::hermann::embA'.
  |   | wrong # args: should be "::classA::classA myNs name"
  |   |     while executing
  |   | "$cls(__CTOR__) $myNs {*}$argsL"
  |     while executing
  | "CtorN $clsNs [MakeN $clsNs $Xname $Xns] $args"
  |     (procedure "Create3N" line 2)
  |     invoked from within
  | "Create3N $clsNs $embName $myNs {*}$args"

# the NAMED-NS has an array called 'my'
namespace upvar ::hermann my myR3
> error: in itpEvalDirect
namespace "::hermann" not found
    while executing
"namespace upvar ::hermann my myR3"
    invoked from within
"interp eval $itp $cmd"

# both REFERENCES are equal but 'myR3' is already resolved
print -list ::hermann::my myR3
> ::hermann::my        , LIST
  | info                 : myR3

# the EMBEDDED-INSTANCE is now at '::hermann'
print -list ::hermann ::hermann::embA
> ::hermann            , LIST
  | info                 : ::hermann::embA

# the class and the class namespace is UNCHANGED
print -list ::classB
> LIST
  | ::classB             : <namespace>
  |                      : variables   : * : info : vars
  |                      : public-own  : classB : ~classB
  |                      : private-own : bProc
  | -------------------- : ------------------------------------
 

Instance in GLOBAL ns

Task: create a LOCAL instance in a GLOBAL namespace

  • main/Instance-Global-namespace.atl
 
# ===========================================================================================
# more on REFERENCE in GLOBAL namespace

# An instance always require a class
::myooX::ClassN ::MyClass {
  proc MyClass { myNs someVal } {
    namespace upvar $myNs my my
    set my(val) $someVal-123
  }
  proc getVal {myNs} {
    namespace upvar $myNs my my
    set my(val)
  }
}
> ::MyClass

# By default a INSTANCE created with 'NewN' is always located in the namespace of the class :
set gmyNs [::myooX::NewN ::MyClass abc]
> ::MyClass::MyClass-1

# The INSTANCE-NS is like the CLASS-NS a namespace with an array variable :
print -list $gmyNs ::MyClass
> LIST
  | ::MyClass::MyClass-1 : <namespace>
  |                      : variables : * : info : vars
  | -------------------- : ---------------------------------
  | ::MyClass            : <namespace>
  |                      : variables   : * : info : vars
  |                      : children    : ::MyClass::MyClass-1
  |                      : public-own  : MyClass
  |                      : private-own : getVal
  | -------------------- : ----------------------------------------

# A INSTANCE-NS can always made to a LOCAL-REF using :
namespace upvar $gmyNs my gmy
> 

# The 'gmy' and the 'gmyNs::my' point to the SAME variable :
print -list gmy ${gmyNs}::my
> LIST
  | gmy                  : <instance>
  |                      : __CLASS__ : ::MyClass
  |                      : __NAME__  : MyClass-1
  |                      : __NS__    : ::MyClass::MyClass-1
  |                      : val       : abc-123
  | -------------------- : -----------------------------------
  | ::MyClass::MyClass-1::my : <instance>
  |                      : __CLASS__ : ::MyClass
  |                      : __NAME__  : MyClass-1
  |                      : __NS__    : ::MyClass::MyClass-1
  |                      : val       : abc-123
  | -------------------- : -----------------------------------

# Calling an instance-method is simple :
::MyClass::getVal $gmyNs
> abc-123

# or just use the LOCAL-REF :
::MyClass::getVal $gmy(__NS__)
> abc-123

# a proc using the instance does NOT require to be part of the class :
proc outsider {myNs} {
  # create LOCAL-REF 'my'
  namespace upvar $myNs my my
  # access 'my'
  return "my=$my(val)"
}
> 

# call a proc using the INSTANCE-NS always works
outsider $gmyNs
> my=abc-123

# call a proc using LOCAL-REF works with '__NS__'
outsider $gmy(__NS__)
> my=abc-123

# call a proc using STRING-NS always works
outsider "::MyClass::MyClass-1"
> my=abc-123
 
Attention
It is always a risk using the TCL buildin variable because of 'special' usage.
-> prefer using TCL buildin upvar

Instance in LOCAL ns

Task: create a LOCAL instance in a LOCAL namespace

  • main/Instance-Local-namespace.atl
 
# ===========================================================================================
# more on REFERENCE in LOCAL namespace

# An instance always require a class
::myooX::ClassN ::MyClass {
  proc MyClass { myNs someVal } {
    namespace upvar $myNs my my
    set my(val) $someVal-123
  }
  proc getVal { myNs } {
    namespace upvar $myNs my my
    set my(val)
  }
}
> ::MyClass

# test INSTANCE access in the namespace '::dummy' :
namespace eval ::dummy {
  namespace current
  > ::dummy
  variable dmyNs
  > 
  # create a INSTANCE in the namespace '::dummy' :
  # REMEMBER: 'Create3N CLASS NAME NS ...' is the same as 'Class2N CLASS NS::NAME ...'
  set dmyNs [::myooX::Create3N ::MyClass xyz ::dummy otto]
  > ::dummy::xyz

  # same as above but using '::dummy::xyz'
  # ATTENTION: overwrite an EXISTING instance will NOT harm and just call the CTOR and return the EXISTING inssance :
  set dmyNs [::myooX::Create2N ::MyClass ::dummy::xyz otto]
  > ::dummy::xyz

  # REMEMBER: the DEFAULT namespace is always the CLASS namespace and NOT the CURRENT namespace :
  set dmy2Ref [::myooX::Create2N ::MyClass abc otto]
  > ::MyClass::abc

  # The INSTANCE-NS is like the CLASS-NS a namespace with an array variable :
  print -list ::dummy $dmyNs ::MyClass
  > LIST
    | ::dummy              : <namespace>
    |                      : variables : * : info : vars
    |                      : children  : ::dummy::xyz
    | -------------------- : ---------------------------------
    | ::dummy::xyz         : <namespace>
    |                      : variables : * : info : vars
    | -------------------- : ---------------------------------
    | ::MyClass            : <namespace>
    |                      : variables   : * : info : vars
    |                      : children    : ::MyClass::abc
    |                      : public-own  : MyClass
    |                      : private-own : getVal
    | -------------------- : -----------------------------------

  # A INSTANCE-NS can always made to a LOCAL-REF using :
  namespace upvar $dmyNs my dmyR
  > 

  # Is 'dmyR' created in the LOCAL-NS ?
  namespace which -variable dmyR
  > ::dummy::dmyR

  # print NS of LOCAL-REF
  print dmyR(__NS__)
  > dmyR(__NS__)<::dummy::xyz>

  # The 'dmyR' and the 'dmyNs::my' point to the SAME variable :
  print -list dmyR ${dmyNs}::my
  > LIST
    | dmyR                 : <instance>
    |                      : __CLASS__ : ::MyClass
    |                      : __NAME__  : xyz
    |                      : __NS__    : ::dummy::xyz
    |                      : val       : otto-123
    | -------------------- : ---------------------------
    | ::dummy::xyz::my     : <instance>
    |                      : __CLASS__ : ::MyClass
    |                      : __NAME__  : xyz
    |                      : __NS__    : ::dummy::xyz
    |                      : val       : otto-123
    | -------------------- : ---------------------------

  # Calling an instance-method is simple :
  ::MyClass::getVal $dmyNs
  > otto-123

  # or just use the LOCAL-REF :
  ::MyClass::getVal $dmyR(__NS__)
  > otto-123

  # a proc using the instance does NOT require to be part of the class :
  proc outsider {dmyNs} {
    # create LOCAL-REF 'my'
    namespace upvar $dmyNs my my
    # access 'my'
    return "my=$my(val)"
  }
  > 

  # call a proc using the INSTANCE-NS always works
  outsider $dmyNs
  > my=otto-123

  # call a proc using LOCAL-REF works with '__NS__'
  outsider $dmyR(__NS__)
  > my=otto-123

  # call a proc using STRING-NS always works
  outsider "::dummy::xyz"
  > my=otto-123
}
 
Attention
It is always a risk using the TCL buildin variable because of 'special' usage.
-> prefer using TCL buildin upvar

Array versa Namespace

‍I struggled with whether myoo should be array-reference-based or namespace-reference-based.

After doing some research with the tclmyoo TCL-API and libmyoo C-API I switch to namespace-reference-based

The following reasons led to the switch to namespace-reference :

  1. With TclGetNamespaceFromObj from the tcl internal Int API, a very powerful tool is available for resolving a namespace.
  2. It has been confirmed that namespace upvar NS my my is significantly faster than upvar NS::my my.
  3. To call a sub-method, the local-reference no longer needs to be resolved because the instance-namespace is always used for the global namespace (::).
  4. An external-pointer can also be attached to the tcl internal Tcl_Namespace* pointer, which speeds up the All-Language-Compiler (ALC) compiler massively.
  5. The code becomes much smaller and simpler by switching to the namespace-reference, so that I can proudly say that myoo is by far the smallest Object-Oriented-Programming (OOP) in the world.
  6. Even with the tcl-only version, tclmyoo is faster than tcloo with over ten years of development work.

performance-test

This section compare the api from myoo (tclmyoo and libmyoo) with the api from tcloo.

It should be noted that myoo, in contrast to tcloo, uses an array as a data structure and is therefore 100%-TCL-compilant.

‍A possible extension would be a direct mapping of the class and instance as a C data structure based on the tcl-array-code, but this will not be 100%-TCL-compliant.

See also
performance test: different variants of 'my'

tcloo versa tclmyoo

tcloo versa libmyoo

tclmyoo versa libmyoo