Exploring Type Safety in Smalltalk
written by Peter William Lount
version 1, 20050914
"More generally, a dynamically typed program will have less information about itself [specifically no manifestly specified type information] than one with manifest typing (although I presume it would be the same as a statically typed program with type inference). That's part of the point - you don't have to specify as much. [Which is a huge win.] At least as far as Smalltalk is concerned, these are part of the reason it has development traditions like test-driven design, and unit testing (and is where the original refactoring tools came from, as well as the original xUnit). These kinds of measures help ensure correctness when the program changes, while preserving the flexibility, terseness, and other advantages of not specifying types up-front. And as well, keyword messages make name collisions that much less likely."
[Editors notes in square brackets].
[Actually dyamicly typed (or really dynamicly untyped or dynamicly non-typed or simply dynamic) programs have more meta information available at runtime than staic programs do. Dynamic programs simply don't apply types to variables, parameters and return values as you are required to provide in static and typed languages and systems].
Something magical happens when "manifest" type information is left out of programs. Smalltalk is an excellent example of this magic. While adding type information has it's benefits it also alters the shape of how you build programs. As there are somethings that can be done with "manifest typed" programs that can't be done with dynamic programs, the reverse is also especially true: untyped, non-typed, or dynamic programs have special capabilities that typed systems don't have. It's very interesting that a line in the sand between typed and dynamic systems exists, very interesting indeed. How do we know this line exists? The evidence is simple and based upon facts, Smalltalk exists and works well - very well - without the need for types. In addition when types are added to Smalltalk the way that you program changes, limits are now placed upon variables, parameters, and return values that alter the "shape", "nature", and "style" of code writing. These changes have a huge impact upon the flexibility, terseness and other advantages that Smalltalk has to offer.
Those that think that types are not used in Smalltalk are not entirely correct, "types" are used, or more correctly the objects class meta information
is available for use at runtime to perform any necessary and all possible 'type' operations
at run-time (which includes almost all the compile time "type" possibilities). The object meta data
available through the base Smalltalk language while the program is running is a much more powerful facility and provides capabilities not possible in staticly compiled typed systems such as C, Java, C++, C#, ... . These and other statically compiled typed language and systems strip away most if not all of the "type meta data" so that your program is a barren husk devoid of the richness that runtime meta data provides.
While some programs don't need the rich runtime meta data that Smalltalk provides a whole class of applications can only be built upon the powerful base that Smalltalk provides with it's meta data capabilities.
In a way it's a ironicly funny and twisted sorry state that those that promote the "safety of typed systems" and "additional capabilities of typed systems" also are promoting the "barren space devoid of the richness of runtime meta data". A whole world of powerful "meta data programming" is lost to those languages, not to mention the loss of the other dynamic language features (typelessness is but one of Smalltalks many advantages).
(anObject isKindOf: String) ifTrue: [...] ifFalse: [...]
is an example of Smalltalk's runtime equilivant of "type testing" and shows how object meta data is accessed, in this case the object class meta data or "type". Actually this example tests whether or not "anObject" is any "kind" of String including one of it's subclasses of specialized strings such as a "Symbol". (A Symbol in Smalltalk is simply an a particular sequence of characters with a unique identity so that two symbols with the same character sequence give you the same object instance exactly, whereas two String's with the same character sequence have different identities. In Smalltalk Strings are specified with text between two single quote characters. i.e. 'Hello world'. Symbols are specified with a leading pound character "#" and no quotes. i.e. #WhatCanYouSay123).
(anObject isMemberOf: String) ifTrue: [...] ifFalse: [...]
is a more specific "type" test that mirrors what's usually specified for variables, parameters and return values in C, Java, C++, C#, ... . In this case "anObject" is being tested to see if it's an instance of a specific class, String. So if anObject is an instance of the String subclass Symbol the answer is false.
It's very interesting to note that dynamic Smalltalk programs provide the ability to implement "type safety" at runtime. As a pragmatic matter and programming style it's used when necessary or by choice. However, the cautions with using "types" in "typed and static programs" regarding the loss of flexibility and loss of other capabilities apply to Smalltalk meta programming as well. One must be carefull to avoid the pitfalls of over constraining a program. Essentially all typed programs are inherently over constrained.
Smalltalkers have been aware of these self imposed "type/isKindOf:" software design problems for many decades. In many ways "isKindOf:" must be treated with respect and used judiciciously since the results can be just as messy as any typed or static program. In a way some Smalltalkers treat "isKindOf:" with almost as much distain as most programmers treat "goto" statements. While it's clear that "goto" statements work - heck all of our high level languages fancy control structures that "replaced" goto statements are actually implemented with them at the lowest level of assembly language! - it's also clear from experience that we and our programs are better off without gotos. Class "type" meta data must be carefully used otherwise the program becomes brittle and usually entails more code than needed. However, isKindOf: has it's powerful uses, so I don't consider it as bad style automatically.
The take home point is that Smalltalk has had runtime meta data since the beginning and this meta data provides any and all the needed "type safety" and in addition provides capabilities simply not present and that are devoid in static and typed languages.
In a static and typed language the type declaration would be something like String anObject
. This would prevent the program from compiling if anything else was attempted to be placed into the variable "anObject". Right there the claimed benefit of "type safety" interfeers directly with the ability of a programmer to write and test their code in a dynamicly live and interactive system. Right there flexibility is lost!
Ok, for a moment let's assume that you don't want a variable to have anything other than a String and that you're ok with that constraint. A sequence such as anObject := 'hello world'
will assign the string 'hello world' into the variable anObject. Now it's a simple matter to use one of the tests from above at any later time to ensure that this variable is "type safe" by containing a String.
You also have the added flexibility to pre-test your assignment. For example:(someOtherObject isKindOf: String) ifTrue: [anObject := someOtherObject] ifFalse: [anObject := String new]
In this example you are pretesting the class "type" of the object to ensure that the variable has only a String placed into it.
In Smalltalk you are in total control of how and when to use "type safety" constraints (and their implicit limitations inherent in any constraint). This is where part of the power of Smalltalk comes from: by giving you control you have more power. Note that the limitations of type contraints are much more prelevant in static and typed languages and systems since you don't have a full meta programming language for the specification of the type constraints. Most often the type constrains are simplistic statements that limit the type of a variable to a specific type (or class or one of it's subclasses). So, static and typed languages and systems type systems really offer very simplistic type systems that don't offer true expressive power and control of your program.
There is another aspect that is very powerful that is lacking in static and typed languages and systems which is the fact that Smalltalk provides you with the expressive power of the full language for all class meta data programming! In the above examples you may have noticed that the "class/type tests" were used in conjunction with a two way branching "ifTrue:ifFalse:" conditional control statement. This demonstrates that meta programming in Smalltalk is fully integrated into the language. All meta programming is done with the same programming language as regular programming is done with. This is an earth shattering capability. It provides you with unprecedented control over what is happening in your program while it's running!
By no means are you limited to simply using "isKindOf:" or "isMemberOf:", you also have the simple yet powerful "class" message to access an objects class at anytime. [Note: there are also many other meta programming objects and messages available for use]. For example here we add the "valid classes of our choosing" to a Set instance and then either immediately or sometime later on we test the set with our target object to see if it's the type we want.
anObject := someObject
aSet := Set new.
aSet add: String.
aSet add: Symbol.
aSet add: AnObjectClassOfMyDesign.
aSet add: AnotherObjectClassOfMyDesign.
(aSet includes: anObject class) ifTrue: [...] ifFalse: [...].
In this following example we use a Dictionary (a.k.a. a hash table, a lookup table, or a map) to provide different "actions" based upon the "class/type' of the target object. (Note that blocks of code in Smalltalk are also objects. A block is any code that is surrounded with the square brackets: "[ ... ]" where "..." are ANY valid Smalltalk expressions or statements. Blocks can also take parameters. Blocks are yet another super powerful feature of Smalltalk.)
anObject := someObject
aTestDict := Dictionary new.
aTestDict at: String put: [...].
aTestDict at: Symbol put: [...].
aTestDict at: AnObjectClassOfMyDesignput: [...].
aTestDict at: AnotherObjectClassOfMyDesign put: [...].
anActionBlock := aTestDict at: anObject class ifAbsent: .
aResult := anActionBlock value: someObject.
As these examples clearly demonstrate we can basically do pretty much whatever we want that makes sense to for our program at runtime. Certainly it's easy to create spagetti code but that's always the case in ANY programming language. The key is teaching yourself when and how to access the full power of runtime meta programming. The key is learning effective style. A very important key is knowing when you need the limitations of "type constraints" in your program and when other techniques and object oriented programming styles would be better to use. As such it should be noted that the above are not necessarily presented as examples of "good smalltalk style" but are presented to prove once and for all that "type safety" has been in the pervue of Smalltalk since the beginning over twenty five years ago. These and other meta programming tools in the Smalltalk tool box go far beyond what's available and offered in static and typed programming languages such as C, Java, C++, C# and others. These "mainstream" languages are decades behind the times. Just think, what can you accomplish with the competive advantage of Smalltalk's dymanic capabilities that enable you to be decades ahead of your competition?
We have demonstrated some of the dynamic runtime power and capability of Smalltalk in this article. We have shown that Smalltalk offers just as much type safety as any static or typed program with an important and powerful difference, you - the programmer - are in total control not some language designer who insists on simplistic type safety constraints! This has important implications for what kinds of programs are possible in Smalltalk.
Give Smalltalk a try. Download one of the many versions of Smalltalk
and expand what you are able to do in your program. Join the dynamic meta programming revolution!
See Dynamic Runtime Type-Object-Class Inference
for follow up discussions.
1999-2010 by Smalltalk.org, All Rights Reserved.