Thu, Mar 29, 2007, 8:07pm F-Script Style Thoughts
Programming » F-Script
(Last updated: Fri, Apr 6, 2007, 2:49pm)
S
ome thoughts on yesterday's experiment about F-Script in general.

I'm very happy with the power of the language, the speed, Objective-C class access, the class browser, and the interactive shell. That said, it is clear that the code I wrote today, which is much better than yesterday's code, F-Script is about on a par with Ruby for readability, imho. By which I mean, it's a bit harder to see what's going on than in a language like Python, or even (clean) Objective-C. One must impose a certain amount of self-restraint then, especially if you're on a project with others.

Update 3/30: A much better version was produced here.



I'm going to quote a bit from the code on the test page to think over some things. I'll start with the block that adds line numbers:
( fscript )
  1 codeWithLineNumbers := [ :line :number |
2 (number<10 ifTrue:[' '] ifFalse:['']) ++ (number stringValue) ++
3 ' ' ++ line ++ '\n'. ].
4
5 code := (codeWithLineNumbers value:@codeLines value:
6 @((codeLines count) iota + 1)) \ #++.

This is fairly elegant code with my only complain about blocks in F-Script, the use of "value:value:…" method names. I would have been much happier (though others might not be) having to write the argument names:
( fscript )
  1 code := (codeWithLineNumbers line:@codeLines number:
2 @((codeLines count) iota + 1)) \ #++.

This is also more in the spirit of Objective-C to be so explicit with the method names. I'm sure there's a very good reason it's not done this way, but I'm just commenting from a programmer's angle here.



Ok, next is the thorny issue of where to apply some methods in order to make the code's intent clear. I originally had written:
( fscript )
  1 rows := [ :i | |y highlight|
2 y := i raisedTo:2.5.
3 highlight := (y=(y intValue) ifTrue:[' class="int"'] ifFalse:['']).
4 '<tr class="data"><td' ++ highlight ++ '>' ++ (i stringValue) ++ '</td>' ++
5 '<td' ++ highlight ++ '>' ++ (y stringValue) ++ '</td></tr>'. ] value:@(45 iota).
6
7 (ROWS replaceWithString:(rows \ #++) inString:template). "used later on in the script"

but because the range of values (45 iota) shouldn't be so coupled to the rows block itself, and it's simply hard to see the "value:" call at the end of the block, even with a variation like:
( fscript )
  1 rows := [ :i | |y highlight|
2 y := i raisedTo:2.5.
3 highlight := (y=(y intValue) ifTrue:[' class="int"'] ifFalse:['']).
4 '<tr class="data"><td' ++ highlight ++ '>' ++ (i stringValue) ++ '</td>' ++
5 '<td' ++ highlight ++ '>' ++ (y stringValue) ++ '</td></tr>'.
6 ] value:@(45 iota).

I ended up pushing the value: method to further down, though it then has the disadvantage of making the last line much less readable:
( fscript )
  1 rows := [ :i | |y highlight|
2 y := i raisedTo:2.5.
3 highlight := (y=(y intValue) ifTrue:[' class="int"'] ifFalse:['']).
4 '<tr class="data"><td' ++ highlight ++ '>' ++ (i stringValue) ++ '</td>' ++
5 '<td' ++ highlight ++ '>' ++ (y stringValue) ++ '</td></tr>'. ].
6
7 (ROWS replaceWithString:((rows value:@(45 iota)) \ #++) inString:template).

but it's at least better than the 1st attempt. I know, it's probably a good reason to use an intermediate variable for clarity, but I'll just have to see how my F-Script coding style evolves on this point. I'd rather not introduce too many intermediate variables if they're not needed elsewhere.



I'll stop there for now. It's clear that F-Script has a look all its own, not one borrowed heavily from Objective-C or Smalltalk. If anything, I'd expect Ruby coders to be at home with it the quickest.

Leave a comment