Updated 2013-06-16 22:32:27 by RLE
 package require snit
    
    snit::type Dict {
        variable dictv
    
        method append {key args} {
        variable dictv
        return [eval ::dict append dictv [list $key] $args]
        }
    
        method exists {args} {
        variable dictv
        return [eval ::dict exists [list $dictv] $args]
        }
    
        method filter {ftype args} {
        variable dictv
        return [eval ::dict [list $dictv $ftype] $args]
        }
    
        method for {kv body} {
        variable dictv
        return [uplevel 1 ::dict for $kv $dictv $body]
        }
    
        method get {args} {
        variable dictv
        return [eval ::dict get [list $dictv] $args]
        }
    
        method incr {key {incr 1}} {
        variable dictv
        return [::dict incr dictv $key $incr]
        }
    
        method keys {{glob *}} {
        variable dictv
        return [eval ::dict keys [list $dictv] $glob]
        }
    
        method lappend {key args} {
        variable dictv
        return [eval ::dict lappend dictv [list $key] $args]
        }
    
        method remove {args} {
        variable dictv
        return [::set dictv [eval ::dict remove [list $dictv] $args]]
        }
    
        method replace {args} {
        variable dictv
        return [::set dictv [eval ::dict replace [list $dictv] $args]]
        }
    
        method set {args} {
        variable dictv
        return [::set dictv [eval ::dict set dictv $args]]
        }
    
        method size {} {
        variable dictv
        return [::dict size $dictv]
        }
    
        method unset {args} {
        variable dictv
        return [eval ::dict unset dictv $args]
        }
    
        method values {{glob *}} {
        variable dictv
        return [::dict values $dictv $glob]
        }
    
        method subdict {sub args} {
        variable dictv
        return [$self set [eval ::dict create $args]]
        }
    
        method serialize {} {
        variable dictv
        return $dictv
        }
    
        method restore {ser} {
        variable dictv
        eval dict set dictv $ser
        }
    
        constructor {args} {
        variable dictv
        ::set dictv [eval ::dict create $args]
        }
        destructor {}
    }

WHD: Two questions: why are you declaring dictv in every method? You don't need to. Second, why are you explicitly qualifying "::set"? You don't need to do that either.

CMcC: Answer 1) I think I should have to. It's been a while since I looked at snit's implementation, but how is the silent importation of instance variables achieved? Instance vars exist in namespaces, AFAIK they have to be qualified by namespace or explicitly declared. If Snit's doing the variable declarations itself, then there's an avoidable overhead.

I've checked the output. Snit declares all instance variables in all methods. I think this is needless overhead, detrimental to performance. I would rather it declare no variables but self, type, etc.

I note that the variable declaration for each instance variable is of the form: [::variable ${selfns}::options] ... is this strictly necessary? Aren't method invocations performed in the namespace context ${selfns} anyway? IOW, isn't [::variable options] equivalent to the snit-generated form?

Ah! No, from what I remember of looking at Snit, in fact the procs representing methods are defined in a per-class namespace, so my '::variable dict' in this context is actually incorrect! It's probably equivalent to referencing a class variable dict.

WHD: 1) It's true that there's an overhead to declaring the instance variables automatically in each method is an avoidable overhead. You avoid it by declaring them *only* in the methods that need them and not in the body of the type definition. But if you need it in each method, as you do here, it's a great convenience.

2) Snit redefines "variable"; the code you have here is correct. If you used "::variable", though, it would be wrong.

3) Yes, procs representing methods are defined in the type namespace and execute in that namespace. To have them execute in the instance namespace, I'd need to duplicate them for each instance. Faster, possibly, but you'd have lots more memory overhead per instance.

4) I still don't understand why you're qualifying "::set". The "set" method doesn't conflict with it.

See also: