Tcl Source Code

Check-in [6a997a7f19]
Login

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

Overview
Comment:few improvements for [effa2e2346f8372a]: code deduplication, init commands declared as list, update mocked-up/injected command if needed, code review (C89/C90-capability, etc)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | apn-oo-lazy-init-sbmod
Files: files | file ages | folders
SHA3-256: 6a997a7f19eaa6fa74f7a83cf9e58c32fa8cfad09c134f39ad61d80219aa95e8
User & Date: sebres 2025-08-16 14:12:06.891
References
2025-08-16
23:02 New ticket [8a13caa31d] Setting of system encoding isn't applied to stdout on certain circumstances. artifact: a90b13432a user: sebres
14:30 Ticket [effa2e2346] RFE - lazy loading of TclOO for faster interp creation status still Open with 3 other changes artifact: a37f40ea3c user: sebres
Context
2025-08-18
21:40
partial back-port from tclSE (currently windows only): allow to load statically linked modules witho... check-in: 07f7174617 user: sebres tags: experimental-load-tcltest-implicitly
12:29
Lazy init for 9.1 Leaf check-in: 105952fb15 user: apnadkarni tags: apn-oo-lazy-init-sbmod-91
2025-08-16
14:12
few improvements for [effa2e2346f8372a]: code deduplication, init commands declared as list, update ... Leaf check-in: 6a997a7f19 user: sebres tags: apn-oo-lazy-init-sbmod
04:22
Delete oo::singleton,configurable commands before defining them as classes Leaf check-in: edd3cd05f0 user: apnadkarni tags: apn-oo-lazy-init
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclOO.c.
47
48
49
50
51
52
53














54
55
56
57
58
59
60
    {"private", TclOODefinePrivateObjCmd, 1},
    {"renamemethod", TclOODefineRenameMethodObjCmd, 1},
    {"self", TclOODefineObjSelfObjCmd, 0},
    {"unexport", TclOODefineUnexportObjCmd, 1},
    {NULL, NULL, 0}
};















/*
 * What sort of size of things we like to allocate.
 */

#define ALLOC_CHUNK 8

/*







>
>
>
>
>
>
>
>
>
>
>
>
>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    {"private", TclOODefinePrivateObjCmd, 1},
    {"renamemethod", TclOODefineRenameMethodObjCmd, 1},
    {"self", TclOODefineObjSelfObjCmd, 0},
    {"unexport", TclOODefineUnexportObjCmd, 1},
    {NULL, NULL, 0}
};

static const char *
initCmds[] = {
    "_init",
    "class",
    "configurable",
    "define",
    "objdefine",
    "object",
    "singleton",
    "InfoObject",
    "InfoClass",
    NULL
};

/*
 * What sort of size of things we like to allocate.
 */

#define ALLOC_CHUNK 8

/*
228
229
230
231
232
233
234
235
236
237
238
239
240

241






242









243









244
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
 *	Creates namespaces, commands, several classes and a number of
 *	callbacks. Upon return, the OO system is ready for use.
 *
 * ----------------------------------------------------------------------
 */
static int
TclOOInitModuleObjCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    Interp *iPtr = (Interp *)interp;

    if (iPtr->objectFoundation == NULL) {






	/* Not initialized so do it */



















	/*
	 * Defining of oo::{configurable,singleton} as classes will fail
	 * if the command of that name exists so delete their stubs.
	 */
	(void) Tcl_DeleteCommand(interp, "::oo::configurable");
	(void) Tcl_DeleteCommand(interp, "::oo::singleton");
	if (InitFoundation(interp) != TCL_OK) {
	    return TCL_ERROR;
	}

    }

    return Tcl_EvalObjv(interp, objc, objv, 0);
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOInit --







|





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

<
>







242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

293
294
295
296
297
298
299
300
 *	Creates namespaces, commands, several classes and a number of
 *	callbacks. Upon return, the OO system is ready for use.
 *
 * ----------------------------------------------------------------------
 */
static int
TclOOInitModuleObjCmd(
    void *clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    Interp *iPtr = (Interp *)interp;
    
    if (iPtr->objectFoundation != NULL) {
	/* 
	 * Shall be not initialized yet, so it looks like a mockup/injection,
	 * try to update the command.
	 */
	Foundation *fPtr = (Foundation *) iPtr->objectFoundation;
	const char *cmdName = (char *)clientData;

	if (objc) {
	    Tcl_Command cmd = Tcl_FindCommand(interp, cmdName, fPtr->ooNs, 0);
	    Tcl_Command cmd2 = Tcl_FindCommand(interp, TclGetString(objv[0]),
					fPtr->ooNs, 0);
	    if (cmd && cmd2) {
	    	Tcl_CmdInfo info;
		Tcl_GetCommandInfoFromToken(cmd, &info);
		Tcl_SetCommandInfoFromToken(cmd2, &info);
		goto evalIt;
	    }
	}

	/* We cannot reinitialize the command, so simply produce an error */
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
	    "unexpected already initialized foundation calling \"%s\" for \"%s\"",
		objc ? TclGetString(objv[0]) : "", cmdName));
	return TCL_ERROR;
    }

    /*
     * Defining of oo::{configurable,singleton} as classes will fail
     * if the command of that name exists so delete their stubs.
     */
    (void) Tcl_DeleteCommand(interp, "::oo::configurable");
    (void) Tcl_DeleteCommand(interp, "::oo::singleton");
    if (InitFoundation(interp) != TCL_OK) {
	return TCL_ERROR;
    }


evalIt:
    return Tcl_EvalObjv(interp, objc, objv, 0);
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOInit --
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
 *
 * ----------------------------------------------------------------------
 */
int
TclOOInit(
    Tcl_Interp *interp)		/* The interpreter to install into. */
{
    Tcl_CreateObjCommand(interp, "::oo::class",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);
    Tcl_CreateObjCommand(interp, "::oo::configurable",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);
    Tcl_CreateObjCommand(interp, "::oo::define",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);
    Tcl_CreateObjCommand(interp, "::oo::objdefine",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);
    Tcl_CreateObjCommand(interp, "::oo::object",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);

    Tcl_CreateObjCommand(interp, "::oo::singleton",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);


    Tcl_Command infoCmd;
    Tcl_Obj *mapDict;

    /*
     * Install into the [info] ensemble.
     */

    infoCmd = Tcl_FindCommand(interp, "info", NULL, TCL_GLOBAL_ONLY);
    if (infoCmd) {
	Tcl_CreateObjCommand(interp, "::oo::InfoObject",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);
	Tcl_CreateObjCommand(interp, "::oo::InfoClass",
	    TclOOInitModuleObjCmd, INT2PTR(0), NULL);
	Tcl_GetEnsembleMappingDict(NULL, infoCmd, &mapDict);
	TclDictPutString(NULL, mapDict, "object", "::oo::InfoObject");
	TclDictPutString(NULL, mapDict, "class", "::oo::InfoClass");
	Tcl_SetEnsembleMappingDict(interp, infoCmd, mapDict);
    }

    /*
     * Set up the version and patchlevel variables. This used to be done by
     * the init script which is no longer used.
     */
    Tcl_SetVar2(interp, "::oo::patchlevel", NULL, TCLOO_PATCHLEVEL, 0);
    Tcl_SetVar2(interp, "::oo::version", NULL, TCLOO_VERSION, 0);

#ifndef TCL_NO_DEPRECATED
    Tcl_PkgProvideEx(interp, "TclOO", TCLOO_PATCHLEVEL,
	    &tclOOStubs);
#endif
    Tcl_PkgProvideEx(interp, "tcl::oo", TCLOO_PATCHLEVEL,
	    &tclOOStubs);

    if (Tcl_EvalEx(interp,
	"package ifneeded tcl::oo " TCLOO_PATCHLEVEL " {};"
	"package ifneeded TclOO " TCLOO_PATCHLEVEL " {};",
	TCL_INDEX_NONE, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*







|
|
<
<
|
<
|
|
|
<
>
|
|
|
<
<
<







<
<
<
<













<
<
<
<
<
<
<

|
|







313
314
315
316
317
318
319
320
321


322

323
324
325

326
327
328
329



330
331
332
333
334
335
336




337
338
339
340
341
342
343
344
345
346
347
348
349







350
351
352
353
354
355
356
357
358
359
 *
 * ----------------------------------------------------------------------
 */
int
TclOOInit(
    Tcl_Interp *interp)		/* The interpreter to install into. */
{
    Tcl_Namespace *ooNS;
    const char **cmdNamePtr;


    Tcl_Command infoCmd;

    Tcl_Obj *mapDict;

    ooNS = Tcl_CreateNamespace(interp, "::oo", NULL, NULL);

    for (cmdNamePtr = initCmds; *cmdNamePtr; cmdNamePtr++) {
	TclCreateObjCommandInNs(interp, *cmdNamePtr, ooNS,
		TclOOInitModuleObjCmd, (void *)*cmdNamePtr, NULL);
    }




    /*
     * Install into the [info] ensemble.
     */

    infoCmd = Tcl_FindCommand(interp, "info", NULL, TCL_GLOBAL_ONLY);
    if (infoCmd) {




	Tcl_GetEnsembleMappingDict(NULL, infoCmd, &mapDict);
	TclDictPutString(NULL, mapDict, "object", "::oo::InfoObject");
	TclDictPutString(NULL, mapDict, "class", "::oo::InfoClass");
	Tcl_SetEnsembleMappingDict(interp, infoCmd, mapDict);
    }

    /*
     * Set up the version and patchlevel variables. This used to be done by
     * the init script which is no longer used.
     */
    Tcl_SetVar2(interp, "::oo::patchlevel", NULL, TCLOO_PATCHLEVEL, 0);
    Tcl_SetVar2(interp, "::oo::version", NULL, TCLOO_VERSION, 0);








    if (Tcl_EvalEx(interp,
	"package ifneeded tcl::oo " TCLOO_PATCHLEVEL " oo::_init;"
	"package ifneeded TclOO " TCLOO_PATCHLEVEL " oo::_init;",
	TCL_INDEX_NONE, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*
378
379
380
381
382
383
384









385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400








401
402
403
404

405
406
407
408
409
410
411
412
413
414
415
416
417
418

419
420
421
422
423

424
425
426
427
428
429
430
    }
    cmdPtr = (Command *) TclCreateObjCommandInNs(interp, name,
	    namespacePtr, cmdProc, NULL, NULL);
    cmdPtr->nreProc = nreProc;
    cmdPtr->compileProc = compileProc;
}










/*
 * ----------------------------------------------------------------------
 *
 * InitFoundation --
 *
 *	Set up the core of the OO core class system. This is a structure
 *	holding references to the magical bits that need to be known about in
 *	other places, plus the oo::object and oo::class classes.
 *
 * ----------------------------------------------------------------------
 */

static int
InitFoundation(
    Tcl_Interp *interp)
{








    if (((Interp *) interp)->objectFoundation) {
	return TCL_OK;
    }


    static Tcl_ThreadDataKey tsdKey;
    ThreadLocalData *tsdPtr = (ThreadLocalData *)
	    Tcl_GetThreadData(&tsdKey, sizeof(ThreadLocalData));
    Foundation *fPtr = (Foundation *) Tcl_Alloc(sizeof(Foundation));
    Tcl_Namespace *define, *objdef;
    Tcl_Obj *namePtr;
    size_t i;

    /*
     * Initialize the structure that holds the OO system core. This is
     * attached to the interpreter via an assocData entry; not very efficient,
     * but the best we can do without hacking the core more.
     */


    memset(fPtr, 0, sizeof(Foundation));
    ((Interp *) interp)->objectFoundation = fPtr;
    fPtr->interp = interp;
    fPtr->ooNs = Tcl_FindNamespace(interp, "::oo", NULL, 0);
    assert(fPtr->ooNs != NULL);

    Tcl_Export(interp, fPtr->ooNs, "[a-z]*", 1);
    define = Tcl_CreateNamespace(interp, "::oo::define", fPtr, NULL);
    objdef = Tcl_CreateNamespace(interp, "::oo::objdefine", fPtr, NULL);
    fPtr->helpersNs = Tcl_CreateNamespace(interp, "::oo::Helpers", fPtr,
	    DeletedHelpersNamespace);
    Tcl_CreateNamespace(interp, "::oo::configuresupport", NULL, NULL);
    fPtr->epoch = 1;







>
>
>
>
>
>
>
>
>
















>
>
>
>
>
>
>
>




>
|
<
|
|
|
|
<







>





>







400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

446
447
448
449

450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
    }
    cmdPtr = (Command *) TclCreateObjCommandInNs(interp, name,
	    namespacePtr, cmdProc, NULL, NULL);
    cmdPtr->nreProc = nreProc;
    cmdPtr->compileProc = compileProc;
}

static int
NoopCmd(
    TCL_UNUSED(void *),
    TCL_UNUSED(Tcl_Interp *),
    TCL_UNUSED(int) /*objc*/,
    TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
    return TCL_OK;
}
/*
 * ----------------------------------------------------------------------
 *
 * InitFoundation --
 *
 *	Set up the core of the OO core class system. This is a structure
 *	holding references to the magical bits that need to be known about in
 *	other places, plus the oo::object and oo::class classes.
 *
 * ----------------------------------------------------------------------
 */

static int
InitFoundation(
    Tcl_Interp *interp)
{
    static Tcl_ThreadDataKey tsdKey;
    ThreadLocalData *tsdPtr = (ThreadLocalData *)
	    Tcl_GetThreadData(&tsdKey, sizeof(ThreadLocalData));
    Foundation *fPtr;
    Tcl_Namespace *define, *objdef;
    Tcl_Obj *namePtr;
    size_t i;

    if (((Interp *) interp)->objectFoundation) {
	return TCL_OK;
    }

#ifndef TCL_NO_DEPRECATED
    Tcl_PkgProvideEx(interp, "TclOO", TCLOO_PATCHLEVEL,

	    &tclOOStubs);
#endif
    Tcl_PkgProvideEx(interp, "tcl::oo", TCLOO_PATCHLEVEL,
	    &tclOOStubs);


    /*
     * Initialize the structure that holds the OO system core. This is
     * attached to the interpreter via an assocData entry; not very efficient,
     * but the best we can do without hacking the core more.
     */

    fPtr = (Foundation *) Tcl_Alloc(sizeof(Foundation));
    memset(fPtr, 0, sizeof(Foundation));
    ((Interp *) interp)->objectFoundation = fPtr;
    fPtr->interp = interp;
    fPtr->ooNs = Tcl_FindNamespace(interp, "::oo", NULL, 0);
    assert(fPtr->ooNs != NULL);
    TclCreateObjCommandInNs(interp, "_init", fPtr->ooNs, NoopCmd, NULL, NULL);
    Tcl_Export(interp, fPtr->ooNs, "[a-z]*", 1);
    define = Tcl_CreateNamespace(interp, "::oo::define", fPtr, NULL);
    objdef = Tcl_CreateNamespace(interp, "::oo::objdefine", fPtr, NULL);
    fPtr->helpersNs = Tcl_CreateNamespace(interp, "::oo::Helpers", fPtr,
	    DeletedHelpersNamespace);
    Tcl_CreateNamespace(interp, "::oo::configuresupport", NULL, NULL);
    fPtr->epoch = 1;