Porting Chronos...

...To Earlier Versions of VisualWorks

Without any modifications or special procedures, Chronos.st will file-in successfully to any VW 5.i3 or later VisualWorks image. Even though the code itself is known to work in even earlier versions of VW (although it has not been extensively tested in non-VW7x images,) the file format of Chronos.st cannot be correctly interpreted by VisualWorks images prior to VW 5i.3. For older versions of VW, it is necessary to file out Chronos.st using a format that can be consumed by the target image (or else to backport the ability to consume the modern VW XML format into the target image.)

The optional “PARC Goodie” FileOut30.pcl parcel enables a modern VW image to file out packages or bundles in the classic pre-5i “chunk format.” It also supports a variety of non-VisualWorks file-out formats.

However, due to the lack of any meaningful support for “shared pool Dictionary” file-out/file-in provided by the classic ST80/VW “chunk” file-out format, it is necessary to define two “shared pool” globals before filing-in Chronos to a pre-5i image (or into a post 3x image if the file-in is in the classic “chunk” file-out format.). This can be done be evaluating the following “do it” in the target image before filing-in Chronos:

    Smalltalk
        at: #Chronos put: Dictionary new;
        at: #ChronosConstants put: Dictionary new.


Note to those porting into VW 5i.0, 5i.1 and 5i.2
: When filing-in a classic “chunk format” file containing the Chronos codebase into a post-3x image, #Chronos and #ChronosConstants must be predefined as Namespaces (contained by #Smalltalk,) instead of as Dictionaries.

For pre-3x images, there is insufficient ANSI Smalltalk compatibility for Chronos to operate without errors. This can be fixed by backporting ANSI Smalltalk compatibility methods and other changes into the target image. For example, the following steps were found to be necessary in order to get Chronos up and running in VW 2.5.1 (in addition to defining the two global shared pool Dictionaries, as mentioned previously):

  • Add the methods #on:do: and #ensure: to BlockClosure (behavior as specified by ANSI.)
  • Add the method #return: to Exception (behavior as specified by ANSI.)
  • Add the methods #message and #receiver to Exception (behavior as specified by ANSI for the MessageNotUnderstood Exception.)
  • Define the global #Error with the value “Object errorSignal”.
  • Define the global #MessageNotUnderstood with the value “Object messageNotUnderstoodSignal”

Installing and using Chronos in pre-3x VisualWorks images is not recommended.

…To Other Smalltalk Environments

Chronos was architected and designed to be portable to other Smalltalk systems. However, the author of Chronos strongly prefers to avoid doing any such ports himself (in spite of the fact that he did quite a bit of the work needed to make the Squeak port fully functional; Squeak, after all, has a special place in the world, and has no commerical vendor behind it who is primarily responsible for its care and feeding.) However, he is willing to serve as a consultant to anyone who is seriously engaged in porting Chronos to some other Smalltalk environment. To make a request for such aid, send an e-mail to the following address: {porting (at) chronos-st (dot) org}. Hopefully, the following information will prove to be sufficient:

Firstly, you may find the optional "contributed component" (a.k.a. “Goodie”) FileOut30.pcl parcel to be useful. It enables a modern VW image to file out packages or bundles in the classic ST80 “chunk format.” It also supports a variety of non-VisualWorks file-out formats. An even better option would be the Rosetta Cross-Dialect Smalltalk Code Interchange Tool. You can find it at http://rosettast.sourceforge.net/.

