Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to use TclOO's renamemethod?

66 views
Skip to first unread message

Arjen Markus

unread,
Apr 8, 2019, 3:10:20 PM4/8/19
to
Hello,

I am trying to define objects with specialised methods using TclOO and I am running into a problem - any help (including alternative methods ;)) appreciated.

Here is my code (it can be further reduced, of course, but illustrates what I am after):

# q.tcl --
# What is going wrong?
#

namespace eval quasirandom {

# qrpoints --
# Create the class
#
::oo::class create qrpoints {

# constructor --
# Construct a new instance of the qrpoints class
#
# Arguments:
# dimin Number of dimensions, or one of: circle, disk, sphere, ball
#
constructor {dimin} {
my variable dim

if { ( ![string is integer -strict $dimin] || $dimin <= 0 ) && $dimin ni {circle disk sphere ball} } {
return -code error "The dimension argument should be a positive integer value or one of circle, disk, sphere or ball"
}

switch -- $dimin {
"circle" {
set dim 1
}
"disk" -
"sphere" {
set dim 2
}
"ball" {
set dim 3
}
default {
set dim $dimin
}
}

my Setup $dimin
}

# Setup --
# Private method to set up the type-dependent methods
#
# Arguments:
# dimension Dimension or type string
#
method Setup {dimension} {
if { [string is integer $dimension] } {
::oo::objdefine [self] {
renamemethod PlainNext next
}
} else {
TODO
}
}

# PlainNext --
# Generate the next point - for a hyperblock
#
method PlainNext {} {
return {1 2}
}

} ;# End of class

} ;# End of namespace eval

# --------------------------------------------
# test --
#

quasirandom::qrpoints create square 2

puts [square next]


And here is the error message I get:

method PlainNext does not exist
while executing
"renamemethod PlainNext next"
(in definition script for object "::square" line 2)
invoked from within
"::oo::objdefine [self] {
renamemethod PlainNext next
}"
(class "::quasirandom::qrpoints" method "Setup" line 3)
invoked from within
"my Setup $dimin"
(class "::quasirandom::qrpoints" constructor line 24)
invoked from within
"quasirandom::qrpoints create square 2"
(file "q.tcl" line 75)


What I do not understand is why the method PlainNext does not exist. It is clearly there in the code. I hope it is a simple mistake.

Regards,

Arjen

s.effe...@googlemail.com

unread,
Apr 9, 2019, 4:06:10 AM4/9/19
to
Not a solution but ...

Unfortunately, there is no test in Tcl's own test suite for an object based renamemethod.

I tried (in the constructor):
::oo:objdefine [self] { method PlainNext { return {1 2} } }

"PlainNext" is now undeniably an object method. Result: The renaming itself works, calling "next" doesn't work.

I tried (in the constructor):
::oo:objdefine [self] { method plainNext { return {1 2} } }

Observe the lower case "p", the renaming is of course also done on "plainText". Result: Renaming works, calling "next" works.

Then I tried it with a class method plainText. Renaming doesn't work.

Preliminary verdict: It seems that class methods don't become object methods upon object construction (or are note recognised by renamemethod as such). Visibility rules are obscure.

-- Stephan

Arjen Markus

unread,
Apr 9, 2019, 4:22:56 AM4/9/19
to
Thanks for this analysis. Hm, food for thought. I suppose an alternative could be to define a hierarchy of classes and hide that from the user (by providing a simple command that return an object instead of using the class directly).

Regards,

Arjen

Harald Oehlmann

unread,
Apr 9, 2019, 4:41:30 AM4/9/19
to
Stefan,

a missing test is a bug. Could you file a bug report on
core.tcl-lang.org/tcl ?

Thank you,
Harald

Donal K. Fellows

unread,
Apr 9, 2019, 5:02:34 AM4/9/19
to

On 08/04/2019 20:10, Arjen Markus wrote:
> What I do not understand is why the method PlainNext does not exist.

The method exists in the definition scope of the class, but not in the
definition scope of the instance. (These are different, and are stitched
together to form the collection of methods you can call by TclOO's
dispatch engine. That's got lots of caching and cunningness under the
covers to avoid copying stuff where it doesn't need to.) The
[renamemethod] definition command only moves a method around within its
definition scope.

I think you'd have been better off using a forward:

method Setup {dimension} {
if { [string is integer $dimension] } {
::oo::objdefine [self] {
forward next my PlainNext
# I've put extra spaces in above for clarity
}
} else {
TODO
}
}

Alternatively, define “profiles” of how things can work as classes and
mix them in:

method Setup {dimension} {
if { [string is integer $dimension] } {
::oo::objdefine [self] {
mixin PlainPointsProfile
}
} else {
TODO
}
}

...

class PlainPointsProfile {
# next --
# Generate the next point - for a hyperblock
#
method next {} {
return {1 2}
}
}

The best choice depends on whether you're doing a little patching in the
Setup method or bringing in a whole bunch of methods at once. (Also, I
could probably name things better.)

Donal.
--
Donal Fellows — Tcl user, Tcl maintainer, TIP editor.

Arjen Markus

unread,
Apr 9, 2019, 5:08:09 AM4/9/19
to
Ah, thanks for these suggestions. I am a trifle uncertain as to how the various properties of the original object can be used in these mixins, but that ought to be cliarifed via some experimentation.

Regards,

Arjen

Donal K. Fellows

unread,
Apr 9, 2019, 5:23:59 AM4/9/19
to

On 09/04/2019 09:06, s.effe...@googlemail.com wrote:
> Unfortunately, there is no test in Tcl's own test suite for an
> object based renamemethod.

That was an oversight. Fixed (on the 8.6 branch for now; will be merged
to the other main branches Real Soon).

> It seems that class methods don't become object methods upon object
> construction
That is indeed correct. Doing such a copy provides simple semantics (I
once wrote an object system that worked like that) but it's very memory
hungry and slow to create instances, as every method that might ever be
used has to be copied in. And it also means that modifying a class does
not affect the instances of that class.

Harald Oehlmann

unread,
Apr 9, 2019, 11:03:48 AM4/9/19
to
Am 09.04.2019 um 11:23 schrieb Donal K. Fellows:
>
> On 09/04/2019 09:06, s.effe...@googlemail.com wrote:
>> Unfortunately, there is no test in Tcl's own test suite for an
>> object based renamemethod.
>
> That was an oversight. Fixed (on the 8.6 branch for now; will be merged
> to the other main branches Real Soon).

Thanks, Donal, for caring ! Very aprciated !

Arjen Markus

unread,
Apr 9, 2019, 2:35:22 PM4/9/19
to
On Tuesday, April 9, 2019 at 11:02:34 AM UTC+2, Donal K. Fellows wrote:
I tried the "forward" solution and that worked, but the "mixin" solution produced:

PlainPointProfile does not refer to an object
while executing
"::oo::Obj9::my Set PlainPointProfile"
("uplevel" body line 1)
invoked from within
"uplevel 1 [list [namespace which my] Set $args]"
(class "::oo::Slot" method "-set" line 2)
invoked from within
"::oo::Obj9::my --default-operation PlainPointProfile"
("uplevel" body line 1)
invoked from within
"uplevel 1 [list [namespace which my] $def {*}$args]"
(class "::oo::Slot" method "unknown" line 6)
invoked from within
"mixin PlainPointProfile"
(in definition script for object "::square" line 2)
invoked from within
"::oo::objdefine [self] {
mixin PlainPointProfile
}"
(class "::quasirandom::qrpoints" method "Setup" line 6)
invoked from within
"my Setup $dimin"
(class "::quasirandom::qrpoints" constructor line 24)
invoked from within
"quasirandom::qrpoints create square 2"
(file "q.tcl" line 88)

As the "forward" solution is quite suitable for my purpose, I will choose that, but the error with the other solution is noteworthy as well.

Regards,

Arjen

Arjen Markus

unread,
Apr 10, 2019, 2:51:54 AM4/10/19
to
Oops, my mistake (I think): I create the classes in the namespace "::quasirandom" and that is apparently not where ::oo::objdefine looks for mixin classes.

Or is there some friction between namespaces and ::oo::objdefine?

Regards,

Arjen

Christian Gollwitzer

unread,
Apr 10, 2019, 3:03:05 AM4/10/19
to
Am 10.04.19 um 08:51 schrieb Arjen Markus:
>>> I think you'd have been better off using a forward:
>>>
>>> method Setup {dimension} {
>>> if { [string is integer $dimension] } {
>>> ::oo::objdefine [self] {
>>> forward next my PlainNext
>>> # I've put extra spaces in above for clarity
>>> }
>>> } else {
>>> TODO
>>> }
>>> }

Hi Arjen,

which quasirandom numbers do you generate? I have an implementation of
Kocis-White scrambled Halton sequences in C++, and was thinking to
translate it into Tcl for a project with Monte-Carlo sampling. I'd be
interested in your implementation, if you make it available.

Christian

Arjen Markus

unread,
Apr 10, 2019, 3:15:15 AM4/10/19
to
Hi Christian,

I am working on this sequence by Martin Roberts - http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/

I have a decent enough implementation ready, see the Wiki (https://wiki.tcl-lang.org/page/Evaluation+of+multiple+integrals+using+quasi%2Drandom+points) for the very first version. It really seems a lot better than Halton and others I have experimented with. And much easier to implement :).

My intention is to include it in Tcllib, but right now it lacks documentation and proper test cases.

Regards,

Arjen

Donal K. Fellows

unread,
Apr 10, 2019, 4:40:39 AM4/10/19
to

On 10/04/2019 07:51, Arjen Markus wrote:
> Oops, my mistake (I think): I create the classes in the namespace
> "::quasirandom" and that is apparently not where ::oo::objdefine
> looks for mixin classes.
>
> Or is there some friction between namespaces and ::oo::objdefine?
TclOO tries to be very careful with namespaces and stack frames. This
can mean that sometimes you need to be as careful too, but not usually
if you're just using the simple parts of it.

It looks in whatever is the current namespace in the scope where
[oo::define] or [oo::objdefine] is called. It's the most intuitive way
of working I could think of. It's a bit like how the names you use with
the “create” method are resolved in the caller's scope, and not in the
internal namespace scope of the class that you've invoked the method on.

Without that, it'd be looking in a namespace that you really don't
expect (::oo::objdefine in this case) and that's not useful to anyone.
0 new messages