[comment {-*- mode: tcl ; fill-column: 90 -*- doctools manpage}]
[comment {quadrant: reference}]
[include pkg_version.inc]
[manpage_begin critcl_tcl9 n [vset VERSION]]
[include include/module.inc]
[titledesc {How To Adapt Critcl Packages for Tcl 9}]
[description]
[para]
[include include/welcome.inc]
[para]

This guide contains notes and actions to take by writers of [vset critcl]-based
packages to make their code workable for both Tcl 8.6 and 9.

[comment {= = == === ===== ======== ============= =====================}]

[list_begin enumerated]

[enum] Generally, if there is no interest in moving to Tcl 9, i.e. Tcl 8.[lb]456[rb]
       are the only supported runtimes, then just keep using [vset critcl] [const 3.2].

[para] The remainder of this document can be ignored.

[enum] Use [vset critcl] version [vset VERSION] [strong {if, and only if}]
       Tcl 9 support is wanted.

[para] With some work this will then also provide backward compatibility with Tcl 8.6.

[enum] Header [file tcl.h]

[para] Replace any inclusion of Tcl's public [file tcl.h] header file in the package's
       C code with the inclusion of [vset critcl]'s new header file [file tclpre9compat.h].

[para] This includes [file tcl.h] and further provides a set of compatibility definitions
       which make supporting both Tcl 8.6 and Tcl 9 in a single code base easier.

[para] The following notes assume that this compatibility layer is in place.

[enum] [cmd critcl::tcl]

[para] Before [vset critcl] [vset VERSION] a single default ([const 8.4]) was used for
       the minimum Tcl version, to be overriden by an explicit [cmd critcl::tcl] in the
       package code.

[para] Now the default is dynamic, based on the [strong runtime] version, i.e.
       [cmd {package provide Tcl}], [vset critcl] is run with/on.

[para] When running on Tcl 9 the new default is version [const 9], and [const 8.6] else.
       [strong Note] how this other default was bumped up from [const 8.4].

[para] As a consequence it is possible to

[list_begin enumerated]

[enum] Support just Tcl 8.4+, 8.5+, by having an explicit [cmd {critcl::tcl 8.x}] in
       the package code.

[para] [strong {Remember however}], it is better to simply stick with
       [vset critcl] [const 3.2] for this.

[enum] Support just Tcl 9 by having an explicit [cmd {critcl::tcl 9}] in the package code.

[enum] Support both Tcl 8.6 and Tcl 9 (but not 8.4/8.5) by leaving [cmd critcl::tcl] out of the code
       and using the proper [syscmd tclsh] version to run [vset critcl] with.
[list_end]

[enum] Code checking

[para] [vset critcl] [vset VERSION] comes with a very basic set of code checks pointing
       out places where compatibility might or will be an issue.

[para] The implementation checks all inlined C code declared by [cmd critcl::ccode],
       [cmd critcl::ccommand], [cmd critcl::cproc] (and related/derived commands), as well
       as the C companion files declared with [cmd critcl::csources].

[para] It is very basic because it simply greps the code line by line for a number
       of patterns and reports on their presence. The C code is not fully parsed.
       The check can and will report pattern found in C code comments, for example.

[para] The main patterns deal with functions affected by the change to [type Tcl_Size],
       the removal of old-style interpreter state handling, and command creation.

[para] A warning message is printed for all detections.

[para] This is disabled for the [const Tcl_Size]-related pattern if the line also matches
       the pattern [const {*OK tcl9*}].

[para] In this way all places in the code already handled can be marked and excluded
       from the warnings.      

[list_begin enumerated]

[enum] Interpreter State handling

[para] Tcl 9 removed the type [type Tcl_SavedResult] and its associated functions
       [fun Tcl_SaveResult], [fun Tcl_RestoreResult], and [fun Tcl_DiscardResult].

[para] When a package uses this type and the related functions a rewrite is necessary.

[para] With Tcl 9 use of type [type Tcl_InterpState] and its functions
       [fun Tcl_SaveInterpState], [fun Tcl_RestoreInterpState], and
       [fun Tcl_DiscardInterpState] is now required.

[para] As these were introduced with Tcl 8.5 the rewrite gives us compatibility with
       Tcl 8.6 for free.

[enum] [type Tcl_Size]

[para] One of the main changes introduced with Tcl 9 is the breaking of the 2G barrier
       for the number of bytes in a string, elements in a list, etc.

       In a lot of interfaces [type int] was replaced with [type Tcl_Size], which is
       effectively [type ptrdiff_t] behind the scenes.

[para] The [file tclpre9compat.h] header mentioned above provides a suitable definition
       of [type Tcl_Size] for [const 8.6], i.e. maps it to [type int].

       This enables the package code to use [type Tcl_Size] everywhere and still have it
       work for both Tcl 8.6 and 9.

[para] It is of course necessary to rewrite the package code to use [type Tcl_Size].

[para] The checker reports all lines in the C code using a function whose signature
       was changed to use [type Tcl_Size] over [type int].

[para] Note that it is necessary to manually check the package code for places where
       a [const %d] text formatting specification should be replaced with
       [const TCL_SIZE_FMT].

[para] I.e. all places where [type Tcl_Size] values are formatted with [fun printf]-style
       functions a formatting string [example {"... %d ..."}] has to be replaced with
       [example {"... " TCL_SIZE_FMT " ..."}]

[para] The macro [cmd TCL_SIZE_FMT] is defined by Critcl's compatibility layer, as an
       extension of the [cmd TCL_SIZE_MODIFIER] macro which only contains the
       formatting modifier to insert into a plain [const %d] to handle [type Tcl_Size]
       values.

[para] [strong Note] how the original formatting string is split into multiple strings.
       The C compiler will fuse these back together into a single string.

[enum] Command creation.

[para] This is technically a part of the [type Tcl_Size] changes.

[para] All places using [fun Tcl_CreateObjCommand] have to be rewritten to use
       [fun Tcl_CreateObjCommand2] instead, and the registered command functions
       to use [type Tcl_Size] for their [arg objc] argument.

[para] The [file tclpre9compat.h] header maps this back to the old function
       when compilation is done against Tcl 8.6.

[para] [vset critcl] does this itself for the commands created via [cmd critcl::ccommand],
       [cmd critcl::cproc], and derived places ([package critcl::class]).

[enum] TIP 494. This TIP adds three semantic constants wrapping [const -1] to Tcl 9 to
       make the meaning of code clearer. As part of this it also casts the constant to the
       proper type. They are:

[list_begin itemized]
[item] [const TCL_IO_FAILURE]
[item] [const TCL_AUTO_LENGTH]
[item] [const TCL_INDEX_NONE]
[list_end]

[para] Critcl's compatibility layer provides the same constants to Tcl 8.6.

[para] Critcl's new checker highlights places where [const TCL_AUTO_LENGTH] is suitable.

[para] Doing this for the other two constants looks to require deeper and proper parsing
       of C code, which the checker does not do.

[list_end]
[list_end]

[section {Additional References}]
[list_begin enumerated]
[enum] [uri https://wiki.tcl-lang.org/page/Porting+extensions+to+Tcl+9]
[enum] [uri https://wiki.tcl-lang.org/page/Tcl+9+functions+using+Tcl%5FSize]
[enum] [uri https://core.tcl-lang.org/tcl/wiki?name=Migrating%20scripts%20to%20Tcl%209]
[enum] [uri https://core.tcl-lang.org/tcl/wiki?name=Migrating%20C%20extensions%20to%20Tcl%209]
[list_end]


[comment {= = == === ===== ======== ============= =====================}]
[include include/feedback.inc]
[manpage_end]
