You can download F-Script 2.1 now (for Mac OS X 10.6 or later).
The main new feature in this version is support for adding methods to existing classes. This is similar to Objective-C categories, but works dynamically at run-time. This is quite useful for prototyping stuff and experimenting with new designs, as well as for making object-oriented frameworks developed independently work together. Besides, it is a natural extension of the ability to define Cocoa classes directly in F-Script and lets you write a bigger part of your application code in F-Script, should you want to.
You can teach new tricks to any class registered in the Objective-C runtime, regardless of its original implementation language (Objective-C, F-Script or other). The syntax is straightforward: class name followed by new methods inside a pair of curly braces. For example, here is how we can add a print method the NSObject class:
NSObject
{
- (void)print
{
"Print the receiver's description on standard output."
stdout print:self description
}
}
Of course, this also works for class methods. For example, the following code adds a pi method to the NSNumber class:
NSNumber
{
+ pi
{
^ 3.141592653589793
}
}
The following example, a little bit more sophisticated, adds some common Smalltalk collection methods (namely collect:, inject:into:, groupedBy: and select:) to the NSArray class:
NSArray
{
- collect:transformer
{
"Answer a new NSArray constructed by gathering the results of
evaluating transformer (a block with one parameter) with each
element of the receiver."
^ transformer value:@self
}
- groupedBy:criteria
{
"Answer an NSDictionary whose keys are the result of evaluating
criteria (a block with one parameter) for all elements in the
collection, and the value for each key is the collection of
elements that evaluated to that key. For example
{'Hello', 'guys', 'I', 'enjoy', 'programming', 'with', 'style'}
groupedBy:#length
returns a dictionary with the following key/value associations:
1 -> {'I'},
4 -> {'guys', 'with'},
5 -> {'hello', 'enjoy', 'style'},
11 -> {'programming'}"
| result |
result := #{}.
self do:[:each|
| key group |
key := criteria value:each.
group := result at:key.
group == nil ifTrue:
[
group := {}.
result at:key put:group.
].
group addObject:each.
].
^ result
}
- inject:initialValue into:operation
{
"Answer the final result of evaluating operation (a block with
two parameters) using the previous evaluation result and each
element of the receiver as the parameters. The first evaluation
of operation is performed with initialValue as the first
parameter, and the first element of the receiver as the second
parameter. For instance, to sum the numeric elements of an
array, use:
anArray inject:0 into:#+"
| nextValue |
nextValue := initialValue.
self do:[:each|
nextValue := operation value:nextValue value:each
].
^ nextValue
}
- select:discriminator
{
"Answer a new NSArray which contains the elements in the
receiver which cause discriminator (a block with one parameter)
to evaluate to true. For each element of the receiver,
discriminator is evaluated with the element as the parameter.
Each element which causes discriminator to evaluate to true is
added to the new array."
^ self where:(discriminator value:@self)
}
}
Share and enjoy!