Prev: Compressing a file (in windows)
Next: Compressing a file (in windows) -sorry for the triple-post
From: Lawrence Woodman on 24 Jul 2010 03:12 Hello all, I am having problems calling unexported methods from the C api. I have the following C code to create a method called set2 in the BaseExample class (this ends up as libset.so): #include <string.h> #include <tcl8.6/tclOO.h> static int Set2(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext, int objc, Tcl_Obj *const objv[]) { char buffer[200]; int argSkip = Tcl_ObjectContextSkippedArgs(objectContext); if (objc != argSkip) { Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } Tcl_Object contextObject = Tcl_ObjectContextObject(objectContext); Tcl_Namespace *namespace = Tcl_GetObjectNamespace(contextObject); if (strlen(namespace->fullName) >= 200-7) { return TCL_ERROR; } /* If I try this line instead of the following then */ /* I get:- ERROR: unknown method "SetX"... */ /* sprintf(buffer, "%s SetX 2", namespace->fullName); */ /* The following generates:- ERROR: invalid command name "my" * sprintf(buffer, "my SetX 2"); if (Tcl_EvalObjEx(interp, Tcl_NewStringObj(buffer, -1), 0) != TCL_OK) { printf("ERROR: %s\n", Tcl_GetStringFromObj (Tcl_GetObjResult(interp), NULL)); } return TCL_OK; } int Set_Init(Tcl_Interp *interp) { const static Tcl_MethodType set2MethodType = { TCL_OO_METHOD_VERSION_CURRENT, /* version */ "set2", /* name */ Set2, /* callProc */ NULL, /* deleteProc */ NULL /* cloneProc */ }; Tcl_Obj *baseName; Tcl_Object baseObject; Tcl_Class baseClass; Tcl_Obj *set2Name; // Get the root class // Get the Validator class baseName = Tcl_NewStringObj("BaseExample", -1); Tcl_IncrRefCount(baseName); if ((baseObject = Tcl_GetObjectFromObj(interp, baseName)) == NULL) { Tcl_DecrRefCount(baseName); return TCL_ERROR; } Tcl_DecrRefCount(baseName); baseClass = Tcl_GetObjectAsClass(baseObject); set2Name = Tcl_NewStringObj("set2", -1); Tcl_IncrRefCount(set2Name); Tcl_NewMethod( interp, baseClass, set2Name, 1, &set2MethodType, (ClientData) NULL); Tcl_DecrRefCount(set2Name); if ( Tcl_PkgProvide(interp, "set", "0.1") != TCL_OK ) { return TCL_ERROR; } return TCL_OK; } This is tested using the following script: ::oo::class create BaseExample { constructor {} { variable X 0 } method SetX {pX} { variable X $pX } method getX {} { variable X return $X } } load ./set/libset.so set base [BaseExample new] puts "getX: [$base getX]" $base set2 puts "getX: [$base getX]" The code above has just been created to test and explain the problem I am having. Which is essentially that depending on how I try to call the unexported method, I either get: 'ERROR: unknown method "SetX"...' or 'ERROR: invalid command name "my"'. Any help on this would be greatly appreciated. Lawrence Woodman
From: Donal K. Fellows on 25 Jul 2010 11:33 On Jul 24, 8:12 am, Lawrence Woodman <nos...(a)example.com> wrote: > The code above has just been created to test and explain the problem I am > having. Which is essentially that depending on how I try to call the > unexported method, I either get: 'ERROR: unknown method "SetX"...' or > 'ERROR: invalid command name "my"'. An unexported method is, well, not exported. It's not part of the public interface of an object. If you wish to call it, you need to do so via [my], but that's not a command that's available trivially outside the body of a method. Why? Because it's not in the global namespace (which knows nothing about objects). So where is it? As you should be aware, every object has its own namespace. It's where the object stores all its variables. You can (assuming you've got a recent enough build of TclOO) find out the namespace's name from the Tcl level with [info object namespace] and from the C level with Tcl_GetObjectNamespace(). Aside from those variables, there's also one command by default: [my]. Every object has its own. Getting the name of a namespace is trivial. Calling any method through that route is now trivial... (BTW, the namespace name is also a stable reference to the object as namespaces cannot be renamed or aliased.) Donal.
From: Lawrence Woodman on 27 Jul 2010 05:54 On Sun, 25 Jul 2010 08:33:00 -0700, Donal K. Fellows wrote: > On Jul 24, 8:12 am, Lawrence Woodman <nos...(a)example.com> wrote: >> The code above has just been created to test and explain the problem I >> am having. Which is essentially that depending on how I try to call >> the unexported method, I either get: 'ERROR: unknown method "SetX"...' >> or 'ERROR: invalid command name "my"'. > > An unexported method is, well, not exported. It's not part of the public > interface of an object. If you wish to call it, you need to do so via > [my], but that's not a command that's available trivially outside the > body of a method. Why? Because it's not in the global namespace (which > knows nothing about objects). So where is it? > > As you should be aware, every object has its own namespace. It's where > the object stores all its variables. You can (assuming you've got a > recent enough build of TclOO) find out the namespace's name from the Tcl > level with [info object namespace] and from the C level with > Tcl_GetObjectNamespace(). Aside from those variables, there's also one > command by default: [my]. Every object has its own. Getting the name of > a namespace is trivial. Calling any method through that route is now > trivial... Donal, Thanks for your help. I assumed that Tcl_EvalObjEx() would be running in the same namespace as the method within which it had been called and was surprised to find out that it runs in the global namespace. I can now access the unexported methods without any problem. bfn Lawrence Woodman
From: Donal K. Fellows on 27 Jul 2010 18:55 On 27 July, 10:54, Lawrence Woodman <nos...(a)example.com> wrote: > Thanks for your help. I assumed that Tcl_EvalObjEx() would be running in > the same namespace as the method within which it had been called and was > surprised to find out that it runs in the global namespace. Eh? That conclusion sounds surprising to me, so I don't trust it. (That you might be in a different context to what you expect though, that's *very* possible.) Donal.
From: Lawrence Woodman on 28 Jul 2010 05:42 On Tue, 27 Jul 2010 15:55:00 -0700, Donal K. Fellows wrote: > On 27 July, 10:54, Lawrence Woodman <nos...(a)example.com> wrote: >> Thanks for your help. I assumed that Tcl_EvalObjEx() would be running >> in the same namespace as the method within which it had been called and >> was surprised to find out that it runs in the global namespace. > > Eh? That conclusion sounds surprising to me, so I don't trust it. (That > you might be in a different context to what you expect though, that's > *very* possible.) I'm guessing from your reply that I may have misunderstood this more than I realized. If I run Tcl_EvaLObjEx() with "namspace current" from a method that I have created, I get "::" returned, indicating that it is running in the global namespace. Should this not happen? bfn Lawrence
|
Next
|
Last
Pages: 1 2 Prev: Compressing a file (in windows) Next: Compressing a file (in windows) -sorry for the triple-post |