Smalltalk - Self Modifying code
Published: 3:12 PM GMT+12, Friday, 3 December 2004 under:
technology smalltalk
In this wee Smalltalk application I'm writing I'm pulling out the version number to use as a custom header in SMTP messages, it's a small thing, but the code I was using was:
SessionManager current versionInfo productVersionString
Which is all well and good, assuming I'm setting my version resource properly, at the time, my application was reporting "1.0.0.0" as the version and I got a query from one of the support engineers wondering why we has seeing "2002.5.1.4" being reported in the logs. This was logical, as when running in development mode, the current SessionManager is Dolphin Smalltalk's, not my own. So I changed my code to the following:
(SessionManager current isKindOf: TXTMailSessionManager)
ifTrue: [^SessionManager current versionInfo productVersionString]
ifFalse: [^(PackageManager current packageNamed: 'SMSComposer') packageVersion]
ifTrue: [^SessionManager current versionInfo productVersionString]
ifFalse: [^(PackageManager current packageNamed: 'SMSComposer') packageVersion]
So here the code first checks if the SessionManager is mine, and if not, returns the version of the package. All fine and dandy, yet the striped executable now includes PackageManager and any dependant classes, which increases the size of my executable. Then I started to think "hey, this is Smalltalk, I can get funky", a quick question to the guys on #smalltalk and I added the following line to my "set version" routine:
SMSComposerSettings
compile: 'applicationVersionString',
String lineDelimiter,
'^''' , aVersionNumber , ''''
compile: 'applicationVersionString',
String lineDelimiter,
'^''' , aVersionNumber , ''''
What this is doing is compiling a new function on my settings class, which simply returns a version string, now I just call #productVersionString on my settings class to get my version number, this works at runtime and development time, and doesn't introduce any new dependancies. The entire code for my version update routine is:
updateVersionNumber: aVersionNumber
"Update the class with a new version number method"
SMSComposerSettings
compile: 'productVersionString',
String lineDelimiter,
'^''' , aVersionNumber , ''''.
"Update my packages with a new version number"
#('SMSComposer' 'SMSComposerOutlookAddin' 'addressbooks' 'doap-project')
do: [:packageToUpdate |
PackageTools updateVersionNumber: aVersionNumber for: packageToUpdate]
"Update the class with a new version number method"
SMSComposerSettings
compile: 'productVersionString',
String lineDelimiter,
'^''' , aVersionNumber , ''''.
"Update my packages with a new version number"
#('SMSComposer' 'SMSComposerOutlookAddin' 'addressbooks' 'doap-project')
do: [:packageToUpdate |
PackageTools updateVersionNumber: aVersionNumber for: packageToUpdate]
Now, whenever I update the version of my application, I simply call in a workspace:
PackageTools updateVersionNumber: '3.0.4.21'
Some may argue I shouldn't set the same version number for all of the packages in this project, but for now, I can live with that.