Syntactical Sugar: once

It dawned on me that I do things like this a lot:

did_it = false
array.each do |element|
unless did_it
puts "This is the first element"
did_it = true
end
# Do other stuff
end

...Yes, I know there are other ways of accomplishing this, some of which may be far more succinct, but I prefer this one because it's clearest.

Still, everytime I do this, I wince. It seems pretty verbose for the simple procedure of doing something on the first element of a foreach loop.

It would be nice if someone could concoct the syntactic sugar to make that look like this:

array.each do |element|
once do
puts "This is the first element"
end
# Do other stuff
end

...Perhaps the "once" function should be named "on_the_first_time", but whatever floats your boat. I like shorter (unabbreviated) names.

All this needs, of course, is some way of remembering that this function has already been called. Something like this:

def once
yield unless &yield.has_already_been_called
end

However, how to reference (&) the block being called by yield is beyond my ken, as is the magic behind has_already_been_called.

If you have any ideas on how to make this work, I'd like to hear them.

It dawns on me that this could be slightly uglier and probably work... something along the lines of:

def once_for(name)
unless @@already_called.include?(name)
yield
@@already_called[name] = true
end
end

array.each do |element|
once_for(:some_unique_name) do
puts "This is the first element"
end
# Do other stuff
end

...Any thoughnuts?

1 comment:

Victor said...

I don't speak Ruby, but I think in Perl you could accomplish something similar with a combination of caller (to create a unique flag for each call context) and closures.

Or, you could subclass the array, and add a 'do_once' flag which would be modified by the 'each' function at the beginning and the end of the iteration.