Itcl - the [incr Tcl] extension

Check-in Differences
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From 0d99fec557eac487 To 883c2c383fee7603

2025-02-20
13:23
amend to [987067386fa2edae]: adding coverage for constructor too (just to ensure we don't fall into the same trap by constructors) check-in: eb467f0c52 user: sebres tags: trunk, main
12:56
fixes [987067386fa2edae] don't use name of class in destructed hash, so ensure NS::C inheriting C would invoke destructor of base class (if both have destructors and clases have the same name) check-in: 883c2c383f user: sebres tags: trunk, main
12:54
add test illustrating bug [987067386fa2edae]: NS::C inheriting C would not invoke destructor of base class (if both have destructors and clases have the same name) check-in: df20905f77 user: sebres tags: trunk, main
2024-12-26
21:56
Fix compiler warning on 32-bit platforms (ITCL_Z_MODIFIER -> TCL_SIZE_MODIFIER everywhere) check-in: 0d99fec557 user: jan.nijtmans tags: trunk, main
21:40
Use TCL_SIZE_MODIFIER when appropriate check-in: 9319f83e74 user: jan.nijtmans tags: tip-626
2024-12-05
11:29
Fix broken pkgindex for nmake. Ticket [8b8406e3] check-in: 79b81cdcce user: apnadkarni tags: trunk, main, itcl-4-3-2

Changes to generic/itclObject.c.
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
        /*
         *  Create a "destructed" table to keep track of which destructors
         *  have been invoked.  This is used in ItclDestructBase to make
         *  sure that all base class destructors have been called,
         *  explicitly or implicitly.
         */
        contextIoPtr->destructed = (Tcl_HashTable*)ckalloc(sizeof(Tcl_HashTable));
        Tcl_InitObjHashTable(contextIoPtr->destructed);

        /*
         *  Destruct the object starting from the most-specific class.
         *  If all goes well, return the null string as the result.
         */
        callbackPtr = Itcl_GetCurrentCallbackPtr(interp);
        Tcl_NRAddCallback(interp, FinalizeDeleteObject, contextIoPtr,







|







1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
        /*
         *  Create a "destructed" table to keep track of which destructors
         *  have been invoked.  This is used in ItclDestructBase to make
         *  sure that all base class destructors have been called,
         *  explicitly or implicitly.
         */
        contextIoPtr->destructed = (Tcl_HashTable*)ckalloc(sizeof(Tcl_HashTable));
        Tcl_InitHashTable(contextIoPtr->destructed, TCL_ONE_WORD_KEYS);

        /*
         *  Destruct the object starting from the most-specific class.
         *  If all goes well, return the null string as the result.
         */
        callbackPtr = Itcl_GetCurrentCallbackPtr(interp);
        Tcl_NRAddCallback(interp, FinalizeDeleteObject, contextIoPtr,
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425



1426
1427
1428
1429
1430
1431
1432
    Itcl_ListElem *elem;
    ItclClass *iclsPtr;

    if (contextIoPtr->flags & ITCL_OBJECT_CLASS_DESTRUCTED) {
        return TCL_OK;
    }
    /*
     *  Look for a destructor in this class, and if found,
     *  invoke it.
     */
    if (Tcl_FindHashEntry(contextIoPtr->destructed,
            (char *)contextIclsPtr->namePtr) == NULL) {



        result = Itcl_InvokeMethodIfExists(interp, "destructor",
            contextIclsPtr, contextIoPtr, 0, NULL);
        if (result != TCL_OK) {
            return TCL_ERROR;
        }
    }








|
<


|
>
>
>







1414
1415
1416
1417
1418
1419
1420
1421

1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
    Itcl_ListElem *elem;
    ItclClass *iclsPtr;

    if (contextIoPtr->flags & ITCL_OBJECT_CLASS_DESTRUCTED) {
        return TCL_OK;
    }
    /*
     *  Ensure a destructor for this class is not already invoked yet.

     */
    if (Tcl_FindHashEntry(contextIoPtr->destructed,
            (char *)contextIclsPtr) == NULL) {
        /*
         *  Look for a destructor in this class, and if found, invoke it.
         */
        result = Itcl_InvokeMethodIfExists(interp, "destructor",
            contextIclsPtr, contextIoPtr, 0, NULL);
        if (result != TCL_OK) {
            return TCL_ERROR;
        }
    }

Changes to tests/delete.test.
81
82
83
84
85
86
87
88
89


90





































91
92
93
94
95
96
97
         [itcl::find classes test_delete*] \
         [namespace children :: test_delete*] \
         [namespace which -command test_delete_base] \
         [namespace which -command test_delete] \
         [itcl::find objects test_delete*]
} {{} {} {} {} {} {}}

test delete-2.4 {object destructors get invoked properly} {
    lsort $test_delete_watch


} {::test_delete0 ::test_delete1 ::test_delete2 ::test_delete_base0 ::test_delete_base1 ::test_delete_base2}






































# ----------------------------------------------------------------------
#  Deleting class namespaces
# ----------------------------------------------------------------------
test delete-3.1 {redefine classes with inheritance} {
    variable ::test_delete_watch ""
    itcl::class test_delete_base {







|

>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
         [itcl::find classes test_delete*] \
         [namespace children :: test_delete*] \
         [namespace which -command test_delete_base] \
         [namespace which -command test_delete] \
         [itcl::find objects test_delete*]
} {{} {} {} {} {} {}}

test delete-2.4 {object destructors get invoked properly} -body {
    lsort $test_delete_watch
} -cleanup {
    set test_delete_watch {}
} -result {::test_delete0 ::test_delete1 ::test_delete2 ::test_delete_base0 ::test_delete_base1 ::test_delete_base2}

test delete-2.5 {object destructors get invoked properly, bug [987067386fa2edae]} -setup {
    variable ::test_delete_watch {}
    itcl::class ::test_delete_base {
        destructor {
            global ::test_delete_watch
            lappend test_delete_watch "base $this"
        }
    }
    namespace eval itcl_test_ns {
      # class in NS with different name than base
      itcl::class test_delete_other {
        inherit ::test_delete_base
        destructor {
            global ::test_delete_watch
            lappend test_delete_watch "derivate-other $this"
        }
      }
      # class in NS with different name than base
      itcl::class test_delete_base {
        inherit ::test_delete_base
        destructor {
            global ::test_delete_watch
            lappend test_delete_watch "derivate-same $this"
        }
      }
    }
} -body {
    itcl_test_ns::test_delete_other test_del_other
    itcl_test_ns::test_delete_base test_del_base
    itcl::delete object test_del_other test_del_base
    set test_delete_watch
} -cleanup {
    set test_delete_watch {}
    namespace delete itcl_test_ns
    itcl::delete class ::test_delete_base
} -result {{derivate-other ::test_del_other} {base ::test_del_other} {derivate-same ::test_del_base} {base ::test_del_base}}

# ----------------------------------------------------------------------
#  Deleting class namespaces
# ----------------------------------------------------------------------
test delete-3.1 {redefine classes with inheritance} {
    variable ::test_delete_watch ""
    itcl::class test_delete_base {
204
205
206
207
208
209
210
211
212
213
214

test delete-5.4 {scoped command names are decoded properly} {
    list [catch {itcl::delete object {namespace inscope ::xyzzy xxx}} msg] $msg \
         [catch {itcl::delete object {namespace inscope :: xxx yyy}} msg] $msg \
         [catch {itcl::delete object {namespace inscope :: xyzzy}} msg] $msg
} {1 {unknown namespace "::xyzzy"} 1 {malformed command "namespace inscope :: xxx yyy": should be "namespace inscope namesp command"} 1 {object "namespace inscope :: xyzzy" not found}}

namespace delete test_delete_name test_delete2

::tcltest::cleanupTests
return







|



243
244
245
246
247
248
249
250
251
252
253

test delete-5.4 {scoped command names are decoded properly} {
    list [catch {itcl::delete object {namespace inscope ::xyzzy xxx}} msg] $msg \
         [catch {itcl::delete object {namespace inscope :: xxx yyy}} msg] $msg \
         [catch {itcl::delete object {namespace inscope :: xyzzy}} msg] $msg
} {1 {unknown namespace "::xyzzy"} 1 {malformed command "namespace inscope :: xxx yyy": should be "namespace inscope namesp command"} 1 {object "namespace inscope :: xyzzy" not found}}

catch { namespace delete test_delete_name test_delete2 }

::tcltest::cleanupTests
return