0

I have a piece of code like this

oo::class create class_test {
    variable title_text
    variable result
    method title {t} {
        set title_text $t
        set result [format "%-6s %-6s" {*}$title_text]
    }
    method print {} {
        return $result
    }
}

set a "abcde"
set b "fghij"
class_test create foo
foo title {"$a" "$b"}
puts [foo print]

The real output is

$a     $b

While the expected output is

abcde  efghi

Could someone help to fix it?

Telmo Dias
  • 3,938
  • 2
  • 36
  • 48

3 Answers3

2

Change

foo title {"$a" "$b"}

to

foo title [list $a $b]

so that the variables get substituted by their values.

Shawn
  • 47,241
  • 3
  • 26
  • 60
1

You want to expand substitutions inside a {brace-quoted} string (logically) after the point that it is written in the script. This isn't usually recommended (not when you can construct arguments with list correctly), but you can do it.

method title {t} {
    set title_text [lmap value $t {
        uplevel 1 [list subst $value]
    }]
    set result [format "%-6s %-6s" {*}$title_text]
}

We do the transform on each word in the argument (lmap) and the transform is to apply subst to it, which must be done in the caller's context (uplevel 1). The use of list in there is so that we guarantee that we make a substitution-free script to run in the outer context, a very strongly recommended practice.


A feature of TclOO is that you don't need to take special precautions to use uplevel (or upvar) when using it, unlike some other older object systems for Tcl. That makes doing this sort of thing in a method no more tricky than doing it in a normal procedure. This is true even when inheritance is present.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
0

Could someone help to fix it?

I fail to see why you, first, pack variable references into a single value and, then, uplevel-substitute them. In addition, the number of value arguments to format seem fixed. Why not just use two separate formal parameters to your title method and use them directly?

method title {v1 v2} {
    set result [format "%-6s %-6s" $v1 $v2]
}

Then just call it like so:

foo title $a $b

Update

to generate the title in different length

then better use args like so?

method title {args} {
    set result [format [join [lrepeat [llength $args] "%-6s"] " "] {*}$args]
}

args is the natural way of having a method (proc) with variable arguments in Tcl.

mrcalvin
  • 3,291
  • 12
  • 18
  • what I want to do is to gengerate the title in different length, which means the number of arguments varies from different situations. – Cambridge Lv Mar 10 '20 at 03:51
  • Yeah, but if I exec directly `foo title {"$a" "$b"}`, I will come across the problem I'm asking. Shawn has shown the right way for me. Thank you anyway. – Cambridge Lv Mar 11 '20 at 12:41
  • You would execute the following for `args` to work: `foo title $a $b`. – mrcalvin Mar 11 '20 at 22:10