In association with heise online

Laziness as a virtue

"Lazy" list evaluation is an extension that will particularly benefit programmers who are familiar with functional programming languages. It allows developers to use a highly compact syntax for the processing of loops and (infinite) collections, because temporary arrays will no longer required. For example,

require 'prime'

prime_array =
Prime.each do |value|
next if value % 4 != 3
prime_array << value
break if prime_array.size == 5

can be replaced with

' {|value| value % 4 == 3 }.take(5).to_a' 

What's really interesting apart from the syntax, however, is the fact that developers can chain the enumerators, as can be seen in the second case. Evaluation is no longer a direct process; instead, a "lazy" enumerator will return a reusable Enumerator::Lazy. The expression will only be evaluated once an actual value is returned. The resulting advantage is demonstrated in the following tests:

require 'test/unit'

include Test::Unit::Assertions

a = [1,2,3,4,5,6]

// Without lazy, the array will be processed in full.

assert_equal(4, { |x| x > 3 }.first)

// With lazy, processing will stop as soon as the first value
// that is larger than 3 has been found

assert_equal(4, { |x| x > 3 }.first)

Enumerator::Lazy implementations also exist for the popular map, flat_map, select, reject, grep, zip, take, take_while, drop, drop_while and cycle methods.

Despite the advantages of a more compact syntax and the chaining and processing of infinite collections, one issue shouldn't be left unmentioned: the processing speed may be reduced by a factor of about 4. The reason for this is that when enumerators are chained, partials results must remain in RAM as they will be used as parameters in subsequent processing.

Against hacking

Ruby 2.0 offers a new feature that is also available in various other programming languages: "keyword arguments", which are also called "named parameters". Previously, a similar behaviour could be implemented in Ruby via the workaround of submitting a hash when calling a method. If a developer wanted to use default values, these values were usually combined with the actual arguments via merge().

def config(opts={})
default_values = {ssl: true, timeout: 500}
opts = default_values.merge(opts)

#=> {:ssl=>true, :timeout=>500}

config :ssl => false, :timeout => 200
#=> {:ssl=>false, :timeout=>200}

The new feature makes this "hack" redundant. Developers can now directly state names in a method call, and default values can be given accordingly in the method declaration for these arguments. The following examples demonstrate these options.

def phrase(question: 'The answer to life the universe and everything',  answer: '42')
[question, answer]

#=> ["The answer to life the universe and everything", "42"]

phrase question: 'The answer'
#=> ["The answer", "42"]

phrase question: 'The answer', wrong_answer: '43'
#=> ArgumentError: unknown keyword: wrong_answer

Developers can also include optional parameters that are directly interpreted as hash values. To do so, ** must be inserted before the actual parameter. This will directly convert the optional parameter into a hash value, which can be quite handy.

def config(ssl: true, timeout: 500, **options)
[ssl, timeout, options]

#=> [true, 500, {}]

config ssl: false, timeout: 100, test_mode: true
#=> [false, 100, {:test_mode=>true}]

Finally, one more slightly cryptic example that involves the splat (*) operator which allows a list of values to be passed in as an array.

def config(*clients, ssl: true, timeout: 500, **options)
[clients, ssl, timeout, options]

#=> [ , true, 500, {}]

config 'foo', 'bar', ssl: false, timeout: 100, test_mode: true,
max_response: 50
#=> [["foo", "bar"], false, 100, {:test_mode=>true, :max_response=>50}]

Further options can be found in the test cases for "keyword arguments".

Next: This and that and conclusion

Print Version | Permalink:
  • Twitter
  • Facebook
  • submit to slashdot
  • StumbleUpon
  • submit to reddit

  • July's Community Calendar

The H Open

The H Security

The H Developer

The H Internet Toolkit