【问题标题】:Itcl: inconsistency of $this variableItcl:$this 变量不一致
【发布时间】:2017-05-03 19:18:32
【问题描述】:

在将我的项目从 Tcl 8.5.9/Itcl 3.4 迁移到 Tcl 8.6.6/Itcl 4.0.5 时,我遇到了 $this 变量的不一致问题,具体取决于它的访问方式。这是最小化的测试用例:

puts "Tcl  version : $tcl_patchLevel"
puts "Itcl version : [package require Itcl]"

itcl::class Base {
    public {
        method base_process {script} {
            uplevel $m_main main_process [list $script]
        }
        method set_main {main} {
          set m_main $main
        }
    }
    protected {
        variable m_main
    }
}

itcl::class Main {
  inherit Base
    public {
        method main_process {script} {
            uplevel $script
        }
    }
}

itcl::class Worker {
  inherit Base
    public {
        method worker_process_direct {} {
            puts "Direct query: this = $this"
        }
        method worker_process_inderect {} {
            base_process {puts "Indirect query: this = $this"}
        }
        method worker_process_both {} {
            puts "Direct query: this = $this"
            base_process {puts "Indirect query: this = $this"}
        }
    }
}

Main main

Worker worker
worker set_main main

puts "\n==== worker_process_direct   ===="
worker worker_process_direct

puts "\n==== worker_process_indirect ===="
worker worker_process_inderect

puts "\n==== worker_process_both     ===="
worker worker_process_both

worker_process_directworker_process_both 函数始终提供正确的结果。但worker_process_inderect 仅适用于旧版本的 Tcl/Itcl。对于 Tcl 8.6.6/Itcl 4.0.5,$this 变量奇怪地更改为 Main 类的实例,而不是 Worker

这是上面两个版本的 Tcl/Itcl 脚本的输出。

Tcl  version : 8.5.9
Itcl version : 3.4

==== worker_process_direct   ====
Direct query: this = ::worker

==== worker_process_indirect ====
Indirect query: this = ::worker          <<<<<<<<<<<< CORRECT

==== worker_process_both     ====
Direct query: this = ::worker
Indirect query: this = ::worker
Tcl  version : 8.6.6
Itcl version : 4.0.5

==== worker_process_direct   ====
Direct query: this = ::worker

==== worker_process_indirect ====
Indirect query: this = ::main            <<<<<<<<<< INCORRECT

==== worker_process_both     ====
Direct query: this = ::worker
Indirect query: this = ::worker

我是否遗漏了什么,并且 Tcl/Itcl 发生了我没有注意到的重大变化?

【问题讨论】:

  • 嗯,您正在使用不同的主要版本的 itcl……我可以用 Tcl 8.6.3 和 Itcl 4.0.2 重现。
  • tl;dr:看起来你发现了一个 itcl 错误。祝你好运。

标签: tcl itcl


【解决方案1】:

现在这非常很好奇!我扩充了你的脚本来定义Main,如下所示:

itcl::class Main {
    inherit Base
    public {
        method main_process {script} {
            uplevel $script
            # Print what is actually going on!
            puts >>[tcl::unsupported::disassemble script $script]<<
        }
    }
}

在 8.5/3.4 中,我得到以下输出:

Tcl  version : 8.5.9
Itcl version : 3.4

==== worker_process_direct   ====
Direct query: this = ::worker

==== worker_process_indirect ====
Indirect query: this = ::worker
>>ByteCode 0x0x7fedea044c10, refCt 1, epoch 3, interp 0x0x7fedea033010 (epoch 3)
  Source "puts \"Indirect query: this = $this\""
  Cmds 1, src 35, inst 12, litObjs 3, aux 0, stkDepth 3, code/src 0.00
  Commands 1:
      1: pc 0-10, src 0-34
  Command 1: "puts \"Indirect query: this = $this\""
    (0) push1 0     # "puts"
    (2) push1 1     # "Indirect query: this = "
    (4) push1 2     # "this"
    (6) loadScalarStk 
    (7) concat1 2 
    (9) invokeStk1 2 
    (11) done 
<<

