Don Box: The underlying language feature (along with its
cousin, anonymous methods) do in fact rock though.
Let’s explore further.
How do you call a function in C?
name (parameters)
Now, how do you call a method in C++?
object.method(parameters)
The way the latter works under the covers is that an additional
parameter is typically passed, and bound to the name
this. Hold that thought.
Now, lets’s look at a few of the control structures in C#,
as they are typically used:
while (parameter) {block}
if (parameter) {block}
for (parameters) {block}
foreach (parameters) {block}
switch (parameter) {block}
lock (parameter) {block}
I’ve taken a few liberties with how I have named things to
emphasize similarities, but my key point is that from a simple
syntactic point of view, each of these statements look like a
procedure call statement, albeit with a funny “extra”
block parameter.
And, among these examples, the lock example feels a bit
strange. It feels like a bit of application specific
functionality creeping down into the language. Hold that
thought too.
Now, one final example to feed into this mix. I’ll
give a very simple C# example:
public class test {
public static void Main(string[] args) {
int[] list = new int[] {1,2,3,4,5,6,7,8,9,10};
int sum = 0;
foreach (int i in list) { sum = sum + i; }
System.Console.WriteLine(sum);
}
}
Now, I realize that this problem of solving the sum of a series
of consecutive integers can be reduced to a simple equation, but
dang it, remember that this is meant as an example. Bear with
me.
Now, let’s show how this can be implemented in Ruby:
list = [1,2,3,4,5,6,7,8,9,10]
sum = 0
list.each() {|i| sum = sum + i}
puts sum
Now, if you ignore the people who will tell you that in Ruby the
parenthesis are not required, or whisper in your ear
inject,
inject, inject, and if you ignore the extra pro-forma
baggage that C# requires; then you see that there is the
same core four statements involved in both implementations.
The third of which looks suspiciously like a procedure/method
call like thing — with an extra parameter.
Which, in Ruby, is exactly what it is.
In object oriented systems, there is a bit of mental judo going
on whereby you convert a system from imperative statements like
“print x” to a more message oriented “to: x;
message: go print yourself”. The same thing is going on
here. In Ruby, you are calling one method, and passing it a
block that it can chose to call as many, or as few, times as it
likes. The method can even chose to stash away the block for
later use.
The block itself can even be parameterized, as it is
above. In this example, the block expects one parameter,
which it names i.
One more interesting thing to note is that the block captures
its scope, i.e., it behaves like a closure. Again referencing
this example, the block directly accesses and modifies a value
named sum, something which is not visible to the
definition of the
Array.each
method.
How can this be useful? The lock example above is a
specific example whereby the language designers had enough
foresight to build a similar feature into the language. In
Ruby, such features need not be a part of the language, as you can
build your own.
You should be barred from talking about Ruby. In your own posts, it’s not a problem, but when others refer to your posts about Ruby, then all hell break loose. Excellent post anyways though :)
I think you may have just sold me on Ruby with “list.each() {|i| sum = sum + i}” ... not sure which I like more. The built in iterator and/or the easy implementation of the code block ...
Though I suppose if I wanted to be a pain I could gripe about it not being {|i| sum += i} ...
A lot of the attraction people seem to have to delegates, closures, or blocks is shorter syntax (most people accept that inner classes do much the same job). Also inner classes have some advantages: more than one method, extending a base class to use default implementations of methods, and that a single concept (class) is used. Therefore I suggest some syntax modification to reduce verbosity in Java:
1. Make new keyword optional
2. When only a single statement is present then class and method bodies don’t require {}, i.e. like if, for, etc.
3. When an abstract class or interface is extended and there is only one method to implement then the method visibility, return type, name, and argument types are not needed.
These syntax changes reduce:
textField.addActionListner( new ActionListener() {
public void actionPerformed( ActionEvent notUsed ) {
textArea.append( textField.getText() );
}
});
public class test {
public static void Main(string[] args) {
int[] list = new int[] {1,2,3,4,5,6,7,8,9,10};
int sum = 0;
Array.ForEach<int>(list, delegate (int i) { sum += i; });
System.Console.WriteLine(sum);
}
}
Notice the use of a closure being passed to Array.ForEach<T>. Yes, more verbose and type anal when compared to Ruby. But still quite nice.
I should also note how superior Haskell is for this same problem. Not necessarily an indication of the overall superiority of the language (although I might argue that, too), but you can whittle it down to one line:
Question: is C# 2.0 publicly downloadable from somewhere?
My recollection was that C# didn’t implement true closures — instead the delegate would have initially made a copy of the sum variable, and then operate against that copy. I presume that I am not remembering that correctly?
Sam: For sure, they’re up on the web. We just dropped our Beta2 release. I’m assuming you don’t want to deal with Visual Studio and all that. We do a horrible job advertising this, but you can certainly do barebones, cmd-line development... Just like grabbing the JDK and cooking with gas with javac.
That’s technically all you need. These are optional.
SDK (docs, additional utilities): [link]
Visual Studio C# Express ("free"/academic and hobbyist version): [link]
Regarding closures as implemented in C#: I was surprised at first, but yes--they do completely capture the enclosing lexical scope. There is some compiler magic to do the closure conversion of captured variables--especially with locals--like moving the captured local to a field of the closure object, or even a field of the class for the local’s method (if more than one closure refers to it). But at least all of the corner cases I’ve tested work properly.
Ildasm comes with the redist, and gives you a good decompiled view (in IL) into how it works. The code generated for this and the coroutines/iterator feature is very interesting.
Steven: Cool. I agree--Ruby is pretty awesome. So long as a language has 1st class closures and higher order functions, I think all is well in the world. The Haskell Standard Prelude just happens to come with a whole host of nifty libraries for recursive list processing--they could easily be implemented in Ruby. Foldl and foldr are sweet.
Joe: assuming that C# works as you say for this corner case, then color me impressed.
I really wanted to experiment to find the edge cases, enough so that I was willing to upgrade my version of WindowsInstaller. A GenuineCheck, a legitcheck, a reboot, and an EULA later, I am faced with an install that stalls while attempting to stop IIS Services. Two more attempts (each involving a reboot), and I’ve come to the conclusion that this is not for me.
All around me, people are making the switch — either to OSX or to some version of Linux. Perhaps it is time for me to join them.
In fact, squeak defines inject:into: like this in Collection:
inject: thisValue into: binaryBlock
"Accumulate a running value associated with evaluating the argument,
binaryBlock, with the current value of the argument, thisValue, and the
receiver as block arguments. For instance, to sum the numeric elements
of a collection, aCollection inject: 0 into: [:subTotal :next | subTotal +
next]."
| nextValue |
nextValue _ thisValue.
self do: [:each | nextValue _ binaryBlock value: nextValue value: each].
^nextValue
I got amazed by how similar ruby syntax was to Smalltalk. I did my biggest software project in Smalltalk (Digitalk’s, some years ago) and I’ve never been so productive as then, but I was younger... :-)
As Joe points out, you have full read/write access to the activation frame of the surrounding method (and instance).
I believe that Java has a feature that allows you to define anonymous inner classes and get read-only access to your activation frame. I don’t know whether that’s implemented using a copy or something more exotic.
As for your difficulty installing Whidbey, that blows. I’ll point the relevant folks to your blog and hopefully we can fix this - after all, that’s why we call them betas.
Don’s kicking butt over there with lots of experimentation with closures and iterators in C#. Sam has commented and seems to be impressed with C#'s new evolutionary direction. I am too. Inspired, I went back to a couple posts I did mid last year. I...
The Java implementation of inner classes is a copy of the local variable (which must be declared final), so for a primitive that is in effect read-only access. For an Object though the access you get depends upon the object, e.g. if it has set methods then you get write access. Also you can always package something that doesn’t have write access into an array, which does, and therefore give yourself write access. However, typically in Java you would do something like this:
final int[] list = { 1, 2, 3 };
class Summer { // declare inner class that reads list and sums it
int sum = 0;
Summer() { for ( final int elem : list ) sum += elem; }
}
System.out.println( new Summer().sum );
Functional programming in Java is normally done using a third party package, e.g. jga [link] (there are plenty of other functional programming packages). Therefore you wouldn’t typically hand code the loop or the inner class since these packages have this functionality.
Oh, if only we can make Sam Ruby a Ruby programmer... The Google Consolidation Factor (GCF) would be enormous.
What you mentioned about blocks is cool, but it’s just pretty syntax if you don’t look at what’s going on behind the scenes. A block is an anonymous bit of code, all wrapped up, that you can pass around as you wish. This is insanely useful when it comes to things like manipulating databases.
Db.open(foo, bar, baz) do |handle|
handle.do_something_dangerous()
end
Notice: no error handling there. Why? Because Db.open looks something like
def open(username, password, database)
begin
h = connect(database)
h.authenticate(username, password)
...
begin
h.begin_transaction
yield(h)
h.commit_transaction
rescue DBTransactionError
h.abort_transaction
end
rescue DBError
# Oops! DB did something bad
ensure
h.close
end
end
That “yield” bit is where your code gets called, and if things mess up the DB layer completely cleans up for you.
A simpler example of blocks deals with files:
File.open("foo.txt") do |f|
f.do_something()
end
Note: the file isn’t closed by the reader. When the block is done, the file is automagically closed behind the scenes. It isn’t closed when GC happens and the variable falls out of scope, it’s done as soon as the block ends.
final List< Integer > list = asList( 1, 2, 3 ); // create list
final Plus< Integer > sum = new Plus< Integer >( Integer.class ); // function to inject
// or
// final BinaryFunctor< Integer, Integer, Integer > sum = GenericParser.parse( "x + y", Integer.class, Integer.class, Integer.class ); // function to inject
final Accumulate< Integer > summer = new Accumulate< Integer >( sum ); // inject function
System.out.println( summer.fn( list.iterator() ) ); // sum the list
In my previous post , I talked about .NET 3.5 Extension Methods and ended by mentioning Ruby Blocks - because they are much admired. As one example in Ruby, one might output the sum an array of numbers as follows ......
A “Print” To the Console Because I write a lot of small console applications, I find myself typing ... Console.WriteLine("some text"); in C# again and again. I’ve always pined for the ability...
In my previous post , I talked about .NET 3.5 Extension Methods and ended by mentioning Ruby Blocks - because they are much admired. As one example in Ruby, one might output the sum of an array of numbers as follows ......
A “Print” To the Console Because I write a lot of small console applications, I find myself typing ... Console.WriteLine("some text"); in C# again and again. I’ve always pined for the ability...