Index: TODO =================================================================== diff -u -re6ceb1ea38f6aada0281a8e7d5e5fed37578eca6 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- TODO (.../TODO) (revision e6ceb1ea38f6aada0281a8e7d5e5fed37578eca6) +++ TODO (.../TODO) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -4227,17 +4227,33 @@ - invalidation of per-object parameter cache * on mixin changes and * on deletion/adding of per-object slots -- decactivate PER_OBJECT_PARAMETER_CACHING per default +- activate PER_OBJECT_PARAMETER_CACHING per default (flipping this parameter makes regression test more than 20 faster). - extended regression test +nsf.c +- added functiality for "cget" to call parameter-methods + (e.g. "... cget -class"). The method cget calls either + "/slot/ get ..." (when slot=... is provided in the parameter spec) + or it assumes that the method without argument returns the value +- added "::nsf::object::property /obj/ volatile" to query + whether a object is volatile or not +- "/obj/ cget -volatile" returns now the volatial state of the object +- factored out ParameterMethodDispatch() from OConfigureMethod() +- extended regression test ======================================================================== TODO: +- finalize handling of parameter methods in cget + * what to do with "cget -noinit" + * check all provided definitions + * handling of extra args in parameter methods? - regression tests for "/obj/ info lookup parameter ...." - handling of "required" in reconfigure (see parameter-object-mixin-dependency in parameters.test) - handling of recreate (see regression test for class-level properties) +- maybe "::nsf::object::property /obj/ volatile 0|1" to alter + volatile state. - check noconfig - "/obj/ configure" returns values which can't be read via "/obj/ cget" (but altered properly via "configure"). Index: generic/nsf.c =================================================================== diff -u -r60dc0dde60e22fb2b74bc6c3b15e0148af7d0fa5 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- generic/nsf.c (.../nsf.c) (revision 60dc0dde60e22fb2b74bc6c3b15e0148af7d0fa5) +++ generic/nsf.c (.../nsf.c) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -272,6 +272,14 @@ Tcl_Obj *guardObj, NsfCallStackContent *cscPtr); static void GuardDel(NsfCmdList *filterCL); +/* prototypes for forwarders */ +static void ForwardCmdDeleteProc(ClientData clientData); +static int ForwardProcessOptions(Tcl_Interp *interp, Tcl_Obj *nameObj, + Tcl_Obj *withDefault, int withEarlybinding, Tcl_Obj *withMethodprefix, + int withObjframe, Tcl_Obj *withOnerror, int withVerbose, + Tcl_Obj *target, int objc, Tcl_Obj * CONST objv[], + ForwardCmdClientData **tcdPtr); + /* properties of objects and classes */ static int IsBaseClass(NsfObject *cl); static int IsMetaClass(Tcl_Interp *interp, NsfClass *cl, int withMixins); @@ -12511,7 +12519,233 @@ return TCL_OK; } +/* + *---------------------------------------------------------------------- + * ParameterMethodDispatch -- + * + * Dispatch a method provided via parameter definition. The function checks + * the parameter definition, builds a argument list for the function call + * and invokes finally the configured cmd. This function is typically + * called from configure. + * + * Results: + * Tcl result code + * + * Side effects: + * The called function might sideeffect. + * + *---------------------------------------------------------------------- + */ static int +ParameterMethodDispatch(Tcl_Interp *interp, NsfObject *object, + Nsf_Param *paramPtr, Tcl_Obj *newValue, + CallFrame *uplevelVarFramePtr, + CONST char *initString, + Tcl_Obj *lastObj, Tcl_Obj **nextObjPtr, + int nrRemainingArgs) { + CallFrame *varFramePtr = Tcl_Interp_varFramePtr(interp); + NsfCallStackContent csc, *cscPtr = &csc; + CallFrame frame2, *framePtr2 = &frame2; + int result; + + /* + * The current call-frame of configure uses an obj-frame, such + * that setvar etc. are able to access variables like "a" as a + * local variable. However, in the init block, we do not like + * that behavior, since this should look like like a proc body. + * So we push yet another call-frame without providing the + * var-frame. + * + * The new frame will have the namespace of the caller to avoid + * the current obj-frame. Nsf_PushFrameCsc() will establish a + * CMETHOD frame. + */ + + Tcl_Interp_varFramePtr(interp) = varFramePtr->callerVarPtr; + cscPtr->flags = 0; + CscInit(cscPtr, object, object->cl /*cl*/, NULL /*cmd*/, + NSF_CSC_TYPE_PLAIN, 0, NsfGlobalStrings[NSF_CONFIGURE]); + Nsf_PushFrameCsc(interp, cscPtr, framePtr2); + + if (paramPtr->flags & NSF_ARG_INITCMD) { + /* cscPtr->cmdPtr = NSFindCommand(interp, "::eval"); */ + result = Tcl_EvalObjEx(interp, newValue, TCL_EVAL_DIRECT); + + } else if (paramPtr->flags & NSF_ARG_ALIAS) { + Tcl_Obj *methodObj, **ovPtr, *ov0; + CONST char *methodString; + int oc = 0; + + /* + * Restore the variable frame context as found at the original call + * site of configure(). Note that we do not have to revert this + * context change when leaving this configure() context because a + * surrounding [uplevel] will correct the call-stack context for us ... + */ + if (uplevelVarFramePtr) { + Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; + } + + /* + * Mark the intermittent CSC frame as INACTIVE, so that, e.g., + * call-stack traversals seeking active frames ignore it. + */ + cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; + + /* + * If "method=" was given, use it as method name + */ + methodObj = paramPtr->method ? paramPtr->method : paramPtr->nameObj; + methodString = ObjStr(methodObj); + + /*fprintf(stderr, "ALIAS %s, nrargs %d converter %p toNothing %d i %d oc %d, pcPtr->lastObjc %d\n", + paramPtr->name, paramPtr->nrArgs, paramPtr->converter, + paramPtr->converter == ConvertToNothing, + i, objc, pc.lastObjc);*/ + + if (paramPtr->converter == ConvertToNothing) { + /* + * We are using the varargs interface; pass all remaining args into + * the called method. + */ + if (newValue == paramPtr->defaultValue) { + /* + * Use the default. + */ + if (Tcl_ListObjGetElements(interp, paramPtr->defaultValue, &oc, &ovPtr) != TCL_OK) { + goto method_arg_done; + } + ov0 = *ovPtr; + ovPtr ++; + } else { + /* + * Use actual args. + */ + ov0 = lastObj; + ovPtr = nextObjPtr; + oc = nrRemainingArgs; + } + } else { + /* + * A simple alias, receives no (when noarg was specified) or a + * single argument (default). + */ + if (paramPtr->nrArgs == 1) { + oc = 1; + ov0 = newValue; + } else { + oc = 0; + ov0 = NULL; + } + ovPtr = NULL; + } + + /* + * Check, if we have an object parameter alias for the constructor. + * Since we require the object system for the current object to + * determine its object system configuration, we can't do this at + * parameter compile time. + */ + if (initString && *initString == *methodString && strcmp(initString, methodString) == 0) { + result = DispatchInitMethod(interp, object, oc, &ov0, 0); + } else { + + /*fprintf(stderr, "call alias %s with methodObj %s.%s oc %d, nrArgs %d '%s'\n", + paramPtr->name, ObjectName(object), ObjStr(methodObj), oc, + paramPtr->nrArgs, ObjStr(newValue));*/ + + Tcl_ResetResult(interp); + result = NsfCallMethodWithArgs(interp, (Nsf_Object*)object, methodObj, + ov0, oc, ovPtr, + NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); + } + } else /* must be NSF_ARG_FORWARD */ { + Tcl_Obj *forwardSpec = paramPtr->method ? paramPtr->method : NULL; /* different default? */ + Tcl_Obj **nobjv, *ov[3]; + int nobjc; + + assert(paramPtr->flags & NSF_ARG_FORWARD); + + /* + * The current implementation performs for every object + * parameter forward the full cycle of + * + * (a) splitting the spec, + * (b) convert it to a the client data structure, + * (c) invoke forward, + * (d) free client data structure + * + * In the future, it should convert to the client data + * structure just once and free it with the disposal of the + * parameter. This could be achieved + */ + if (forwardSpec == NULL) { + result = NsfPrintError(interp, "no forward spec available\n"); + goto method_arg_done; + } + result = Tcl_ListObjGetElements(interp, forwardSpec, &nobjc, &nobjv); + if (result != TCL_OK) { + goto method_arg_done; + } else { + Tcl_Obj *methodObj = paramPtr->nameObj; + ForwardCmdClientData *tcd = NULL; + int oc = 1; + + result = ForwardProcessOptions(interp, methodObj, + NULL /*withDefault*/, 0 /*withEarlybinding*/, + NULL /*withMethodprefix*/, 0 /*withObjframe*/, + NULL /*withOnerror*/, 0 /*withVerbose*/, + nobjv[0], nobjc-1, nobjv+1, &tcd); + if (result != TCL_OK) { + if (tcd) ForwardCmdDeleteProc(tcd); + goto method_arg_done; + } + + /*fprintf(stderr, "parameter %s forward spec <%s> After Options obj %s method %s\n", + ObjStr(paramPtr->nameObj), ObjStr(forwardSpec), + ObjectName(object), ObjStr(methodObj));*/ + + tcd->object = object; + ov[0] = methodObj; + if (paramPtr->nrArgs == 1) { + ov[oc] = newValue; + oc ++; + } + + /* + * Mark the intermittent CSC frame as INACTIVE, so that, e.g., + * call-stack traversals seeking active frames ignore it. + */ + cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; + + result = NsfForwardMethod(tcd, interp, oc, ov); + ForwardCmdDeleteProc(tcd); + } + } + method_arg_done: + /* + * Pop previously stacked frame for eval context and set the + * varFramePtr to the previous value. + */ + Nsf_PopFrameCsc(interp, framePtr2); + CscListRemove(interp, cscPtr, NULL); + CscFinish(interp, cscPtr, result, "converter object frame"); + Tcl_Interp_varFramePtr(interp) = varFramePtr; + + /* fprintf(stderr, "NsfOConfigureMethod_ attribute %s evaluated %s => (%d)\n", + ObjStr(paramPtr->nameObj), ObjStr(newValue), result);*/ + + if (likely(result == TCL_OK)) { + if (paramPtr->flags & NSF_ARG_INITCMD && RUNTIME_STATE(interp)->doKeepinitcmd) { + Tcl_ObjSetVar2(interp, paramPtr->nameObj, NULL, newValue, TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1); + } + } + + return result; +} + + +static int MakeProc(Tcl_Namespace *nsPtr, NsfAssertionStore *aStore, Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Obj *args, Tcl_Obj *body, Tcl_Obj *precondition, Tcl_Obj *postcondition, NsfObject *defObject, NsfObject *regObject, @@ -20026,7 +20260,7 @@ /* cmd "object::property" NsfObjectPropertyCmd { {-argName "objectName" -required 1 -type object} - {-argName "objectproperty" -type "initialized|class|rootmetaclass|rootclass|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch" -required 1} + {-argName "objectproperty" -type "initialized|class|rootmetaclass|rootclass|volatile|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch" -required 1} {-argName "value" -required 0 -type tclobj} } */ @@ -20039,6 +20273,14 @@ case ObjectpropertyInitializedIdx: flags = NSF_INIT_CALLED; break; case ObjectpropertyClassIdx: flags = NSF_IS_CLASS; break; case ObjectpropertyRootmetaclassIdx: flags = NSF_IS_ROOT_META_CLASS; break; + case ObjectpropertyVolatileIdx: + if (!valueObj) { + Tcl_SetObjResult(interp, + NsfGlobalObjs[object->opt && object->opt->volatileVarName ? NSF_ONE : NSF_ZERO]); + return TCL_OK; + }; + /* if value is provided, return the error below */ + break; case ObjectpropertyRootclassIdx: flags = NSF_IS_ROOT_CLASS; break; case ObjectpropertySlotcontainerIdx: flags = NSF_IS_SLOT_CONTAINER; allowSet = 1; break; case ObjectpropertyKeepcallerselfIdx: flags = NSF_KEEP_CALLER_SELF; allowSet = 1; break; @@ -22047,9 +22289,6 @@ * "initcmd", "alias" and "forward". */ if (paramPtr->flags & NSF_ARG_METHOD_INVOCATION) { - CallFrame *varFramePtr = Tcl_Interp_varFramePtr(interp); - NsfCallStackContent csc, *cscPtr = &csc; - CallFrame frame2, *framePtr2 = &frame2; int consuming = (*paramPtr->name == '-' || paramPtr->nrArgs > 0); if (consuming && newValue == NsfGlobalObjs[NSF___UNKNOWN__]) { @@ -22061,207 +22300,18 @@ /*fprintf(stderr, "%s consuming nrargs %d no value\n", paramPtr->name, paramPtr->nrArgs);*/ continue; } - - /* - * The current call-frame of configure uses an obj-frame, such - * that setvar etc. are able to access variables like "a" as a - * local variable. However, in the init block, we do not like - * that behavior, since this should look like like a proc body. - * So we push yet another call-frame without providing the - * var-frame. - * - * The new frame will have the namespace of the caller to avoid - * the current obj-frame. Nsf_PushFrameCsc() will establish a - * CMETHOD frame. - */ - - Tcl_Interp_varFramePtr(interp) = varFramePtr->callerVarPtr; - cscPtr->flags = 0; - CscInit(cscPtr, object, object->cl /*cl*/, NULL /*cmd*/, - NSF_CSC_TYPE_PLAIN, 0, NsfGlobalStrings[NSF_CONFIGURE]); - Nsf_PushFrameCsc(interp, cscPtr, framePtr2); - - if (paramPtr->flags & NSF_ARG_INITCMD) { - /* cscPtr->cmdPtr = NSFindCommand(interp, "::eval"); */ - result = Tcl_EvalObjEx(interp, newValue, TCL_EVAL_DIRECT); - - } else if (paramPtr->flags & NSF_ARG_ALIAS) { - Tcl_Obj *methodObj, **ovPtr, *ov0; - CONST char *methodString; - int oc = 0; - - /* - * Restore the variable frame context as found at the original call - * site of configure(). Note that we do not have to revert this - * context change when leaving this configure() context because a - * surrounding [uplevel] will correct the call-stack context for us ... - */ - if (uplevelVarFramePtr) { - Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; - } - - /* - * Mark the intermittent CSC frame as INACTIVE, so that, e.g., - * call-stack traversals seeking active frames ignore it. - */ - cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; - - /* - * If "method=" was given, use it as method name - */ - methodObj = paramPtr->method ? paramPtr->method : paramPtr->nameObj; - methodString = ObjStr(methodObj); - - /*fprintf(stderr, "ALIAS %s, nrargs %d converter %p toNothing %d i %d oc %d, pcPtr->lastObjc %d\n", - paramPtr->name, paramPtr->nrArgs, paramPtr->converter, - paramPtr->converter == ConvertToNothing, - i, objc, pc.lastObjc);*/ - - if (paramPtr->converter == ConvertToNothing) { - /* - * We are using the varargs interface; pass all remaining args into - * the called method. - */ - if (newValue == paramPtr->defaultValue) { - /* - * Use the default. - */ - if (Tcl_ListObjGetElements(interp, paramPtr->defaultValue, &oc, &ovPtr) != TCL_OK) { - goto method_arg_done; - } - ov0 = *ovPtr; - ovPtr ++; - } else { - /* - * Use actual args. - */ - ov0 = objv[pc.lastObjc]; - ovPtr = (Tcl_Obj **)&objv[pc.lastObjc + 1]; - oc = objc - pc.lastObjc; - } - } else { - /* - * A simple alias, receives no (when noarg was specified) or a - * single argument (default). - */ - if (paramPtr->nrArgs == 1) { - oc = 1; - ov0 = newValue; - } else { - oc = 0; - ov0 = NULL; - } - ovPtr = NULL; - } - - /* - * Check, if we have an object parameter alias for the constructor. - * Since we require the object system for the current object to - * determine its object system configuration, we can't do this at - * parameter compile time. - */ - if (initString && *initString == *methodString && strcmp(initString, methodString) == 0) { - result = DispatchInitMethod(interp, object, oc, &ov0, 0); - } else { - - /*fprintf(stderr, "call alias %s with methodObj %s.%s oc %d, nrArgs %d '%s'\n", - paramPtr->name, ObjectName(object), ObjStr(methodObj), oc, - paramPtr->nrArgs, ObjStr(newValue));*/ - - Tcl_ResetResult(interp); - result = NsfCallMethodWithArgs(interp, (Nsf_Object*)object, methodObj, - ov0, oc, ovPtr, - NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); - } - } else /* must be NSF_ARG_FORWARD */ { - Tcl_Obj *forwardSpec = paramPtr->method ? paramPtr->method : NULL; /* different default? */ - Tcl_Obj **nobjv, *ov[3]; - int nobjc; - - assert(paramPtr->flags & NSF_ARG_FORWARD); - - /* - * The current implementation performs for every object - * parameter forward the full cycle of - * - * (a) splitting the spec, - * (b) convert it to a the client data structure, - * (c) invoke forward, - * (d) free client data structure - * - * In the future, it should convert to the client data - * structure just once and free it with the disposal of the - * parameter. This could be achieved - */ - if (forwardSpec == NULL) { - result = NsfPrintError(interp, "no forward spec available\n"); - goto method_arg_done; - } - result = Tcl_ListObjGetElements(interp, forwardSpec, &nobjc, &nobjv); - if (result != TCL_OK) { - goto method_arg_done; - } else { - Tcl_Obj *methodObj = paramPtr->nameObj; - ForwardCmdClientData *tcd = NULL; - int oc = 1; - - result = ForwardProcessOptions(interp, methodObj, - NULL /*withDefault*/, 0 /*withEarlybinding*/, - NULL /*withMethodprefix*/, 0 /*withObjframe*/, - NULL /*withOnerror*/, 0 /*withVerbose*/, - nobjv[0], nobjc-1, nobjv+1, &tcd); - if (result != TCL_OK) { - if (tcd) ForwardCmdDeleteProc(tcd); - goto method_arg_done; - } - - /*fprintf(stderr, "parameter %s forward spec <%s> After Options obj %s method %s\n", - ObjStr(paramPtr->nameObj), ObjStr(forwardSpec), - ObjectName(object), ObjStr(methodObj));*/ - - tcd->object = object; - ov[0] = methodObj; - if (paramPtr->nrArgs == 1) { - ov[oc] = newValue; - oc ++; - } - - /* - * Mark the intermittent CSC frame as INACTIVE, so that, e.g., - * call-stack traversals seeking active frames ignore it. - */ - cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; - - result = NsfForwardMethod(tcd, interp, oc, ov); - ForwardCmdDeleteProc(tcd); - } - } - method_arg_done: - /* - * Pop previously stacked frame for eval context and set the - * varFramePtr to the previous value. - */ - Nsf_PopFrameCsc(interp, framePtr2); - CscListRemove(interp, cscPtr, NULL); - CscFinish(interp, cscPtr, result, "converter object frame"); - Tcl_Interp_varFramePtr(interp) = varFramePtr; - - /* fprintf(stderr, "NsfOConfigureMethod_ attribute %s evaluated %s => (%d)\n", - ObjStr(paramPtr->nameObj), ObjStr(newValue), result);*/ - + // oooo; + result = ParameterMethodDispatch(interp, object, paramPtr, newValue, + uplevelVarFramePtr, initString, + objv[pc.lastObjc], (Tcl_Obj **)&objv[pc.lastObjc + 1], + objc - pc.lastObjc); if (result != TCL_OK) { - Nsf_PopFrameObj(interp, framePtr); - goto configure_exit; + Nsf_PopFrameObj(interp, framePtr); + goto configure_exit; } - - if (paramPtr->flags & NSF_ARG_INITCMD && RUNTIME_STATE(interp)->doKeepinitcmd) { - Tcl_ObjSetVar2(interp, paramPtr->nameObj, NULL, newValue, TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1); - } - - /* done with parameter method handling */ continue; } - + if (newValue == NsfGlobalObjs[NSF___UNKNOWN__]) { /* * Nothing to do, we have a value setter, but no value is specified and @@ -22378,39 +22428,39 @@ * The parameter is linked to a method via * "initcmd", "alias" and "forward". */ - if (paramPtr->flags & NSF_ARG_METHOD_INVOCATION) { + if (found && paramPtr->flags & NSF_ARG_METHOD_INVOCATION) { /* TODO: maybe we can allow this in the future */ /*fprintf(stderr, "method arg %s found, flags %.8x slot %p\n", nameString, paramPtr->flags, paramPtr->slotObj);*/ - found = 0; + // oooo + //found = 0; + //fprintf(stderr, "slot is %p\n", paramPtr->slotObj); + //found = (paramPtr->slotObj != NULL); + // oooo; } if (!found) { result = NsfPrintError(interp, "cannot lookup parameter value for %s", nameString); } else { /* fprintf(stderr, "arg %s found, flags %.8x\n", nameString, paramPtr->flags);*/ - + /* + * Check for slot invocation + */ if (paramPtr->slotObj) { NsfObject *slotObject = GetSlotObject(interp, paramPtr->slotObj); + Tcl_Obj *ov[1]; + /* - * Actually get instance variable or slot value - * In case, explicit slot invocation is needed, we call it. + * Get instance variable via slot. */ - - if (likely(slotObject != NULL)) { - Tcl_Obj *ov[1]; - - if (uplevelVarFramePtr) { - Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; - } - - ov[0] = paramPtr->nameObj; - result = NsfCallMethodWithArgs(interp, (Nsf_Object *)slotObject, NsfGlobalObjs[NSF_GET], - object->cmdName, 2, ov, NSF_CSC_IMMEDIATE); - } else { - fprintf(stderr, "strange, no slotobj\n"); + if (uplevelVarFramePtr) { + Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; } + ov[0] = paramPtr->nameObj; + result = NsfCallMethodWithArgs(interp, (Nsf_Object *)slotObject, NsfGlobalObjs[NSF_GET], + object->cmdName, 2, ov, NSF_CSC_IMMEDIATE); + if (result != TCL_OK) { /* * The error message was set either by GetSlotObject or by ...CallMethod... @@ -22419,13 +22469,41 @@ goto cget_exit; } } else { - int flags = (object->nsPtr) ? TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY : TCL_LEAVE_ERR_MSG; - Tcl_Obj *resutObj = Tcl_ObjGetVar2(interp, paramPtr->nameObj, NULL, flags); - if (resutObj) { + /* + * We do NOT have a slot + */ + if (found && paramPtr->flags & NSF_ARG_METHOD_INVOCATION) { + /* + * It is a parameter associated with a method. Invoke the method + * without an argument. + */ + Tcl_Obj *methodObj = paramPtr->method ? paramPtr->method : paramPtr->nameObj; + + if (uplevelVarFramePtr) { + Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; + } + + result = CallMethod(object, interp, methodObj, 2, 0, NSF_CSC_IMMEDIATE); + if (result != TCL_OK) { + /* + * The error message was set either by GetSlotObject or by ...CallMethod... + */ + Nsf_PopFrameObj(interp, framePtr); + goto cget_exit; + } + } else { + /* + * Must be a parameter associated with a variable + */ + int flags = (object->nsPtr) ? TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY : TCL_LEAVE_ERR_MSG; + Tcl_Obj *resutObj = Tcl_ObjGetVar2(interp, paramPtr->nameObj, NULL, flags); + + if (resutObj) { /* * The value exists */ - Tcl_SetObjResult(interp, resutObj); + Tcl_SetObjResult(interp, resutObj); + } } } } @@ -22844,7 +22922,6 @@ callFrameContext ctx = {0, NULL, NULL}; if (unlikely(RUNTIME_STATE(interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_OFF)) { - fprintf(stderr, "### can't make objects volatile during shutdown\n"); return NsfPrintError(interp, "can't make objects volatile during shutdown"); } Index: generic/nsfAPI.decls =================================================================== diff -u -r60dc0dde60e22fb2b74bc6c3b15e0148af7d0fa5 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision 60dc0dde60e22fb2b74bc6c3b15e0148af7d0fa5) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -170,7 +170,7 @@ } {-nxdoc 1} cmd "object::property" NsfObjectPropertyCmd { {-argName "objectName" -required 1 -type object} - {-argName "objectproperty" -type "initialized|class|rootmetaclass|rootclass|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch" -required 1} + {-argName "objectproperty" -type "initialized|class|rootmetaclass|rootclass|volatile|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch" -required 1} {-argName "value" -required 0 -type tclobj} } {-nxdoc 1} cmd "object::qualify" NsfObjectQualifyCmd { Index: generic/nsfAPI.h =================================================================== diff -u -r60dc0dde60e22fb2b74bc6c3b15e0148af7d0fa5 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- generic/nsfAPI.h (.../nsfAPI.h) (revision 60dc0dde60e22fb2b74bc6c3b15e0148af7d0fa5) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -149,12 +149,12 @@ return result; } -enum ObjectpropertyIdx {ObjectpropertyNULL, ObjectpropertyInitializedIdx, ObjectpropertyClassIdx, ObjectpropertyRootmetaclassIdx, ObjectpropertyRootclassIdx, ObjectpropertySlotcontainerIdx, ObjectpropertyHasperobjectslotsIdx, ObjectpropertyKeepcallerselfIdx, ObjectpropertyPerobjectdispatchIdx}; +enum ObjectpropertyIdx {ObjectpropertyNULL, ObjectpropertyInitializedIdx, ObjectpropertyClassIdx, ObjectpropertyRootmetaclassIdx, ObjectpropertyRootclassIdx, ObjectpropertyVolatileIdx, ObjectpropertySlotcontainerIdx, ObjectpropertyHasperobjectslotsIdx, ObjectpropertyKeepcallerselfIdx, ObjectpropertyPerobjectdispatchIdx}; static int ConvertToObjectproperty(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int index, result; - static CONST char *opts[] = {"initialized", "class", "rootmetaclass", "rootclass", "slotcontainer", "hasperobjectslots", "keepcallerself", "perobjectdispatch", NULL}; + static CONST char *opts[] = {"initialized", "class", "rootmetaclass", "rootclass", "volatile", "slotcontainer", "hasperobjectslots", "keepcallerself", "perobjectdispatch", NULL}; (void)pPtr; result = Tcl_GetIndexFromObj(interp, objPtr, opts, "objectproperty", 0, &index); *clientData = (ClientData) INT2PTR(index + 1); @@ -228,7 +228,7 @@ {ConvertToRelationtype, "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"}, {ConvertToSource, "all|application|baseclasses"}, {ConvertToConfigureoption, "debug|dtrace|filter|profile|softrecreate|objectsystems|keepinitcmd|checkresults|checkarguments"}, - {ConvertToObjectproperty, "initialized|class|rootmetaclass|rootclass|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch"}, + {ConvertToObjectproperty, "initialized|class|rootmetaclass|rootclass|volatile|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch"}, {ConvertToAssertionsubcmd, "check|object-invar|class-invar"}, {ConvertToParametersubcmd, "list|name|syntax"}, {NULL, NULL} Index: library/nx/nx.tcl =================================================================== diff -u -re6ceb1ea38f6aada0281a8e7d5e5fed37578eca6 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- library/nx/nx.tcl (.../nx.tcl) (revision e6ceb1ea38f6aada0281a8e7d5e5fed37578eca6) +++ library/nx/nx.tcl (.../nx.tcl) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -1277,6 +1277,13 @@ lappend options optional } if {$forObjectParameter} { + if {[:info lookup method assign] ni {"" "::nsf::classes::nx::RelationSlot::assign"}} { + # In case the "assign" method was provided on the slot, ask nsf to call it directly + lappend options slot=[::nsf::self] slotassign + } elseif {[:info lookup method get] ni {"" "::nsf::classes::nx::RelationSlot::get"}} { + # In case the "get" method was provided on the slot, ask nsf to call it directly + lappend options slot=[::nsf::self] + } if {[info exists :substdefault] && ${:substdefault}} { lappend options substdefault } @@ -1298,6 +1305,7 @@ } else { set prefix [expr {[info exists :positional] && ${:positional} ? "" : "-"}] set options [:getParameterOptions -withMultiplicity true -forObjectParameter true] + if {[info exists :initcmd]} { lappend options initcmd if {[info exists :default]} { @@ -1306,6 +1314,7 @@ } append initcmd ${:initcmd} set :parameterSpec [list [:namedParameterSpec $prefix ${:name} $options] $initcmd] + } elseif {[info exists :default]} { # deactivated for now: || [string first {$} ${:default}] > -1 if {[string match {*\[*\]*} ${:default}]} { @@ -1377,6 +1386,7 @@ # create methods for slot operations assign/get/add/delete # ::nsf::method::alias RelationSlot assign ::nsf::relation + ::nsf::method::alias RelationSlot get ::nsf::relation RelationSlot protected method delete_value {obj prop old value} { # @@ -1483,6 +1493,10 @@ ::nx::ObjectParameterSlot create ::nx::Object::slot::noinit \ -methodname ::nsf::methods::object::noinit -noarg true ::nx::ObjectParameterSlot create ::nx::Object::slot::volatile -noarg true + ::nsf::method::create ::nx::Object::slot::volatile assign {object var value} {$object volatile} + ::nsf::method::create ::nx::Object::slot::volatile get {object var} { + ::nsf::object::property $object volatile + } # # Define "class" as a ObjectParameterSlot defined as alias @@ -1502,16 +1516,6 @@ # # Define the initcmd as a positional ObjectParameterSlot # - # ::nx::ObjectParameterSlot create ::nx::Object::slot::__init \ - # -disposition alias \ - # -methodname "init" \ - # -noarg true \ - # -positional true \ - # -position 1 - - # - # Define the initcmd as a positional ObjectParameterSlot - # ::nx::ObjectParameterSlot create ::nx::Object::slot::__initcmd \ -disposition initcmd \ -noleadingdash true \ Index: library/xotcl/library/xotcl2.tcl =================================================================== diff -u -r6c5a4270b7d010efabb4cb89a890006b059a5f7e -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- library/xotcl/library/xotcl2.tcl (.../xotcl2.tcl) (revision 6c5a4270b7d010efabb4cb89a890006b059a5f7e) +++ library/xotcl/library/xotcl2.tcl (.../xotcl2.tcl) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -443,9 +443,9 @@ set cSlotContainer [::nx::slotObj ::xotcl::Class] set oSlotContainer [::nx::slotObj ::xotcl::Object] ::nx::RelationSlot create ${cSlotContainer}::superclass - ::nsf::method::alias ${cSlotContainer}::superclass assign ::nsf::relation + #::nsf::method::alias ${cSlotContainer}::superclass assign ::nsf::relation ::nx::RelationSlot create ${oSlotContainer}::class -elementtype class -multiplicity 1..1 - ::nsf::method::alias ${oSlotContainer}::class assign ::nsf::relation + #::nsf::method::alias ${oSlotContainer}::class assign ::nsf::relation ::nx::RelationSlot create ${oSlotContainer}::mixin -forwardername object-mixin \ -elementtype mixinreg -multiplicity 0..n ::nx::RelationSlot create ${oSlotContainer}::filter -forwardername object-filter \ Index: tests/cget.test =================================================================== diff -u -re884c2b0d63fa1b5a691e866ccff8d4094a2a8e4 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- tests/cget.test (.../cget.test) (revision e884c2b0d63fa1b5a691e866ccff8d4094a2a8e4) +++ tests/cget.test (.../cget.test) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -27,6 +27,10 @@ ? {p1 cget -friends} "" # + # a method property + ? {p1 cget -class} ::Person + + # # error handling: # - wrong # args # - wrong parameter @@ -35,7 +39,6 @@ ? {p1 cget} {wrong # of arguments: should be "cget name"} ? {p1 cget -foo} {cannot lookup parameter value for -foo} ? {p1 cget foo} {cannot lookup parameter value for foo} - ? {p1 cget -class} {cannot lookup parameter value for -class} ? {p1 cget -sex} {can't read "sex": no such variable} # Index: tests/info-method.test =================================================================== diff -u -r5d1617640ad71fd52b069f81cfcadbe4cbb6f2a2 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- tests/info-method.test (.../info-method.test) (revision 5d1617640ad71fd52b069f81cfcadbe4cbb6f2a2) +++ tests/info-method.test (.../info-method.test) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -696,13 +696,12 @@ :class property -accessor public a2 :method "sub foo" args {;} } -puts stderr ====1 + C new ? {C info parameter syntax} "?-a value? ?-b value? ?-volatile? ?-properties value? ?-noinit? ?-mixin mixinreg ...? ?-class class? ?-filter filterreg ...? ?__initcmd?" -puts stderr ====2 ? {C info parameter syntax a} "?-a value?" - ? {C info parameter definitions} "-a {-b 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + ? {C info parameter definitions} "-a {-b 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" ? {C info parameter list} "-a -b -volatile -properties -noinit -mixin -class -filter __initcmd" ? {C info parameter names} "a b volatile properties noinit mixin class filter __initcmd" Index: tests/parameters.test =================================================================== diff -u -re6ceb1ea38f6aada0281a8e7d5e5fed37578eca6 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- tests/parameters.test (.../parameters.test) (revision e6ceb1ea38f6aada0281a8e7d5e5fed37578eca6) +++ tests/parameters.test (.../parameters.test) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -274,7 +274,7 @@ C create c1 ? {C eval :__objectparameter} \ - "{-superclass:class,alias,method=::nsf::methods::class::superclass,1..n ::nx::Object} -object-mixin:mixinreg,alias,method=::nsf::classes::nx::Object::mixin -mixin:mixinreg,alias,0..n -object-filter:filterreg,alias,method=::nsf::classes::nx::Object::filter -filter:filterreg,alias,0..n -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -class:class,alias,method=::nsf::methods::object::class __initcmd:initcmd,optional,noleadingdash" + "{-superclass:class,alias,method=::nsf::methods::class::superclass,1..n ::nx::Object} -object-mixin:mixinreg,alias,method=::nsf::classes::nx::Object::mixin -mixin:mixinreg,alias,0..n -object-filter:filterreg,alias,method=::nsf::classes::nx::Object::filter -filter:filterreg,alias,0..n -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -class:class,alias,method=::nsf::methods::object::class __initcmd:initcmd,optional,noleadingdash" #### TOOD: remove or add #? {c1 eval :__objectparameter} \ @@ -306,7 +306,7 @@ "::D::slot::d ::C::slot::a ::C::slot::b ::C::slot::c" ? {d1 eval :__objectparameter} \ - "-d:required -a -b:boolean {-c 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + "-d:required -a -b:boolean {-c 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" } ####################################################### @@ -335,29 +335,29 @@ D mixin M ? {d1 eval :__objectparameter} \ - "-b -m1 -m2 -d:required -a {-c 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" \ + "-b -m1 -m2 -d:required -a {-c 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" \ "mixin added" M mixin M2 ? {d1 eval :__objectparameter} \ - "-b2 -b -m1 -m2 -d:required -a {-c 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" \ + "-b2 -b -m1 -m2 -d:required -a {-c 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" \ "transitive mixin added" D mixin "" #we should have again the old interface ? {d1 eval :__objectparameter} \ - "-d:required -a -b:boolean {-c 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + "-d:required -a -b:boolean {-c 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" C mixin M ? {d1 eval :__objectparameter} \ - "-b2 -b -m1 -m2 -d:required -a {-c 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" \ + "-b2 -b -m1 -m2 -d:required -a {-c 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" \ "mixin added" C mixin "" #we should have again the old interface ? {d1 eval :__objectparameter} \ - "-d:required -a -b:boolean {-c 1} -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + "-d:required -a -b:boolean {-c 1} -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" } ####################################################### @@ -1843,13 +1843,13 @@ nx::Class create M1 {:property b1:required} nx::Class create M2 {:property b2:required} - ? {c1 eval :__objectparameter} "-a1 -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + ? {c1 eval :__objectparameter} "-a1 -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" c1 mixin M1 ? {c1 info precedence} "::M1 ::C ::nx::Object" - ? {c1 eval :__objectparameter} "-b1:required -a1 -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + ? {c1 eval :__objectparameter} "-b1:required -a1 -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" # # Invalidate the object parameter and expect that the per-class @@ -1887,13 +1887,15 @@ # "-b2" # ? {c1 info mixin classes} ::M1 + ? {c1 cget -mixin} ::M1 ? {c1 info lookup parameter names b*} "b1" # # add one more mixin. # c1 mixin add ::M2 ? {c1 info mixin classes} {::M2 ::M1} + ? {c1 cget -mixin} {::M2 ::M1} ? {c1 info lookup parameter syntax b1} "-b1 value" ? {c1 info lookup parameter syntax b2} "-b2 value" ? {lsort [c1 info lookup parameter names b*]} "b1 b2" @@ -1948,7 +1950,7 @@ ? {C info slot objects -closure} "::C::slot::a1 ::nx::Object::slot::volatile ::nx::Object::slot::properties ::nx::Object::slot::noinit ::nx::Object::slot::mixin ::nx::Object::slot::__initcmd ::nx::Object::slot::class ::nx::Object::slot::filter" - ? {c1 eval :__objectparameter} "-a2 -b1:required -a1 -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + ? {c1 eval :__objectparameter} "-a2 -b1:required -a1 -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" # # invalidate object parameter and expect that the per-class mixin @@ -1962,7 +1964,7 @@ ? {C info slot objects -closure} "::C::slot::a1 ::nx::Object::slot::volatile ::nx::Object::slot::properties ::nx::Object::slot::noinit ::nx::Object::slot::mixin ::nx::Object::slot::__initcmd ::nx::Object::slot::class ::nx::Object::slot::filter" - ? {c1 eval :__objectparameter} "-a2 -b1:required -a1 -volatile:alias,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" + ? {c1 eval :__objectparameter} "-a2 -b1:required -a1 -volatile:alias,slot=::nx::Object::slot::volatile,slotassign,noarg -properties:alias,method=::nx::internal::addProperties -noinit:alias,method=::nsf::methods::object::noinit,noarg -mixin:mixinreg,alias,0..n -class:class,alias,method=::nsf::methods::object::class -filter:filterreg,alias,0..n __initcmd:initcmd,optional,noleadingdash" # should not require b1 ? {C create c2} ::c2 Index: tests/properties.test =================================================================== diff -u -re6ceb1ea38f6aada0281a8e7d5e5fed37578eca6 -r200af46a04ef0a09e4d27b6662a5a49b82c8ba52 --- tests/properties.test (.../properties.test) (revision e6ceb1ea38f6aada0281a8e7d5e5fed37578eca6) +++ tests/properties.test (.../properties.test) (revision 200af46a04ef0a09e4d27b6662a5a49b82c8ba52) @@ -747,7 +747,12 @@ ? {c1 configure -a a2} "" ? {C configure -class ::nx::Class} "" - ? {C cget -class} {cannot lookup parameter value for -class} + ? {C cget -class} ::nx::Class + ? {C cget -mixin} "" + ? {C cget -filter} "" + + # ? {C cget -noinit} 0 + ? {C cget -volatile} 0 # # check influence of class-level per-object properties @@ -761,6 +766,8 @@ ? {d1 configure -a a2} "" ? {D configure -class ::nx::Class} "" + ? {D cget -class} ::nx::Class + ? {D cget -cp} 101 ? {D configure -cp 102} "" ? {D cget -cp} 102 @@ -784,7 +791,6 @@ :variable -accessor protected vc vc1 :variable -accessor private vd vd1 :variable -accessor none ve ve1 - } # @@ -802,5 +808,8 @@ ? {o1 b} b1 ? {o1 b b2} "b2" + + ? {o1 configure -class ::nx::Object} "" + ? {o1 cget -class} ::nx::Object }