Внутри метода variable
- это просто известная вам обычная команда Tcl, а текущее пространство имен - это пространство имен экземпляра (которое есть у каждого объекта).
На уровне объявления variable
отличается. (Это совершенно другая команда.) Он настраивает переменный преобразователь для настроенного объекта (в данном примере класса Foo
), чтобы иметь имя переменной, которое, если ононе найден в локальной области (метода), будет найден в пространстве имен экземпляра;решатель фактически сделает это для списка имен переменных.Переменный преобразователь применяется ко всем методам, определенным этим классом - но не его подклассы или суперклассы (я пробовал другой способ; это отстой) - или экземпляр, если в контексте, определяющем экземпляр.1013 * В ваших примерах это означает, что:
- В первом случае и конструктор, и метод
twoBar
имеют bar
на самом деле ссылаются на переменную ::oo::Obj12::bar
(при обычных предположенияхоб именах пространств имен в реализации TclOO). - Во втором случае, когда
bar
относится к ::oo::Obj12::bar
в конструкторе (технически, только после вызова variable
), в twoBar
Метод bar
всегда относится только к локальной переменной, которую вы никогда не устанавливали.Это означает, что чтение из bar
завершается неудачно (из-за стандартной семантики чтения переменных).
Вызов my variable bar
имеет тот же эффект, что и variable bar
внутри этого метода.Разница заключается в том, что один из них может быть вызван как вызываемый извне объекта, а другой может связывать и устанавливать несколько переменных одновременно;оба они используются редко, но принципиально различаются.
На уровне байт-кода единственное заметное различие между двумя методами twoBar
заключается в следующем (в первой версии):
% tcl::unsupported::disassemble method Foo twoBar
ByteCode 0x0x7ff5a2845810, refCt 1, epoch 17, interp 0x0x7ff5a2808010 (epoch 17)
Source "\n return [expr {2 * $bar}]\n ..."
Cmds 2, src 38, inst 6, litObjs 1, aux 0, stkDepth 2, code/src 0.00
Proc 0x0x7ff5a2835f10, refCt 1, args 0, compiled locals 1
slot 0, scalar, resolved, "bar"
Commands 2:
1: pc 0-5, src 9-32 2: pc 0-4, src 17-31
Command 1: "return [expr {2 * $bar}]..."
Command 2: "expr {2 * $bar}..."
(0) push1 0 # "2"
(2) loadScalar1 %v0 # var "bar"
(4) mult
(5) done
Переменная bar
(в слоте 0) помечена как «resolved
» (что делает махинации под крышками).В остальном они полностью идентичны.Конструкторы имеют серьезные различия в последовательности команд, поэтому их сложно сравнивать, но мы все еще можем видеть, что там происходит.
% tcl::unsupported::disassemble constructor Foo
ByteCode 0x0x7ff5a2845c10, refCt 1, epoch 17, interp 0x0x7ff5a2808010 (epoch 17)
Source "\n set bar $input\n ..."
Cmds 1, src 28, inst 5, litObjs 0, aux 0, stkDepth 1, code/src 0.00
Proc 0x0x7ff5a2835d90, refCt 1, args 1, compiled locals 2
slot 0, scalar, arg, "input"
slot 1, scalar, resolved, "bar"
Commands 1:
1: pc 0-3, src 9-22
Command 1: "set bar $input..."
(0) loadScalar1 %v0 # var "input"
(2) storeScalar1 %v1 # var "bar"
(4) done
Опять же, bar
- это resolved
…