Sunday, November 20, 2005
Code as Language
After reading some of Brian Marick's stuff I have been wondering if there were other projects on the web working to the same goal.
Guess what? If you can think it, on the internet you find it :-)
Here is a small review and lots of cut&paste, mainly from comp.lang.ruby..
From "Readability" inflation:
Excerpt I
Similarly, if you're used to:
f = lambda {|a,b| ... }
then after a while, you might find that so natural that you feel
"ready" for
Well, of course, it allows you to write more uniform code, transforming the block definiton into a tool to define new syntax.
Excerpt II
> def foo(a =>, b =>, c =>)
> obj = -> (a, b = 1){ block }
def foo(a:, b:, c:)
Yep, it does. Much better.
I used to think of named parameters (an Ada idiom, if I am not wrong) as a bureaucratic heritage from dying programming languages. These days I think they are fundamental to write readable programs. How else would you know the meaning of a parameter, without chasing words with the mouse to get tooltips to pop up?
Still, I think they should be optional. There is no point in saying:
plot_point x: x, y: y, color: chosen_color
since this would make perfect sense:
plot_point x, y, chosen_color
Excerpt III
Consider Microsoft's Monad's
get-childitem | sort-object extension | foreach { $_.filename}
vs Ruby's
get-childitem.sort_by{|child| child.extension}.map{|child| child.filename}
without adding any readability that I can see over the Microsoft version.
Must agree with Microsoft, just this time. The implicit result variable makes beautiful code possible.
Excerpt IV
> have one.
String contains "abc"
0..10 contains 5
1,2,3,4 contains 3
/^[a-z]*$/ includes "apple"
It would be nice if Array#=== was aliased to Array#include? So that
somearray === someval
Very nice, I'll check if it has been aliased in any ruby library
From Ruby Facets 0.6.2:
Excerpt V
Perhaps it would also be a nice idea to add Enumerable#count,
Kernel#with and Object.new with a template block?
Samples:
[1, 2, 3].count { |item| item > 1 } # => 2
with("foo") { reverse } # "oof"
obj # => "foo"
obj.reverse # => "bar"
This is the way I understood how 'with' would work:
s = "hello"
with(s) {
reverse!
capitalize!
I like the count, it reminds me of the COUNTIF in Excel. Actually I would rename it to count_if.
The 'with' is quite cool. How do they do it? I wonder how it is implemented.
I like to be able to make context explicit.
Excerpt VI
Thanks for that. Can I humbly suggest that Numeric#ago be changed to
Numeric#before? If we're trying to mimic English, you'd never say "10
days ago yesterday" in English, but you would say "10 days before
yesterday". So instead of making people call
10.days.ago( Time.now - 1.day )
they could call
10.days.before( Time.now - 1.day )
instead. And if Time.yesterday and Time.tomorrow had been defined, you
could simply call
10.days.before Time.yesterday
And maybe this would cause transitional issues, but it might be good to
redefine Numeric#ago to refer to a time relative to the current moment,
which is in line with what it means in English.
yesterday = 1.day.ago
last_monday = 8.days.ago
Similarly, Numeric#later could go the other way:
tomorrow = 1.day.later
next_tuesday = 6.days.later
And Numeric#after could add time to any arbitrary starting point:
very nice, I am impressed. great readibility.
I'll explore some more examples and possibly some libraries. I will also try to organize the material that I find in some categories.