Check-in [7ff5dde719]

Login
Bounty program for improvements to Tcl and certain Tcl packages.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Updated TIP 500 in light of implementation experience.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7ff5dde719885f7394c8adce89ad344aa5ae5f3bc63c7f304407e5ae8830ade3
User & Date: dkf 2018-05-19 08:37:09
Context
2018-05-19
10:48
Added an example check-in: e6ade010a0 user: dkf tags: trunk
08:37
Updated TIP 500 in light of implementation experience. check-in: 7ff5dde719 user: dkf tags: trunk
2018-05-17
12:58
TIP #491 Done check-in: a23088053b user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to tip/500.md.

32
33
34
35
36
37
38


























39
40
41
42
43
44
45
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66










67





68
69
70
71
72
73
74
..
77
78
79
80
81
82
83

84
85
86
87
88
89
90
..
96
97
98
99
100
101
102




103
104
105
106

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154
...
235
236
237
238
239
240
241
242
243
244
245
246
mechanism does not need to be totally proof against prying (and introspection
mechanisms are desirable) as TclOO deliberately does not provide security
mechanisms; such mechanisms are the purpose of Tcl's interpreters. All that is
desired is a way of ensuring that code does not inadvertently trample other
code, allowing a superclass to evolve its implementation without needing to
take into account every detail of its subclasses.



























# Detailed Proposal: Methods

For methods, as they actually exist in storage that is totally controlled by
TclOO (and which is not addressable other than via TclOO-created commands or
introspectors) the main complexity is working out what lookups are possible in
a particular case while ensuring that method lookups are fast. Determining
what the context class (or instance) is easy enough, as that's present pretty
................................................................................
inside a method that is part of the class *but a different instance* or
possibly even a *different subclass* of that class, then that method will be
found. That makes this a useful mechanism that is not provided by the TclOO
system in Tcl 8.6.

## Method Invoke Semantics

When a method is invoked, a public (or unexported, if via the **self**
command) method is always preferred. However, if the resolution of the method
would result in no resolution of the method, private methods are also
searched. The private methods that are searched are those of the declaration
context (class or method) of the currently executing method only; subclasses
and superclasses are _not_ examined. Filters are still applied to the outside
of the method call, but the actual private method has no need to ever call
**next** or **nextto**; it is always the terminal method implementation in its










method call chain.






