Search code examples
tclitcl

Itcl Appropriate return value of configbody


I want to return from a configbody but cannot do so explicitly without causing the variable not to be set.

I'd like help understanding the behavior I'm seeing. Please consider the following code (using Itcl 3.4):

package require Itcl
catch {itcl::delete class Model}
itcl::class Model {
    public variable filename "orig"
}

itcl::configbody Model::filename {
    if 1 {
        return ""
    } else {
    }
}

Model my_model
my_model configure -filename "newbie"
puts "I expect the result to be 'newbie:' [my_model cget -filename]"

When I return empty string, filename is not set to the new value. If I do not return but just allow the proc to fall through, filename does change. You can see this by changing the 1 to a 0 in the above code.

I suspect its related to the following statement:

When there is no return in a script, its value is the value of the last command evaluated in the script.

If someone would explain this behavior and how I should be returning, I'd appreciate the help.


Solution

  • Tcl handles return by throwing an exception (of type TCL_RETURN). Normally, the outer part of a procedure or method handler intercepts that exception and converts it into a normal result of the procedure/method, but you can intercept things with catch and see beneath the covers a bit.

    However, configbody does not use that mechanism. It just runs the script in some context (not sure what!) and that context treats TCL_RETURN as an indication to fail the update.

    Workaround:

    itcl::configbody Model::filename {
        catch {
            if 1 {
                return ""
            } else {
            }
        } msg; set msg
        # Yes, that's the single argument form of [set], which READS the variable...
    }
    

    Or call a real method in the configbody, passing in any information that's required.