==== worker_process_both     ====
Direct query: this = ::worker
Indirect query: this = ::worker
>>ByteCode 0x0x7fedea044c10, refCt 1, epoch 3, interp 0x0x7fedea033010 (epoch 3)
  Source "puts \"Indirect query: this = $this\""
  Cmds 1, src 35, inst 12, litObjs 3, aux 0, stkDepth 3, code/src 0.00
  Commands 1:
      1: pc 0-10, src 0-34
  Command 1: "puts \"Indirect query: this = $this\""
    (0) push1 0     # "puts"
    (2) push1 1     # "Indirect query: this = "
    (4) push1 2     # "this"
    (6) loadScalarStk 
    (7) concat1 2 
    (9) invokeStk1 2 
    (11) done 
<<

使用 8.6/4.0 我得到了这个:

Tcl  version : 8.6.3
Itcl version : 4.0.2

==== worker_process_direct   ====
Direct query: this = ::worker

==== worker_process_indirect ====
Indirect query: this = ::main
>>ByteCode 0x0x1009af010, refCt 1, epoch 136, interp 0x0x100829a10 (epoch 136)
  Source "puts \"Indirect query: this = $this"...
  Cmds 1, src 35, inst 12, litObjs 3, aux 0, stkDepth 3, code/src 0.00
  Commands 1:
      1: pc 0-10, src 0-34
  Command 1: "puts \"Indirect query: this = $this"...
    (0) push1 0     # "puts"
    (2) push1 1     # "Indirect query: this = "
    (4) push1 2     # "this"
    (6) loadStk 
    (7) strcat 2 
    (9) invokeStk1 2 
    (11) done 
<<

==== worker_process_both     ====
Direct query: this = ::worker
Indirect query: this = ::worker
>>ByteCode 0x0x1009b0210, refCt 1, epoch 136, interp 0x0x100829a10 (epoch 136)
  Source "puts \"Indirect query: this = $this"...
  Cmds 1, src 35, inst 11, litObjs 2, aux 0, stkDepth 3, code/src 0.00
  Commands 1:
      1: pc 0-9, src 0-34
  Command 1: "puts \"Indirect query: this = $this"...
    (0) push1 0     # "puts"
    (2) push1 1     # "Indirect query: this = "
    (4) loadScalar1 %v0 
    (6) strcat 2 
    (8) invokeStk1 2 
    (10) done 
<<

因此,8.5 使用loadScalarStk 指令在两种(间接)情况下读取变量,而 8.6 使用loadStkloadScalar1 在两种情况下加载变量。这很奇怪;我不希望 loadScalar1 出现在脚本片段中(它需要一个局部变量表),但至少它正在获取预期值,而 loadStk 只是完全获取了错误的值。我也尝试在两个地方使用完全相同的值——脚本保存在一个共享变量中——但这会产生相同的输出;看起来在一个地方它正在评估但选择了错误的值(可能是变量解析器问题?),而在另一个地方它正在选择正确的值但出于错误的原因(因为 LVT 不应该用于脚本片段;这仅适用于完整的过程/方法)。不管怎样,这都是坏消息。

请在http://core.tcl-lang.org/tcl/tktnew 提交错误报告,因为这听起来像是多种错误行为的混合。

【讨论】:

  • 好的。然后提交了票 - core.tcl-lang.org/tcl/tktview/…
  • 跟进:loadStk/loadScalarStk 的区别无关紧要;这实际上只是一个重命名。
  • 我已经探索了更多,我认为这是 incrTcl 中的一个错误;将代码转换为纯基本 TclOO(itcl 4 建立在其上)使其按预期工作。
  • 而事实上,字节码的变化都完全符合预期。我相信这是一个 incr Tcl 错误,可能在扩展安装的变量解析器中。变量解析器看起来很难编写,但实际上比这要困难得多,这就是为什么我们从未在 Tcl 的公共文档支持 API 中真正公开它们。
猜你喜欢
  • 1970-01-01
  • 2020-06-10
  • 2012-03-08
  • 2019-11-20
  • 1970-01-01
  • 2011-07-26
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多