A private method on a class (or object) may not have the same name as another
method on that class; all methods of a class (or object) are part of a single
space of names. When resolving a method call of a subclass of the class that
has the private method, even if the method names match, the private method
does not participate in the call chain; only an exact match from exactly the
right context counts.
................................................................................

    oo::class create Top {
        method Foo {} {
            puts "This is Top::Foo for [self]"
        }
    }
    oo::class create Super {

        private method Foo {} {
            puts "This is Super::Foo for [self]"
        }
        method bar {other} {
            puts "This is Super::bar for [self]"
            my Foo
            [self] Foo
................................................................................
        method Foo {} {
            puts "This is Sub::Foo for [self]"
            next
        }
        private method bar {other} {
            error "This should be unreachable"
        }




    }
    Sub create obj1
    Sub create obj2
    obj1 bar obj2


is expected to print out:

    This is Super::bar for ::obj1
    This is Sub::Foo for ::obj1
    This is Top::Foo for ::obj1
    This is Super::Foo for ::obj1
    This is Super::Foo for ::obj2

Note that the call via **my** picks up the unexported method from the
subclass, and that the call from outside does not find the method on _Sub_,
and the call to **next** does not pick up the method on _Super_.

Private methods on object instances are similar, and are only visible from
other instance methods on the same object. The author expects them to be
rarely used.

## Creation and Introspection

Private methods are created calling **oo::define** (and **oo::objdefine**, and
via the constructor of **oo::class**) like this:

    oo::define TheClass {
        private method foo {...} {
            ...
        }
        private forward bar  SomeOtherCommand
    }

More formally, the **private** definition command sets a flag for the duration
of its execution that causes any methods (of any standard type) defined in the
current definition context to be marked as being private rather than using the
usual public/unexported semantics.  All remaining arguments are then
concatenated as a proper Tcl list and the result evaluated in the current
context. It has no effect on recursive calls, or on the **export** or
**unexport** definition commands, or on any custom declaration types.

At the C API level, private methods can be directly created by setting the
*flags* parameter (called *isPublic* in older versions of the API) to the

constant `TCL_OO_METHOD_PRIVATE`. This lets custom types of methods be
declared by their C code directly.

Introspection is done via appropriate options to **info class methods** and
**info object methods**. In particular, they are never returned when the
**-all** option is given, are found when **-private** option is given (unless
the **-all** option is _also_ given), and can be found when the new option
**-scope** is given, depending on what scope is chosen from the options below:

................................................................................
returns the creation ID of any existing object. It also applies to classes.
Again, note that creation IDs are _always_ system-allocated and are _never_
guaranteed to be unique between interpreters, either in multiple processes or
in the same thread or process; they are only ever locally unique.

# Implementation

Not yet done.

# Copyright

This document has been placed in the public domain.






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>







 







>







 







>
>
>
>




>




|
|
|
|
|
|
|
|
|
|
|
<













<
<
<
<
<
<
<
<

|
>
|
|







 







|




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177
178
179
180
181








182
183
184
185
186
187
188
189
190
191
192
193
...
274
275
276
277
278
279
280
281
282
283
284
285
mechanism does not need to be totally proof against prying (and introspection
mechanisms are desirable) as TclOO deliberately does not provide security
mechanisms; such mechanisms are the purpose of Tcl's interpreters. All that is
desired is a way of ensuring that code does not inadvertently trample other
code, allowing a superclass to evolve its implementation without needing to
take into account every detail of its subclasses.

# Private Declarations: Syntax and Immediate Semantics

This TIP introduces a new definition command, **private**, that is present
when doing both **oo::define** and **oo::objdefine**. Much as with the
**self** definition command (or the **oo::define** and **oo::objdefine**
commands themselves), it takes either single arguments or a list of arguments
(that it then builds a script of by turning them into a list) and evaluates
the result in a special context. The special context is the same as the outer
definition context, except that some definition commands instead create
_private definitions_ in that context.

The following commands are private-definition aware:

  * **forward** — the forwarded method it creates is a _private method_.
  * **method** — the procedure-like method it creates is a _private method_.
  * **self** (in **oo::class**) — the definitions on the class instance inside
    will be _private definitions_ (if the concept applies).
  * **variable** — the variable resolution rules created or manipulated (as
    this is a slot) will be for _private variables_.

If provided with no arguments, the **private** definition command will return
whether it was invoked from a context that should create private definitions.
Otherwise it returns the result of evaluating its script.

The meaning of a private method and a private variable is defined below.

# Detailed Proposal: Methods

For methods, as they actually exist in storage that is totally controlled by
TclOO (and which is not addressable other than via TclOO-created commands or
introspectors) the main complexity is working out what lookups are possible in
a particular case while ensuring that method lookups are fast. Determining
what the context class (or instance) is easy enough, as that's present pretty
................................................................................
inside a method that is part of the class *but a different instance* or
possibly even a *different subclass* of that class, then that method will be
found. That makes this a useful mechanism that is not provided by the TclOO
system in Tcl 8.6.

## Method Invoke Semantics

When a method is invoked, a public (or unexported, if via the **my** command)
method is usually preferred. However, if the class of the object on which the
method is called is also the class that defined the currently executing method
(specifically, is the creator of the method that defines the current stack
frame at the point of the call), bearing in mind that the determination of
this also respects the inheritance and mixin hierarchies, then private methods
on that context class will also be found. Similarly, if the currently
executing method was defined by an object and that object is the object to
which the method invoke is directed, private methods on that object are also
found (the author expects these to be a rarely used feature). Searches for
private methods precede the equivalent public and unexported methods in the
method resolution order, but share a common naming space (i.e., they're stored
in the same hash tables) so that there are no ambiguities.

Since every method has at most one declaring class or object (and not both
simultaneously) there is at most one private method that can be on any call
chain. External calls (e.g., from the top level of Tcl, from a **namespace
eval**, from a procedure) will never have a private method on thir call
chains.

Once the call chain is created, the execution is handled as prior to this TIP;
the implementation of the first element on the call chain is executed,
whatever that is, and that can dispatch to later items on the call chain using
**next** and **nextto**.

A private method on a class (or object) may not have the same name as another
method on that class; all methods of a class (or object) are part of a single
space of names. When resolving a method call of a subclass of the class that
has the private method, even if the method names match, the private method
does not participate in the call chain; only an exact match from exactly the
right context counts.
................................................................................

    oo::class create Top {
        method Foo {} {
            puts "This is Top::Foo for [self]"
        }
    }
    oo::class create Super {
        superclass Top
        private method Foo {} {
            puts "This is Super::Foo for [self]"
        }
        method bar {other} {
            puts "This is Super::bar for [self]"
            my Foo
            [self] Foo
................................................................................
        method Foo {} {
            puts "This is Sub::Foo for [self]"
            next
        }
        private method bar {other} {
            error "This should be unreachable"
        }
        method grill {} {
            puts "This is Sub::grill for [self]"
            my Foo
        }
    }
    Sub create obj1
    Sub create obj2
    obj1 bar obj2
    obj1 grill

is expected to print out:

    This is Super::bar for ::obj1
    This is Super::Foo for ::obj1
    This is Super::Foo for ::obj1
    This is Super::Foo for ::obj2
    This is Sub::grill for ::obj1
    This is Sub::Foo for ::obj1
    This is Top::Foo for ::obj1

Note that the calls via **my**, **self** and through the public handle of
another object all pick up the private method from _Super_,
and the call to **next** from _Sub_ does not pick up the method on _Super_ but
instead goes straight to _Top_.


## Creation and Introspection

Private methods are created calling **oo::define** (and **oo::objdefine**, and
via the constructor of **oo::class**) like this:

    oo::define TheClass {
        private method foo {...} {
            ...
        }
        private forward bar  SomeOtherCommand
    }









At the C API level, private methods can be directly created by setting the
*flags* parameter (called *isPublic* in older versions of the API) of
`Tcl_NewMethod` and `Tcl_NewInstanceMethod` to the constant
`TCL_OO_METHOD_PRIVATE`. This lets custom types of methods be declared private
by their C code directly.

Introspection is done via appropriate options to **info class methods** and
**info object methods**. In particular, they are never returned when the
**-all** option is given, are found when **-private** option is given (unless
the **-all** option is _also_ given), and can be found when the new option
**-scope** is given, depending on what scope is chosen from the options below:

................................................................................
returns the creation ID of any existing object. It also applies to classes.
Again, note that creation IDs are _always_ system-allocated and are _never_
guaranteed to be unique between interpreters, either in multiple processes or
in the same thread or process; they are only ever locally unique.

# Implementation

See the [`tip-500` branch](https://core.tcl.tk/tcl/timeline?r=tip-500).

# Copyright

This document has been placed in the public domain.