Я пытаюсь реализовать классы, реализующие интерфейсы и сериализацию полученных объектов, и обнаружил сообщение об ошибке objdefine (с использованием Tcl 8.5 + TclOO 1.0.x).
Думаю, у меня есть некоторое представление о причине, но я не уверен, что есть обходной путь, кроме перекомпиляции TclOO и исправления.
Я сделал минимальный пример:
package require Tcl 8.5
package require TclOO
# https://wiki.tcl-lang.org/page/Serializing+TclOO+objects#mkup_code_2
::oo::class create ::oo::serializable {}
# https://wiki.tcl-lang.org/page/Extending+TclOO+with+metaclasses#mkup_code_10
::oo::class create ::oo::interface {
superclass ::oo::class
mixin ::oo::InterfaceMixin
self method create {name args} {
set instance [next $name {*}$args]
# this line appears to cause the problem
::oo::define $instance superclass -append [self]
return $instance
}
}
namespace eval ::csh::oo {}
# creates instances with createWithNamespace
::oo::class create ::csh::oo::nclass {
superclass ::oo::class
mixin ::oo::InterfaceMixin
...
}
::oo::interface create ::SpecialMethods {
}
::csh::oo::nclass create ::ABC {
superclass ::oo::serializable ::SpecialMethods
}
set abc [::oo::serializable new]
# error in Tcl 8.5 + TclOO 1.0.x
# ok in Tcl 8.6.12
::oo::objdefine $abc class ::ABC
# error: "may not change a non-class object into a class object"
можно ли изменить класс ::oo::interface
, чтобы ::oo::objdefine
работал?
запуск под GDB показывает для TCLOO 1.0.2:
tclOODefineCmds.c:1188
oPtr->classPtr
— это NULL
, когда делается звонок objdefine
.
Похоже, это может быть ошибка в условиях безопасности для мутаций. Что прискорбно; отдельный TclOO заархивирован, поскольку он не будет отслеживать даже все исправления ошибок в версии TclOO для Tcl 8.6 (не говоря уже о новых функциях в более поздних версиях Tcl). Поскольку код работает с версией 8.6.12, предлагаемое исправление заключается в том, чтобы не использовать серию версий Tcl, срок эксплуатации которых истек; В версии 8.6 исправлены ошибки, а в версии 8.5 (и тесно связанном коде, таком как независимый TclOO) — нет.
Это был не тот ответ, который вы хотели, но это ответ, который вы получите. (Я не заинтересован в том, чтобы выяснить, когда ошибка была исправлена, не говоря уже о переносе исправления в то, что я никогда не выпущу.)
Я так и сделал вывод! Сегодня утром я экспериментировал с портированием трех коммитов из репозитория tcl, которые я определил как необходимые (ad022e6d3b0857ae1266961eb07a1c3459d6e1cf, e0064189465e2ea63ca9e2dd531928a14c968f52, 20213492498c729f4a953da 797793ba5471607d8, это привело к четвертому 90f38b1023a10f8a5518bdcd04cb4e377d709fe9!). Я могу решить сделать это, поскольку используемая версия TCL находится вне моего контроля... Первые два коммита легко портировать, третий - нет, четвертый может потребоваться только третьему, и все начинает выглядеть так: небольшой ад зависимости ;)
В общем, TclOO-как-расширение для Tcl 8.5 не содержит исправлений ошибок, главным образом потому, что я не могу утруждать себя резервным портированием; вместо этого используйте Tcl 8.6.