Index: TODO =================================================================== diff -u -r6c3fb3fec815892805a0497d7485b59d20a79c84 -rcc9032518f095207cd1832ae5b4202e0ace96c71 --- TODO (.../TODO) (revision 6c3fb3fec815892805a0497d7485b59d20a79c84) +++ TODO (.../TODO) (revision cc9032518f095207cd1832ae5b4202e0ace96c71) @@ -3053,12 +3053,16 @@ * added shortcut, when no slot object is needed * extended regression test +- nx::Attribute: changed method 'checkInstVar' to 'setCheckedInstVar' +- set only fresh variables via per-object method "variable" and "attribute" +- added flag -concomplain to per-object method "variable" and "attribute" +- extended regression test + + TODO: - provide warning, when method variable is a noop (e.g. no value provided and no accessor is wanted) - add test for class-level variable - - set value always in per-object variable method? probably yes. - - set value always in per-object attribute method? probably yes. - should we change interface for default value in attribute? probably not, same interface is used in methodparameters as well - we could rename "attribute" to "property" to make distinction between Index: library/nx/nx.tcl =================================================================== diff -u -r76571cce036b3d02efa2943454acfed2bc2f3351 -rcc9032518f095207cd1832ae5b4202e0ace96c71 --- library/nx/nx.tcl (.../nx.tcl) (revision 76571cce036b3d02efa2943454acfed2bc2f3351) +++ library/nx/nx.tcl (.../nx.tcl) (revision cc9032518f095207cd1832ae5b4202e0ace96c71) @@ -821,7 +821,6 @@ #puts stderr "*** [list $class create [::nx::slotObj -container $container $target $name] {*}$opts $initblock]" $class create [::nx::slotObj -container $container $target $name] {*}$opts $initblock - return [::nsf::object::dispatch $target ::nsf::methods::${scope}::info::method handle $name] } } @@ -1366,16 +1365,15 @@ valuechangedcmd } - ::nx::Attribute protected method checkInstVar {} { - if {${:per-object} && [info exists :default] } { - if {![::nsf::var::exists ${:domain} ${:name}]} { - set options [:getParameterOptions -withMultiplicity true] - if {[llength $options] > 0} { - ::nsf::is -complain [join $options ,] ${:default} - } - ::nsf::var::set ${:domain} ${:name} ${:default} - } + ::nx::Attribute public method setCheckedInstVar {-nocomplain:switch value} { + if {[::nsf::var::exists ${:domain} ${:name}] && !$nocomplain} { + error "Object ${:domain} has already an instance variable named '${:name}'" } + set options [:getParameterOptions -withMultiplicity true] + if {[llength $options] > 0} { + ::nsf::is -complain [join $options ,] $value + } + ::nsf::var::set ${:domain} ${:name} ${:default} } ::nx::Attribute protected method getParameterOptions { @@ -1456,16 +1454,17 @@ ::nx::Attribute public method reconfigure {} { #puts stderr "*** Should we reconfigure [self]???" unset -nocomplain :parameterSpec - :checkInstVar :makeAccessor + if {${:per-object} && [info exists :default]} { + :setCheckedInstVar -nocomplain=[info exists :nocomplain] ${:default} + } if {[::nsf::is class ${:domain}]} { ::nsf::invalidateobjectparameter ${:domain} } } ::nx::Attribute protected method init {} { next - :checkInstVar :makeAccessor :handleTraces } @@ -1616,6 +1615,7 @@ {-initblock ""} {-array:switch} {-accessor:boolean false} + {-nocomplain:switch} spec value:optional } { @@ -1628,13 +1628,17 @@ # - when initblock is non empty # - #puts stderr "Object variable $spec accessor $accessor" + #puts stderr "Object variable $spec accessor $accessor nocomplain $nocomplain" if {$initblock eq "" && !$accessor} { + # get name an list of parameter options lassign [::nx::MetaSlot parseParameterSpec -class $class $spec] \ name parameterOptions class opts if {[info exists value]} { + if {[info exists :$name] && !$nocomplain} { + error "Object [self] has already an instance variable named '$name'" + } if {$parameterOptions ne ""} { #puts stderr "::nsf::is $parameterOptions $value" ::nsf::is -complain $parameterOptions $value @@ -1645,18 +1649,23 @@ } return } - return [::nx::MetaSlot createFromParameterSpec [::nsf::self] \ - -per-object \ - -class $class \ - -initblock $initblock \ - -defaultopts [list -accessor $accessor -objectparameter false] \ - $spec \ - {*}[expr {[info exists value] ? [list $value] : ""}]] + set slot [::nx::MetaSlot createFromParameterSpec [self] \ + -per-object \ + -class $class \ + -initblock $initblock \ + -defaultopts [list -accessor $accessor -objectparameter false] \ + $spec \ + {*}[expr {[info exists value] ? [list $value] : ""}]] + + if {$nocomplain} {$slot eval {set :nocomplain 1}} + if {[info exists value]} {$slot setCheckedInstVar -nocomplain=$nocomplain $value} + return [::nsf::object::dispatch [self] ::nsf::methods::object::info::method handle [$slot name]] } - Object method attribute {spec {-class ""} {initblock ""}} { + Object method attribute {-nocomplain:switch spec {-class ""} {initblock ""}} { set r [[self] ::nsf::classes::nx::Object::variable \ -class $class \ + -nocomplain=$nocomplain \ -initblock $initblock \ -accessor true \ {*}$spec] @@ -1672,13 +1681,13 @@ default:optional } { #puts stderr "Class variable $spec" - set r [::nx::MetaSlot createFromParameterSpec [::nsf::self] \ - -class $class \ - -initblock $initblock \ - -defaultopts [list -accessor $accessor -objectparameter $objectparameter] \ - $spec \ - {*}[expr {[info exists default] ? [list $default] : ""}]] - return $r + set slot [::nx::MetaSlot createFromParameterSpec [::nsf::self] \ + -class $class \ + -initblock $initblock \ + -defaultopts [list -accessor $accessor -objectparameter $objectparameter] \ + $spec \ + {*}[expr {[info exists default] ? [list $default] : ""}]] + return [::nsf::object::dispatch [self] ::nsf::methods::class::info::method handle [$slot name]] } Class method attribute {spec {-class ""} {initblock ""}} { @@ -1700,7 +1709,6 @@ Class public method attributes arglist { set slotContainer [::nx::slotObj [::nsf::self]] foreach arg $arglist { - #::nx::MetaSlot createFromParameterSpec [::nsf::self] {*}$arg [self] ::nsf::classes::nx::Class::attribute $arg } ::nsf::var::set $slotContainer __parameter $arglist Index: tests/parameters.test =================================================================== diff -u -r6c3fb3fec815892805a0497d7485b59d20a79c84 -rcc9032518f095207cd1832ae5b4202e0ace96c71 --- tests/parameters.test (.../parameters.test) (revision 6c3fb3fec815892805a0497d7485b59d20a79c84) +++ tests/parameters.test (.../parameters.test) (revision cc9032518f095207cd1832ae5b4202e0ace96c71) @@ -1772,7 +1772,9 @@ # # re-assignment must be requested by a reconfigure call # + puts stderr ====1 [o info slots a] reconfigure + puts stderr ====2 ? {o eval {info exists :a}} 1 ? {o a} anothervalue } @@ -1822,8 +1824,8 @@ ? [list [self] eval {set :dummy 1}] "1" # set 2 variables, one via variable, one via attribute - ? [list [self] variable captain1 "James Kirk"] "" - ? [list [self] attribute [list captain2 "Jean Luc"]] "::enterprise::captain2" + ? [list [self] variable -nocomplain captain1 "James Kirk"] "" + ? [list [self] attribute -nocomplain [list captain2 "Jean Luc"]] "::enterprise::captain2" # in both cases, we expect instance variables ? [list [self] eval {set :captain1}] "James Kirk" @@ -1834,14 +1836,19 @@ ? [list [self] info lookup method captain2] "::enterprise::captain2" # set variable with a value checker - ? [list [self] variable x1:int 1] "" - ? [list [self] attribute [list x2:int 2]] "::enterprise::x2" + ? [list [self] variable -nocomplain x1:int 1] "" + ? [list [self] attribute -nocomplain [list x2:int 2]] "::enterprise::x2" # set variable with a value checker and an invalid value ? [list [self] variable y1:int a] {expected integer but got "a"} ? [list [self] attribute [list y2:int b]] {expected integer but got "b"} + # set variable again, without -nocomplain + ? [list [self] variable x1:int 1] {Object ::enterprise has already an instance variable named 'x1'} + ? [list [self] attribute [list x2:int 2]] {Object ::enterprise has already an instance variable named 'x2'} + # more tests, e.g. multiplicity and user-defined type + # incremental, } } \ No newline at end of file