Semantics of the oo::class command

The "oo::class create <name>" command will fail if the class <name> already exists. This is in contrast to the behaviour of the "proc" command, which overwrites an existing proc. The behavior of "oo::class" makes it awkward to use "package forget; package require" to refresh the contents of a package that defines a class. A package definition like:

namespace boo {
  oo::class create Boo {
    method boo {} { puts "ouch" }
  }
}

causes the following problem:

> package require boo
1.0
> package forget boo
> package require boo
can't create object "Boo": command already exists with that name

This can be avoided by splitting the definition of the class as in:

namespace boo {
  catch {oo::class create Boo}
  oo::define Boo {
    method boo {} { puts "ouch" }
  }
}

but it seems awkward to have to do this for every class that might be used in a package. What is the reasoning behind making it an error to re-"create" a class?

DKF: That's the way all objects are created (though with the “new” method it's not an issue anyway, since that never uses the same name as anything that exists). This matters for a class particularly because deleting a class also deletes the subclasses and instances of that class; I presume this is not something that you would like to have happen accidentally!

The real issue is that you're assuming that package forget unloads the package. It does not. It just forgets that the package is loaded; the package's contents are actually still present.

mpdanielson No, I understand what package forget does. The problem is that objects and classes act differently than any other named "thing" in Tcl. Variables, namespaces and procs can all be "recreated" (so to speak) without causing an error. In the case of procs there may be side effects, since the proc is really deleted/created rather than just having its value changed, but no error. A script that does not use oo can be sourced repeatedly. A script that does use oo can only be sourced once, unless the objects declared in the script are explicitly deleted before sourcing it again, or unless all of the create calls are caught, and oo::define and oo::objdefine are used explicitly. I agree that implicitly destroying all instances of a class when "create" is called for an existing object is not nice. If "create" just called oo:(obj)*define on an existing object, it would act more like the other commands. It's an easy issue to work around, but it seems like a departure from the way the other commands work.

ll Actually, a script that does not use oo can be sourced repeatedly only if it does not use Tk widgets either. You cannot re-create a widget without destroying it first. So objects do not act that differently than some other named "things"...

KPV But with widgets you can easily delete them before re-sourcing the script with

destroy {*}[winfo children .]

DKF: A workaround is a procedure like this one:

proc ::oo::create {className {definitionScript ""}} {
    try {
        set c [uplevel 1 [list ::oo::class create $className]]
    } on error {} {
        set c [uplevel 1 [list namespace which -command $c]]
    }
    uplevel 1 [list ::oo::define $c $definitionScript]
    return $c
}