Can anybody please help me with the following problem:
I am learning XOTCL and loved the concept the way it was described in
documentation. I was immediately suspicious if it will work as
described because with TCL things tend to break/not work as expected
quite often.
Consider the following very simple code:
*************************************************
package require XOTcl
namespace import -force xotcl::*
Class Test
Test my-test
*************************************************
So far all looks fine. Then I run the following command:
% namespace children
::dom ::critcl ::xml ::platform ::activestate ::xotcl ::pkg ::vfs ::tcl
As you can see, namespace "my-test" is not there. It should be there,
it WAS there before when I ran the same code in a different session.
XOTcl object namespaces seem to show up and disappear randomly in
the :: namespace. What gives? I needed to use the nested objects in my
code and XOTcl provided exactly what I needed but doesn't look like it
works reliably.
Thanks
I wish I could help more, but where are the new objects supposed to be
created? One problem (misconception actually) with Tcl is that you can
import commands all you want, but they still execute in the original
namespace. So if xotcl creates stuff below ::xotcl, importing the
command doesn't change that.
I also don't know how visible the new stuff actually is. I think there
is C code involved. If it is anything like tDOM, you don't necessarily
get introspection. Maybe there are specific commands that do it?
I would just spend lots of time testing, it isn't an obvious extension
of Tcl.
Thanks Tom,
I found a solution, which is better described as a workaround.
I added the following constructor code:
Test instproc init {} {Class [self]::dummy;[self]::dummy destroy;}
What happens is that the init (constructor) tries to create an object
called "dummy" nested inside the object's namespace that I need to
create which in turn forces XOTcl to create a namespace with the same
name as the object I am trying to create. After that the "dummy"
object is destroyed.
I don't know why it works, has something to do with the way XOTcl
works internally I guess. I still wish I didn't have to use that
workaround. Hopefully somebody has a better solution.
Thanks again.
Can you provide a complete example of what works? Maybe a full example
is verbose, but it answers many questions which may be obvious to you,
but not to others with the same issue.
Here you go,
#####################################################################
Case #1:
#####################################################################
package require XOTcl
namespace import -force xotcl::*
Class Test
Test t1
Test t1::t2
------------------------------------------------------------------------------------
ERROR> Object alloc failed for '::t1::t2' (possibly parent namespace
does not exist)
####################################################################################
#####################################################################
Case #2:
#####################################################################
package require XOTcl
namespace import -force xotcl::*
Class Test
Test instproc init {} {Class [self]::dummy; [self]::dummy destroy}
Test t1
Test t1::t2
---------------------------------------------------------------------
NO ERRORS
#####################################################################
#####################################################################
The only difference between case #1 and case #2 is this line:
Test instproc init {} {Class [self]::dummy; [self]::dummy destroy}
I am thinking now that it has to be a bug, because case #1 code does
often work without any errors. In case you are wondering I do exit
tclsh after each case.
Thanks
I wish I could give an answer. Personally I think xotcl is a separate
language, if it violates Tcl conventions, that doesn't mean it is a
bug. The only thing I notice is that you are using relative
namespaces, without leading ::, sometimes this can be very
significant. I usually get burned when I don't use the absolute
namespace.
In earlier versions of XOTcl every object has own Tcl namespace but
it is not the current
behavior. Now XOTcl object do not create namespace for performance
reasons.
If you need namespace you can use method "requireNamespace".
The most often scenario to do it is linking XOTcl variables with Tk.
Try this:
package require XOTcl
namespace import -force xotcl::*
Class Test
Test my-test
my-test requireNamespace
(bin) 55 % namespace children
::dom ::platform ::xml ::critcl ::activestate ::xotcl ::pkg ::my-
test ::vfs ::tcl
See XOTcl documentation (method requireNamespace)
# one reason to do such things.
entry .e -variable my-test::entry
Artur
Thanks Artur,
This is exactly what I needed. And now the mysterious XOTcl behavior
with namespaces makes more sense.
Thanks to all who tried to help. I appreciate it.
The reason, XOTcl does not create for every object on default a
namespace is not only due to runtime performance (speed), but
even more due to space. Namespaces are quite large c-structures in
Tcl.
create 100k objects without namespace:
Used memory: 27553792
Memory per xotcl object: 275
Time per object: 10
create 100k objects with namespace:
Used memory: 63762432
Memory per xotcl object: 637
Time per object: 13
you see, one saves 30% on speed an a factor of more than 2 on
memory (times in microseconds, memory in bytes).
XOTcl creates for the objects namespaces, when (a) it has to create
it and (b) when it is told to do so. Cases for (a) are e.g. nested
objects, or when object specific methods (object procs) are defined.
One can tell
XOTcl to create a namespace by the method "requireNamespace" (as
Artur
showed it).
In case, someone always wants objects with namespaces, one can provide
a
mixin class to add these automatically
% ./xotclsh
#
# create a mixin class
#
% Class RequireAlwaysNamespaces
::RequireAlwaysNamespaces
#
# refine method create
#
% RequireAlwaysNamespaces instproc create {args} {
set result [next]
$result requireNamespace
return $result
}
#
# add mixin method to the meta-class Class. All classes
# will use this refined method to create objects.
#
% Class instmixin add RequireAlwaysNamespaces::RequireAlwaysNamespaces
#
# Note that Object is the most general class, which will use our mixin
as well
#
% Object create o
::o
#
# check, if we got the namespace
#
% namespace children
::xotcl ::o ::tcl
Hope, this helps...