Index: TODO =================================================================== diff -u -r6348e0e5067d578e11ea0ef0f5c0900f409ce527 -r76454eeb255e395a6a19345d558e0e96a9c47159 --- TODO (.../TODO) (revision 6348e0e5067d578e11ea0ef0f5c0900f409ce527) +++ TODO (.../TODO) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) @@ -3899,6 +3899,10 @@ - use fixed array size for method_definitions for MSC - Don't export symbols in the general case just because of MSC/C89 compliance +- Forward setting of object parameters to the slot object, when assign + method is user-defined on the slot object +- Cleanup and extend regression test + ======================================================================== TODO: @@ -3966,16 +3970,13 @@ o1 info children ?-type class? ?pattern? - - from parameters.test - # TODO: currently, we need two converters (or a converter on nx::Slot), since - # variable uses nsf::is and attribute uses the slot obj. method variable should - # be changed to use the slotobj as well. - - interface of "variable" and "attribute": * add switch -array for "variable"? (Just setting is trivial, handling setters and incremental setter is more work) - - call user-defined setter in object parameters? + - handle cases, where defaultmethods of the slot are altered. + The parameter handling in nx assumes on several places that + the defaultmethods are {get assign}. - Revise call-stack introspection/intercession, i.e., [current activelevel] vs. [current callinglevel] vs. uplevel()/upvar(): Index: generic/nsf.c =================================================================== diff -u -rbb4f5c65acffb4f0b8f399b3185cf1d670f9864b -r76454eeb255e395a6a19345d558e0e96a9c47159 --- generic/nsf.c (.../nsf.c) (revision bb4f5c65acffb4f0b8f399b3185cf1d670f9864b) +++ generic/nsf.c (.../nsf.c) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) @@ -21228,8 +21228,8 @@ : NULL; /* - * Push frame to allow for [self] and make instance variables of obj accessible as - * locals. + * Push frame to allow for [self] and make instance variables of obj + * accessible as locals. */ Nsf_PushFrameObj(interp, object, framePtr); @@ -21527,14 +21527,20 @@ */ if (i < paramDefs->nrParams || !pc.varArgs) { #if defined(CONFIGURE_ARGS_TRACE) - fprintf(stderr, "*** %s SET %s '%s'\n", - ObjectName(object), ObjStr(paramPtr->nameObj), ObjStr(newValue)); + fprintf(stderr, "*** %s SET %s '%s' // %p\n", + ObjectName(object), ObjStr(paramPtr->nameObj), ObjStr(newValue), paramPtr->slotObj); #endif /* * Actually set instance variable with the provided value or default - * value. + * value. In case, we have a slot provided, use it for initialization. */ - Tcl_ObjSetVar2(interp, paramPtr->nameObj, NULL, newValue, TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1); + + if (paramPtr->slotObj) { + result = NsfCallMethodWithArgs(interp, (Nsf_Object *)object, paramPtr->nameObj, + newValue, 1, NULL, NSF_CSC_IMMEDIATE); + } else { + Tcl_ObjSetVar2(interp, paramPtr->nameObj, NULL, newValue, TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1); + } } } Index: library/nx/nx.tcl =================================================================== diff -u -rf61ee3dfc17d8cf04a0dc9ada9cb0f939514a511 -r76454eeb255e395a6a19345d558e0e96a9c47159 --- library/nx/nx.tcl (.../nx.tcl) (revision f61ee3dfc17d8cf04a0dc9ada9cb0f939514a511) +++ library/nx/nx.tcl (.../nx.tcl) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) @@ -1556,6 +1556,11 @@ lappend options slot=[::nsf::self] } } + } elseif {[:info lookup method assign] ne "::nsf::classes::nx::VariableSlot::assign"} { + # 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] } if {[info exists :arg]} {lappend options arg=${:arg}} if {${:required}} { Index: tests/parameters.test =================================================================== diff -u -r59e100d383b22ea1407f5e5c40e303f2c6bb9027 -r76454eeb255e395a6a19345d558e0e96a9c47159 --- tests/parameters.test (.../parameters.test) (revision 59e100d383b22ea1407f5e5c40e303f2c6bb9027) +++ tests/parameters.test (.../parameters.test) (revision 76454eeb255e395a6a19345d558e0e96a9c47159) @@ -1898,23 +1898,13 @@ # # define an application specific converter # - # TODO: currently, we need two converters (or a converter on nx::Slot), since - # variable uses nsf::is and property uses the slot obj. method variable should - # be changed to use the slotobj as well. ::nx::ObjectParameterSlot method type=range {name value arg} { lassign [split $arg -] min max if {$value < $min || $value > $max} { error "value '$value' of parameter $name not between $min and $max" } return $value } - ::nx::ObjectParameterSlot method type=range {name value arg} { - lassign [split $arg -] min max - if {$value < $min || $value > $max} { - error "value '$value' of parameter $name not between $min and $max" - } - return $value - } # # Test usage of application specific converter in "variable" and @@ -2306,3 +2296,56 @@ xotcl::Object create o ? {o configure -order 15} "::o: unable to dispatch method 'order' during '::o.order'" } + +# +# Test forwarding to slot object, when assign is overloaded +# +nx::Test case forward-to-assign { + set ::slotcalls 0 + nx::Class create Foo { + :property bar { + :public method assign { object property value } { + incr ::slotcalls 1 + nsf::var::set $object $property $value + } + } + } + + # call without default, without object parameter value + set o [Foo new] + ? [list $o eval {info exists :bar}] 0 + ? {set ::slotcalls} 0 + ? [list $o bar] {can't read "bar": no such variable} + + # call without default, with object parameter value + + set o [Foo new -bar "test"] + ? [list $o eval {info exists :bar}] 1 + ? {set ::slotcalls} 1 + ? [list $o bar] "test" + + # test cases for default + set ::slotcalls 0 + nx::Class create Foo { + :property {baz 1} { + :public method assign { object property value } { + incr ::slotcalls 1 + nsf::var::set $object $property $value + } + } + } + + # call with default, without object parameter value + set o [Foo new] + ? [list $o eval {info exists :baz}] 1 + ? {set ::slotcalls} 1 + ? [list $o baz] "1" + + # call with default, with object parameter value + + set o [Foo new -baz "test"] + ? [list $o eval {info exists :baz}] 1 + ? {set ::slotcalls} 2 + ? [list $o baz] "test" + +}