

The Building Blocks of Ruby - wycats
http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/

======
kscaldef
I don't feel like any of these are particularly compelling examples,
particularly if you are familiar with more languages beyond Java and Python
which are used for comparison in the article.

In both the file handling and mutex example, blocks seem to be serving as a
substitute for proper lexically scoped variables. In Perl, for example, we
would use a lexically-scoped file handle to ensure the file is closed when the
variable goes out of scope. The same technique is the standard way of
implementing mutexes in C++.

As for respond_to, I've never understood how it wasn't just a baroque
rewriting of a case-statement, but perhaps someone can enlighten me as to why
blocks are superior in this situation.

~~~
wedesoft
Blocks are objects themselves and they preserve their access to the local
variable scope (i.e. they are "lexical closures"). This allows you to write
control structures yourself. E.g. if-statement:

    
    
      def my_if( cond )
        if cond
          yield
        end
      end
      x = 3
      my_if x < 5 do
        puts "#{x} is lower than 5"
      end
      # prints '3 is lower than 5'
    

Unfortunately the syntax for a control structure accepting more than one block
is less elegant. But you don't need to compromise on the semantics:

    
    
      def my_if_else( cond, a, b )
        if cond
          a.call
        else
          b.call
        end
      end
      x = 2
      my_if_else( x < 0, proc do
        puts "#{x} is lower than zero"
      end, proc do
        puts "#{x} is greater or equal zero"
      end )
      # prints '2 is greater or equal zero'

~~~
kscaldef
Sure and I understand all that. My comment was just that the examples in the
article are perhaps not the best ones to use because they are simply
replicating what other languages do with lexically scoped variables, and users
of those languages view the lack of such as a deficiency of Ruby.

~~~
swannodette
How does a lexically scoped variable close the file? I couldn't find any
documentation about this while Google searching. Is this a real language
feature where you can specify what happens to a variable when it goes out of
scope?

In other words, is it a baked-in convenience or a real extensible abstraction?

~~~
wedesoft

      #include <fstream>
      using namespace std;
      int main()
      {
        {
          fstream f( "test.txt", ios::out );
          f << "Hello" << endl;
        } // File gets closed
        // ...
        return 0;
      }

~~~
weaksauce
I haven't done C++ in a while but is it possible to allocate an fstream object
on the heap instead of the stack? If so and you do not explicitly call delete
on it then will it still close the file when going out of scope?

Something like:

    
    
      #include <fstream>
      using namespace std;
      int main()
      {
        {
          fstream *f = new fstream( "test.txt", ios::out );
          f << "Hello" << endl;
        } // memory leak and non closed file.
        // ...
        return 0;
      }

~~~
scott_s
You can allocate an fstream (or any) object on the heap, and if you do not
explicitly call delete it will not close the file. Resource-acquisition-is-
object-instantiation (RAIOI) is a common C++ idiom, and it only works on stack
variables.

~~~
altano
It only works with stack variables, but you can wrap the construction and
destruction of anything, including heap-allocated objects, with a stack
variable. You tie the allocation of the heap object to the constructor of the
stack variable, and the reverse for de-allocation/destructor.

The premise of all this is that the construction and destruction of stack
variables both happen at well known times and are guaranteed to occur.

------
j_baker
I've always felt that blocks were Ruby's gimmick. They're neat, and I'd like
to have them in Python. But I get the feeling that this is just a bikeshed
issue. People show them off because they're easy to understand. There's
absolutely _nothing_ wrong with that.

However, I get the feeling that they're not Ruby's strongest feature. Python's
coolest features (metaclasses, descriptors, and other things) wouldn't make
sense if you'd just read a blog post on them. I suspect Ruby is the same way.

~~~
bad_user
It's not a bike-shed issue. Surely the other features are great, and Python
has lots of powerful abstractions.

But once you have closures with a light-weight syntax, as Ruby has, the APIs
start to look a lot more different.

For example, take this example ...

    
    
        v = [ x for x in collection if x % 2 == 0 ]
        for item in v:
            print item
    

In Ruby the equivalent would be ...

    
    
        collection.find_all{|x| x % 2 == 0}.each do |item|
            puts item
        end
    

Yes, the Python example is elegant, but Ruby doesn't need extra baked-in
features like list-comprehensions. It doesn't need a bunch of other features
as well, like generators, or generator expressions, or with statements.

There are a lot of PEPs in Python that cover use-cases for Ruby's blocks,
trouble is there are still use-cases that aren't covered.

Guido is partially right though ... adding blocks in Python wouldn't be
pythonic because blocks wouldn't be orthogonal with lots of other Python
features. They should've been added from the start, and now it's kind of late.

------
tptacek
_pedantic:_

Digest::MD5.digest(x), not Digest::MD5.hexdigest(x). If humans aren't reading
it, don't convert it to hex.

------
subwindow
Blocks are also an extremely powerful tool when it comes to building DSLs, and
if done correctly are a great alternative to complicated options
files/hashes/etc. Rails' routes and config/intializer come into mind.

~~~
chromatic
> _Blocks are also an extremely powerful tool when it comes to building
> DSLs..._

I can't read this as anything more insightful than _functions are also an
extremely powerful tool when it comes to building APIs_. I first used Ruby in
2000. What am I missing?

~~~
Vitaly
ruby block syntax is clean, elegant and nest-able which allows creating good
looking DSLs.

    
    
        foo do
          bar do
            ..
          end
          baz 123
        end
    

now try to do the same with some other language which supports something-kind-
of-like-ruby-blocks but with a different syntax. it will not look nearly as
good, so in those languages instead of creating DSL people usually implement
some kind of config file format instead. or just use XML :)

if you'd have to use 'lambda' to define a block for example, it would make a
much worse DSL with lots of extra syntax noise.

~~~
chromatic
The lack of punctuation characters makes this a DSL and not bog-standard Ruby
code?

> ... instead of creating DSL people usually implement some kind of config
> file format instead. or just use XML.

Writing a grammar or a parser means you _haven't_ created a DSL?

Unless by "DSL" you mean "Ruby syntax and Ruby semantics with symbol names
chosen by the programmer", I have no idea what you mean by "DSL".

~~~
jimbokun
How about this:

Ruby's syntactic flexibility and semantic model mean that many cases handled
by a change to the language spec or delegating to another language (XML config
files, for example) can be cleanly handled in Ruby itself. The end result is
often something that looks like a little language for a specific task, such as
Rake, Rails, etc. (I'm not a Ruby programmer, so I hope those are good
examples.)

So with Ruby, there are very few cases where writing a custom grammar or
parser is necessary. Ruby's flexibility gives you the ability to do things
that might require a custom grammar or parser in other languages.

~~~
draegtun
However even Jim Weirich doesn't like Rake being called a "DSL".

I think Piers Cawley was dead on by calling things like this a _Pidgin_

refs:

* <http://www.infoq.com/interviews/jim-weirich-discusses-rake>

* <http://www.bofh.org.uk/2007/08/08/domain-specific-pidgin>

------
adelevie
Yehuda Katz is always able to remind me that there is so much Ruby I don't
know.