Secondly, you will need to follow the procedure as given in the instructions to produce the Chronos Seed. [Link: http://www.chronos-st.org/Chronos-Seed.html]

In the case of the VisualWorks version of Chronos, the packages <Passport-Kernel-VW>, <Chronos-VW-Extensions> and <Chronos-ST80 (and VW) Compatibility> are VisualWorks specific.  Similar packages (with different names) will probably be present in the versions of Chronos specific to other Smalltalk flavors (assuming some sort of module system is even supported at all.)  Providing classes and methods that are analagous to those in  <Passport-Kernel-VW> will be absolutely necessary.  Providing code that is analagous to that provided by the other two packages is entirely optional.

The <Chronos-VW-Extensions> package (or its analog) adds convenience methods ("syntactic sugar") to classes in the Smalltalk base library, such as Number>>hours, so that users (programmers) can code "-8 hours" instead of "Duration hours: -8."  One issue to be considered is whether any such methods would conflict with methods already present in the target Smalltalk library (perhaps ones added by a popular optional module/package.)

Although you won't want to include the <Chronos-VW-Extensions> package "as is" in your initial port, you should nevertheless strongly consider providing analogous extensions in the target Smalltalk environment, unless such methods would conflict with ones natively present (but on the other hand, you might do it even then.) Chronos itself does not need or use any of the extension methods in the <Chronos-VW-Extensions> package, but applications or other libraries that rely on Chronos will almost certainly expect them to be present.

The package <Chronos-ST80 (and VW) Compatibility> is also VisualWorks-specific.  It extends certain Chronos classes with methods to make them type-compatible with Core.Date, Core.Timestamp and Core.Time.  If such compatibility might be useful, you could include this package in your port--although some of the implementation-logic assumes that the classes Date, Timestamp and Time exist, and have the VW API.  Otherwise, you can safely remove this package. Chronos itself does not depend on any of the extension methods in the <Chronos-ST80 (and VW) Compatibility> package.

You might also need or want to add methods to certain Chronos classes to make them partially or fully type-compatible with whatever date/time classes are native to the target Smaltlalk environment.  One piece of advice here: Don't blindly believe the code comments in the host environment's date/time code.  For example, as of Squeak 3.8, comments in the code of Squeak's Chronology library falsely claim that the internal variables of a Chronology.DateAndTime instance specify the date and time relative to Universal Time.  The truth is that those variables specify local time--probably because the Squeak system clock reports local time (Chronos can handle system clocks that report either Universal Time or local time--read the class comments of ChronosSystemClock and CalendarClock for more information.).

The class ChronosInstaller (in the <Chronos-Installation> package) should not be included in the file-in to be ported to the target Smalltalk image (or library.) The ChronosInstaller class only exists as a mechanism to launch the final initialization and configuration of Chronos. It implements just two class-side methods, #initialize and #postLoad:.

The #postLoad: class method is invoked when a VisualWorks parcel is loaded.  Outside of a VisualWorks environment, it is superfluous and can be removed.

When ChronosInstaller is filed out of VisualWorks, VW will include a "do it" that invokes "ChronosInstaller class>>initialize" when filed back in. You don't want that to happen pursuant to the very first file-in of the Chronos code into the Smalltalk platform to which you are porting.  However, the analogous “final initialization and configuration” effect needs to be achieved by the Chronos “file-in” (or whatever the equivalent “distribution file” may be called) that you distribute as the ported “load and go” version of Chronos.  How that is best achieved is platform-specific.  What needs to happen once the fully-ported and functional Chronos codebase has been "filed in" (or otherwise loaded in) to a new image is that the message #install must be sent to the canonical instance of ChronosEnvironment (i.e, the expression "ChronosEnvironment canonical install" must be evaluated.)  That's all that the ChronosInstaller class>>initialize method does. The ported distrubution file you prepare for Chronos needs to make that happen, but not until the entire Chronos codebase has been loaded.  Use whatever mechanism to get that done automatically that is appropriate for the Smalltalk flavor involved.

Thirdly, it may be useful (or even absolutely necessary) to port Chronos into a non-VW Smalltalk environment using a staged approach. For example, it may be advisable to only file-in/install the contents of the <Passport-Kernel> package, fixing any problems or issues encountered during the file-in, then implementing the necessary platform-specific subclasses before attempting to do the same with the remainder of the Chronos codebase. 

Fourthly, it may be necessary to add some “VisualWorks Compatibility” and/or “ANSI-Smalltalk Compatibility” code into the target image (or into the standard library if the target environment is not image based.) Such additions would likely include the following methods (probably not an exhaustive list in some cases): 

  • Object>>isSequenceable
  • Obect>>respondsToArithmetic (answer false, or '^self isNumber', or whatever may be appropriate)
  • Number>>respondsToArithmetic (answer true)
  • SequenceableCollection>>readStream 
  • SequenceableCollection>>writeStream 
  • SequenceableCollection>>newReadWriteStream 
  • *>>literalArrayEncoding 
  • * class>>decodeFromLiteralArray: 
  • Array>>decodeAsLiteralArray

The #literalArrayEncoding message needs to be understood by the instances of any class whose instances have a literal representation that can appear in an Array literal (according to the ANSI-Smalltalk Standard.) The class message #decodeFromLiteralArray: needs to be understood by any class whose instances respond to #literalArrayEncoding.

An issue that you hopefully won't have to deal with is the interpretation of Array literals.  Although the Chronos codebase includes Array literals that assume the ANSI-Standard intepretation of Array literals (where #(nil) = (Array with: nil),) the code that processes any such Arrays ensures that any #nil, #true or #false values that are the elements of such an Array literal are converted to the ANSI-mandated value. There are only two usages of Arrays where this matters: ChronosPrintPolicy specification Arrays and day-of-week policy Arrays (used by SemanticAnnualDateRule objects.)

Also see the comments above regarding the necessary steps and procedures for porting Chronos into ancient versions of VisualWorks—the same issues may need to be resolved in similar or analogous ways.

Fifthly, the flip side of having to remove the platform-specific classes and packages from the version of Chronos from which you are porting is that you must then implement analogous classes and packages for your target Smalltalk platform. At a minimum, you will have to implement platform-specific subclasses of EnvironmentFacade, ResourcePathFacade, ChronosEnvironment, ChronosSystemClock, and ChronosSystemFacade in order to get Chronos working on your target Smalltalk platform.

Be advised that the class comments of EnvironmentFacade, ResourcePathFacade, ChronosEnvironment, ChronosSystemClock, and ChronosSystemFacade are essential reading for anyone who wishes to port Chronos to a non-VisualWorks Smalltalk environment. Most of the code that needs to be changed and/or implemented de novo in order to effect a port of Chronos to another Smalltalk system is specified and documented in those classes. 

Sixthly, for more information about what's involved in discovering what time zone your code happens to be running in, and how to obtain the time zone rules used by the host operating system to convert between Universal Time and local time, you may find the essay Discovering the Local Time Zone--Why It's a Hard Problem to be a useful resource.

Lastly, be advised that Chronos is a work in progress. There will be new versions, perhaps with design and/or API changes. You would be well advised to do ports to other Smalltalk flavors so that the procedure is repeatable--with far less work involved when porting subsequent versions.

The VW version is modularized into StORE packages so that most (and hopefully all) of the platform-specific code resides in the packages Chronos-Environment and Chronos-System. The best approach for porting is to try to limit changes to the Chronos codebase to the classes in those packages (or to introduce subclasses of the classes in those packages.) Where possible, any porting issues that cannot be handled by changes to the Chronos-Environment and Chronos-System packages should instead be handled by introducing compatibility classes/methods into the target environment (especially when the issue is a lack of ANSI compliance.)

Modification of the Chronos codebase for the purpose of making Chronos work correctly on the Smalltalk platform to which it is being ported (other than as herein described,) is strongly not recommended. Instead, please notify the author of Chronos of the porting problem {send and e-mail to porting (at) chronos-st (dot) org} so that a general solution to the problem can be designed and incorporated into the mainline Chronos codebase.

…To Other Programming Languages

The author of Chronos expects that Chronos will be ported to other programming languages, but currently has no intention of doing any such ports himself. However, he may be willing in some cases to offer advice and/or provide consulting services to anyone who attempts to port Chronos to another programming language.

[Chronos] All code (classes and methods, and all associated documentation,) distributed as part of the Chronos Date/Time library are © Copyright 2005-2006 by Alan L. Lovejoy.  All Rights Reserved. Usage is controlled by the Chronos License (which is included in the distribution as the contents of the file {chronos-license.txt}, and is also available from the Chronos web site {http://www.chronos-st.org/License.html})

"Do not go gentle into that good night,
Old age should burn and rave at the close of the day;
Rage, rage at the dying of the light!" -- Dylan Thomas