XOTcl objects can be instantiated while giving them initial values or setup — done before the constructor is called. Here's an example: ====== Class Car -parameter { {doors 4} } Car instproc init {marque} { puts "A $marque is a fine car" } Car new "Land Rover" Car new "Caterham" -doors 2 ====== All fine so far. The problem here is that if ''any'' of the arguments you pass to the constructor begin with a dash, they can cause havoc, as they are interpreted as method calls. Picture initialising a "Message" class with the message from the user as its one and only argument. This is very unsafe as, if the user's message begins with a dash, they can execute arbitrary code through your object. Bad. ====== Class Message Message instproc init {text} { # ... } # ... Message new $textFromUser ;# SECURITY HOLE! ====== Even the following is risky: ====== Car new "ExperimentalCar" -doors $doors ====== if, for example, you got the number of doors from a form. Now obviously in this particular case you should probably be checking the form well before you reach this point, but if your code has a bug, it allows the user to execute code. Quite an unexpected outcome for developers who maybe assumed, at most, an error about it being a bad value, at some point in the execution. You can get around it like this: ====== Message new [list -init $msg] ====== But you really ought to do this all the time. You have to be very, very careful. Unless you do it in this way you are heading for trouble. A Jpeg object with some binary data, or a text file passed to a constructor, or a protocol message — all could trip you up and cause a crash or worse! And all for something which was seemingly innocent. Tcl does have similar problems elsewhere. Commands such as [switch], [file] and others can result in misery, but they are quite well documented and not as commonplace as object instantiation. Having to use the above style for instantiation would be quite awkward if you had to do it virtually all the time. So here is a simple piece of script, using XOTcl's [mixins], which alleviates the problem. It allows safe instantiation, both when we want some preconfigured data, and when it is not necessary. It replaces the [new] method with a safe version, and offers an extra [new-with] method for pre-configuration of the object. It does not override the method [create], or the XOTcl [unknown] mechanism which allows you to create a named object without the [new] command. The latter, in particular, needs to be left as-is for class creation to work. ====== Class SafeInit @ SafeInit instproc new {args} { description { Replaces the normal [new] method with one which does not try to call methods for any values beginning with a dash. This can be used safely whenever there is no need to configure the object during instantiation. } } SafeInit instproc new {args} { return [next [concat [list -init] $args]] } @ SafeInit instproc new-with {args} { description { This is similar to [new] but the last argument is a script which is evaluated, before calling the constructor, within the context of the newly created object. You can use [self], [my] to call methods in the object and set things up. You can even directly set variables for the object without [self] or [my]. } } SafeInit instproc new-with {args} { set script [lindex $args end] set args [lrange $args 0 end-1] set name [my autoname ::xotcl::stk__#] return [my create $name [list -eval $script] [concat [list -init] $args]] } Class instmixin SafeInit ====== And here is an example showing how it is used: ====== Class Foo -parameter { {animal horse} } Foo instproc init {arg1 arg2} { puts "Constructor args: $arg1 $arg2" } Foo instproc hello {} { puts jou } # We do not override [create] or the auto-create from [unknown]. Ie. # class creation still works and other stuff :-) puts "Should say 'jou':" Foo ob 1 2 -hello puts "Animal: [ob animal]" # Instantiate with -dash args set ob [Foo new -hellou world] puts "Animal: [$ob animal]" # Instantiate with some presets puts "Show say 'jou':" set ob [Foo new-with 1 2 { my hello my animal cat }] puts "Animal: [$ob animal]" ====== As you can see "Foo ob 1 2 -hello" still works in the normal way, whereas [new] is now safe. [NEM] Are you sure the use of [concat] here is safe, given that it is a string operation? Wouldn't it be safer to use [list] and [{*}], e.g., [[list -init {*}$args]]? <>Category XOTcl Code