Index: TODO =================================================================== diff -u -r76454eeb255e395a6a19345d558e0e96a9c47159 -r8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3 --- TODO (.../TODO) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) +++ TODO (.../TODO) (revision 8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3) @@ -3903,6 +3903,13 @@ method is user-defined on the slot object - Cleanup and extend regression test +- additional object parameter option "invokesetter" managed by nx.tcl + This was necessary, since the previously implemented strategy + called the setter whenever slot= was provided. This has the problem, + that values could be converted twice (once by "configure", once + by the setter method", which lead for the converter to a double + refcounting on the value. + ======================================================================== TODO: Index: generic/nsf.c =================================================================== diff -u -r76454eeb255e395a6a19345d558e0e96a9c47159 -r8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3 --- generic/nsf.c (.../nsf.c) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) +++ generic/nsf.c (.../nsf.c) (revision 8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3) @@ -608,9 +608,8 @@ ParseContextRelease(ParseContext *pcPtr) { int status = pcPtr->status; - /*fprintf(stderr, "ParseContextRelease %p status %.6x %d elements, " - "called from %s\n", - pcPtr, status, pcPtr->objc, msg);*/ + /*fprintf(stderr, "ParseContextRelease %p status %.6x %d elements\n", + pcPtr, status, pcPtr->objc);*/ #if !defined(NDEBUG) { @@ -619,7 +618,7 @@ * context are at release time sometimes only partially initialized, the * following holds true for ensuring correct release of Tcl_Objs: * - * 1) if one of the objv-flags has NSF_PC_MUST_DECR set, + * 1) if one of the objv-flags has NSF_PC_MUST_DECR set, * then the status flag NSF_PC_STATUS_MUST_DECR has to * be set as well. * @@ -11414,7 +11413,7 @@ */ *outObjPtr = Tcl_GetObjResult(interp); INCR_REF_COUNT2("valueObj", *outObjPtr); - /*fprintf(stderr, "**** NSF_ARG_IS_CONVERTER\n");*/ + /*fprintf(stderr, "**** NSF_ARG_IS_CONVERTER %p\n", *outObjPtr);*/ } *clientData = (ClientData) *outObjPtr; @@ -11561,6 +11560,12 @@ } else if (strncmp(option, "forward", 7) == 0) { paramPtr->flags |= NSF_ARG_FORWARD; + } else if (strncmp(option, "invokesetter", 12) == 0) { + if (unlikely(paramPtr->slotObj == NULL)) { + return NsfPrintError(interp, "option 'invokesetter' must follow 'slot='"); + } + paramPtr->flags |= NSF_ARG_INVOKESETTER; + } else if ((dotdot = strnstr(option, "..", optionLength))) { /* check lower bound */ if (*option == '0') { @@ -21532,10 +21537,11 @@ #endif /* * Actually set instance variable with the provided value or default - * value. In case, we have a slot provided, use it for initialization. + * value. In case, explicit invocation of the setter is needed, we call the method, which + * is typically a forwarder to the slot object. */ - if (paramPtr->slotObj) { + if (paramPtr->flags & NSF_ARG_INVOKESETTER) { result = NsfCallMethodWithArgs(interp, (Nsf_Object *)object, paramPtr->nameObj, newValue, 1, NULL, NSF_CSC_IMMEDIATE); } else { Index: generic/nsfInt.h =================================================================== diff -u -rf80347fbea8fd50ae92c0bd7412cd4af80c78a54 -r8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3 --- generic/nsfInt.h (.../nsfInt.h) (revision f80347fbea8fd50ae92c0bd7412cd4af80c78a54) +++ generic/nsfInt.h (.../nsfInt.h) (revision 8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3) @@ -415,16 +415,17 @@ #define NSF_ARG_UNNAMED 0x080000 #define NSF_ARG_IS_RETURNVALUE 0x100000 #define NSF_ARG_NOLEADINGDASH 0x200000 +#define NSF_ARG_INVOKESETTER 0x400000 /* method invocations */ #define NSF_ARG_METHOD_INVOCATION (NSF_ARG_ALIAS|NSF_ARG_FORWARD|NSF_ARG_INITCMD) /* Disallowed parameter options */ -#define NSF_DISALLOWED_ARG_METHOD_PARAMETER (NSF_ARG_METHOD_INVOCATION|NSF_ARG_NOCONFIG) +#define NSF_DISALLOWED_ARG_METHOD_PARAMETER (NSF_ARG_METHOD_INVOCATION|NSF_ARG_NOCONFIG|NSF_ARG_INVOKESETTER) #define NSF_DISALLOWED_ARG_SETTER (NSF_ARG_SWITCH|NSF_ARG_SUBST_DEFAULT|NSF_DISALLOWED_ARG_METHOD_PARAMETER) /*#define NSF_DISALLOWED_ARG_OBJECT_PARAMETER (NSF_ARG_SWITCH)*/ #define NSF_DISALLOWED_ARG_OBJECT_PARAMETER 0 -#define NSF_DISALLOWED_ARG_VALUECHECK (NSF_ARG_SUBST_DEFAULT|NSF_ARG_METHOD_INVOCATION|NSF_ARG_SWITCH|NSF_ARG_CURRENTLY_UNKNOWN) +#define NSF_DISALLOWED_ARG_VALUECHECK (NSF_ARG_SUBST_DEFAULT|NSF_ARG_METHOD_INVOCATION|NSF_ARG_SWITCH|NSF_ARG_CURRENTLY_UNKNOWN|NSF_ARG_INVOKESETTER) /* flags for ParseContext */ Index: library/nx/nx.tcl =================================================================== diff -u -r76454eeb255e395a6a19345d558e0e96a9c47159 -r8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3 --- library/nx/nx.tcl (.../nx.tcl) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) +++ library/nx/nx.tcl (.../nx.tcl) (revision 8d45ee4442be4ba3222fa1abaeacd94a7aa02cc3) @@ -1560,7 +1560,7 @@ # In case the "assign method" has changed, forward variable # setting in configure (e.g. called during initialization of # object parameters) to the slot. - lappend options slot=[::nsf::self] + lappend options slot=[::nsf::self] invokesetter } if {[info exists :arg]} {lappend options arg=${:arg}} if {${:required}} {