Hello Gustaf,
What would be a good way to define a constant/immutable property/variable in Next?
Thanks
On 29.11.11 18:39, Victor Mayevski wrote:
Hello Gustaf,
What would be a good way to define a constant/immutable property/variable in Next?
Dear Victor,
Below is a short study to set all current instance variables of an object immutable based on variable traces. To implement the immutable functionality on the property level is more involved, since one has to handle default/non-default cases, and one has to register the traces at the right time for every object creation.
Maybe this simple study helps already
-gustaf neumann
============================================================== package req nx package req nx::test package req nx::trait
::nx::Class create C { :require trait nx::traits::callback
# # Method called via trace to reject write operations # :public method reject {name sub op} { error "$op operation on variable $name of object [self] is not allowed" }
# # Method to make all currently defined variables of an object # immutable # :public method immutable {} { foreach v [:info vars] { ::trace add variable :$v write [:callback reject] } } :create c1 { set :x 1 set :y 2 } }
c1 immutable ? {c1 eval {set :x}} 1 ? {c1 eval {set :y}} 2 ? {c1 eval {set :x 1}} {can't set ":x": write operation on variable :x of object ::c1 is not allowed} ? {c1 eval {set :z 3}} 3
Victor,
Maybe this simple study helps already
I just recovered a variation of Gustaf's study which I had used in previous projects of mine. The study below differs with respect to enforcing the "immutability" (prohibiting vs. preserving state) and adds handling of variable unsets. It slightly optimizes over the method dispatch for write traces (using ::nsf::set::var), however, it also comes at extra costs (doubled variable writes).
It can be easily extended for supporting basic introspection, kinds of "/obj/ info immutables" or the like ...
//stefan
package req nx package req nx::test package req nx::trait
::nx::Class create C { :require trait nx::traits::callback # # Make selected (by default, all currently defined) variables of an # object immutable # :public forward immutable %self traces add
# # Make selected (by default, all currently defined) variables of an # object mutable (again ...) # :public forward mutable %self traces remove
:protected method traces {op args} { foreach varName [expr {[llength $args] ? $args : [:info vars]}] { set writeCmdPrefix [list ::nsf::var::set [self] $varName [set :$varName]] set unsetCmdPrefix "$writeCmdPrefix; [:callback immutable $varName]" ::trace $op variable :$varName write "$writeCmdPrefix;#" ::trace $op variable :$varName unset "$unsetCmdPrefix;#" } } :create c1 { set :x 1 set :y 2 } }
# # c1 is mutable ... # ? {c1 eval {set :x}} 1 ? {c1 eval {set :y}} 2 ? {c1 eval {set :x 5}} 5 ? {c1 eval {set :x}} 5 ? {c1 eval {unset :y; set :y}} {can't read ":y": no such variable} ? {c1 eval {set :y 4}} 4 ? {c1 eval {set :z 3}} 3
# # c1 becomes immutable ... # c1 immutable
? {c1 eval {set :x}} 5 ? {c1 eval {set :y}} 4 ? {c1 eval {set :x 1}} 5 ? {c1 eval {set :x}} 5 ? {c1 eval {unset :y; set :y}} 4 # # Subsequent unsets are handled ... # ? {c1 eval {unset :y; set :y}} 4 ? {c1 eval {set :y 2}} 4 ? {c1 eval {set :z 3}} 3
# # c1 becomes mutable (again ...) #
c1 mutable
? {c1 eval {set :x}} 5 ? {c1 eval {set :y}} 4 ? {c1 eval {set :x 1}} 1 ? {c1 eval {set :x}} 1 ? {c1 eval {unset :y; set :y}} {can't read ":y": no such variable} ? {c1 eval {set :y 2}} 2 ? {c1 eval {set :z 3}} 3
Thank you Gustaf and Sefan,
Would it be possible to add that functionality into NX core? For example, via:
Obj property {key:constant value} Obj variable key:constant value
I know I can code it myself but I think programmers would prefer for it to be a built-in function.
On Mon, Jan 2, 2012 at 8:28 AM, Stefan Sobernig stefan.sobernig@wu.ac.at wrote: Victor,
Maybe this simple study helps already
I just recovered a variation of Gustaf's study which I had used in previous projects of mine. The study below differs with respect to enforcing the "immutability" (prohibiting vs. preserving state) and adds handling of variable unsets. It slightly optimizes over the method dispatch for write traces (using ::nsf::set::var), however, it also comes at extra costs (doubled variable writes).
It can be easily extended for supporting basic introspection, kinds of "/obj/ info immutables" or the like ...
//stefan
package req nx package req nx::test package req nx::trait
::nx::Class create C { :require trait nx::traits::callback # # Make selected (by default, all currently defined) variables of an # object immutable # :public forward immutable %self traces add
# # Make selected (by default, all currently defined) variables of an # object mutable (again ...) # :public forward mutable %self traces remove
:protected method traces {op args} { foreach varName [expr {[llength $args] ? $args : [:info vars]}] { set writeCmdPrefix [list ::nsf::var::set [self] $varName [set :$varName]] set unsetCmdPrefix "$writeCmdPrefix; [:callback immutable $varName]" ::trace $op variable :$varName write "$writeCmdPrefix;#" ::trace $op variable :$varName unset "$unsetCmdPrefix;#"
} } :create c1 { set :x 1 set :y 2 } }
# # c1 is mutable ...
# ? {c1 eval {set :x}} 1 ? {c1 eval {set :y}} 2 ? {c1 eval {set :x 5}} 5 ? {c1 eval {set :x}} 5 ? {c1 eval {unset :y; set :y}} {can't read ":y": no such variable} ? {c1 eval {set :y 4}} 4
? {c1 eval {set :z 3}} 3
# # c1 becomes immutable ...
# c1 immutable
? {c1 eval {set :x}} 5 ? {c1 eval {set :y}} 4 ? {c1 eval {set :x 1}} 5 ? {c1 eval {set :x}} 5 ? {c1 eval {unset :y; set :y}} 4 # # Subsequent unsets are handled ... # ? {c1 eval {unset :y; set :y}} 4 ? {c1 eval {set :y 2}} 4
? {c1 eval {set :z 3}} 3
# # c1 becomes mutable (again ...) #
c1 mutable
? {c1 eval {set :x}} 5 ? {c1 eval {set :y}} 4 ? {c1 eval {set :x 1}} 1
? {c1 eval {set :x}} 1 ? {c1 eval {unset :y; set :y}} {can't read ":y": no such variable} ? {c1 eval {set :y 2}} 2 ? {c1 eval {set :z 3}} 3 _______________________________________________ Xotcl mailing list Xotcl@alice.wu-wien.ac.at http://alice.wu-wien.ac.at/mailman/listinfo/xotcl
Dear Victor,
While it is easy to provide a slim implementation, which works nicely for particular cases, it is much more complicated to provide a general solution that works for all potential use cases.
Here are a few questions one has to address here: * Most likely, one would expect something like a write-once semantic via the property (declare the property, assign later some value to it, etc.) rather than a true "const" (at least when "property" rather than "variable" is used). * Since Tcl variables can be altered in many ways (output variables of cmds, resolver, ...) a true "const" must be most likely realized via traces (which have often tricky issues). * it is not clear, whether "const" should imply different write semantics, or as well different unset semantics. In the latter case, when a destroy happens, one should certainly unset the variables even when they are "const". Also, copy/move operations tend to be tricky. * when const is a slot property, we should address as well cases for slots with additional semantics (such as persistent, database-mapped slots, etc.)
Actually, my goal would even go further, by setting optionally objects/classes immutable, but this is opening some more cans of worms, but this opens as well some more potential optimizations.
With have the "immutable" theme block on our todo list, but not for the initial release.
-gustaf neumann
On 03.01.12 20:47, Victor Mayevski wrote:
Thank you Gustaf and Sefan,
Would it be possible to add that functionality into NX core? For example, via:
Obj property {key:constant value} Obj variable key:constant value
I know I can code it myself but I think programmers would prefer for it to be a built-in function.