CSC/ECE 517 Spring 2014/ch1 1w1l m: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
(→‎See Also: Added some links to resources I found helpful)
 
(11 intermediate revisions by 2 users not shown)
Line 4: Line 4:
=== Explanation of Closures ===
=== Explanation of Closures ===


Very simply, a closure is a function that can use a variable that was valid within the scope that the closure was defined, but need not be in-scope where the closure is called. A quick example is very illustrative.
====Blocks in Ruby====
A block is a segment of code that can be used as an argument for a method[http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/]. These segments of code may have their own initialized variables only able to be referenced locally in the block, much like in a method. Single line blocks are commonly encapsulated in curly braces after a method call, and multi-line blocks are between "do" and "end" statements. A block's code is not executed when it is encountered, but rather after all instances of the yield statement within the method.
 
<code>
=begin 
  Ruby Code blocks are chunks of code between braces or 
  between do- end that you can associate with method invocations 
=end 
def call_block 
  puts 'Start of method' 
  # you can call the block using the yield keyword 
  yield 
  yield 
  puts 'End of method' 
end 
# Code blocks may appear only in the source adjacent to a method call 
call_block {puts 'In the block'}
</code>
The above code outputs the following:
<code>
    >ruby p022codeblock.rb 
    Start of method 
    In the block 
    In the block 
    End of method 
    >Exit code: 0 
</code>
 
====So what's a closure?====
Very simply, a closure is a function that can use a variable that was valid within the scope that the closure was defined, but need not be in-scope where the closure is called.[https://www.princeton.edu/~achaney/tmve/wiki100k/docs/Closure_(computer_science).html] A quick example is very illustrative.


<code>
<code>
Line 27: Line 56:
=== Decorators ===
=== Decorators ===


Decorators are an interesting and powerful language feature that can be implemented elegantly with closures.
[https://wiki.python.org/moin/PythonDecorators Decorators] are an interesting and powerful language feature that can be implemented elegantly with closures.


<code>
<code>
Line 53: Line 82:
  Back from calling func
  Back from calling func
</code>
</code>


=== Command Pattern===
=== Command Pattern===
The command Pattern can be implemented using proc objects, which are the closure of an object
The [https://en.wikipedia.org/wiki/Command_pattern Command Pattern] can be implemented using proc objects, which are the closure of an object.


In the command pattern, commands for objects to be implemented are queued and can be executed at any time. Arguments are considered passed when the method is called.
In the Command Pattern, commands for objects to be implemented are queued and can be executed at any time. Arguments are considered passed when the method is called.


<code>
<code>
Line 74: Line 102:


===Strategy Pattern===
===Strategy Pattern===
The [http://www.codeproject.com/Articles/52807/Design-Patterns-Part-1-The-Strategy-Pattern Strategy Pattern] allows an algorithms behavior to be determined at runtime. It describes the definition of a family of interchangeable algorithm classes whose functionality is different for identically named methods.


<code>
<code>
 
  class Fighter
  class Report
   def initialize(&fighting_behavior)
  attr_reader :title, :text
    @finish_move = fighting_behavior
  attr_accessor :formatter
   def initialize(&formatter)
  @title = 'Monthly Report'
  @text = [ 'Things are going', 'really, really well.' ]
  @formatter = formatter
   end
   end
   def output_report
  @formatter.call( self )
   def finish_opponent
    @finish_move.call
   end
   end
  end
  end
 
boxer = Fighter.new { puts 'Left hook to the body!' }
boxer.finish_opponent #=> Left hook to the body!
 
mortal_kombat_warrior = Fighter.new { puts 'Blast him with a lighting bolt' }
mortal_kombat_warrior.finish_opponent #=> Blast him with a lighting bolt
 
mma = Fighter.new { puts 'Put you to sleep, Good Night!' }
mma.finish_opponent #=> Put you to sleep, Good Night!
 
lion = Fighter.new { puts 'Bites your head off' }
lion.finish_opponent #=> Bites your head off!
</code>
=== Function Factory ===
A version of the classic [http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Factory.html Factory Pattern], but for use with functions, can be implemented easily with the help of closures.
<code>
#!/usr/bin/env python
def status():
    """Returns the status of the system. Just a stub, for demo.
    :returns: Always returns True. Just a demo.
    """
    return True
def messenger_factory(messenger_type):
    """Builds very lightweight messenger functions.
    :param messenger_type: Currently supported types are human and wire.
    :type messenger_type: string
    :returns: Function that creates messages of the required format.
    """
    version = "Version 1.0"
    dynamic_status = status
    if messenger_type == "human":
        def human_messenger():
            """Messenger with a format that is human-readable.
            :returns: Human-readable string of status and version.
            """
            return "Status is {}. Version is {}".format(dynamic_status(), version)
        return human_messenger
    elif messenger_type == "wire":
        def wire_messenger():
            """Messenger with format that is ready to be put on the wire.
            :returns: JSON (dict) message with status and version.
            """
            return {"version": version, "status": dynamic_status()}
        return wire_messenger
    else:
        raise ValueError("Unexpected messenger type: {}".format(messenger_type))
human_messenger = messenger_factory("human")
wire_messenger = messenger_factory("wire")
print "Human: {}".format(human_messenger())
print "Wire: {}".format(wire_messenger())
</code>


HTML_FORMATTER = lambda do |context|
<code>
  puts('<html>')
[~517/wiki]$ chmod ug+x func_factory.py
  puts(' <head>')
[~517/wiki]$ ./func_factory.py
  puts(" <title>#{context.title}</title>")
Human: Status is True. Version is Version 1.0
  puts(' </head>')
Wire: {'status': True, 'version': 'Version 1.0'}
  puts(' <body>')
  context.text.each do |line|
  puts(" <p>#{line}</p>" )
  end
  puts(' </body>')
  puts(' </html>')
end
</code>
</code>


== See Also ==
== See Also ==
* [http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ Understanding Ruby Blocks, Procs and Lambdas]
* [https://en.wikipedia.org/wiki/Closure_(computer_programming) Closure (Computer Programming)]
* [https://en.wikipedia.org/wiki/Software_design_pattern Software Design Patterns]
* [http://joeybutler.net/ruby/what-is-a-closure What is a Closure?]
== References ==
== References ==
<references />
<references />

Latest revision as of 04:28, 24 February 2014

Design Patterns Involving Closures

Background

Explanation of Closures

Blocks in Ruby

A block is a segment of code that can be used as an argument for a method[1]. These segments of code may have their own initialized variables only able to be referenced locally in the block, much like in a method. Single line blocks are commonly encapsulated in curly braces after a method call, and multi-line blocks are between "do" and "end" statements. A block's code is not executed when it is encountered, but rather after all instances of the yield statement within the method.

=begin  
 Ruby Code blocks are chunks of code between braces or  
 between do- end that you can associate with method invocations  
=end  
def call_block  
 puts 'Start of method'  
 # you can call the block using the yield keyword  
 yield  
 yield  
 puts 'End of method'  
end  
# Code blocks may appear only in the source adjacent to a method call  
call_block {puts 'In the block'}

The above code outputs the following:

   >ruby p022codeblock.rb  
   Start of method  
   In the block  
   In the block  
   End of method  
   >Exit code: 0  

So what's a closure?

Very simply, a closure is a function that can use a variable that was valid within the scope that the closure was defined, but need not be in-scope where the closure is called.[2] A quick example is very illustrative.

def closure_builder(message="Default"):
    def closure():
        # Message is in-scope here
        print message
    return closure

# Build two functions
default_closure = closure_builder()
custom_closure = closure_builder("Custom")
del closure_builder

# Call the closures you built
default_closure()  # Amazingly, prints "Default"
custom_closure()  # Amazingly, prints "Custom"

Examples

Decorators

Decorators are an interesting and powerful language feature that can be implemented elegantly with closures.

#!/usr/bin/env python

def decorate(func):
    def decorated_func():
        print "About to call func"
        func()
        print "Back from calling func"
    return decorated_func

@decorate
def func_to_decorate():
    print "In func_to_decorate"

func_to_decorate()

[~517/wiki]$ chmod ug+x decorator.py
[~517/wiki]$ ./decorator.py
About to call func
In func_to_decorate
Back from calling func

Command Pattern

The Command Pattern can be implemented using proc objects, which are the closure of an object.

In the Command Pattern, commands for objects to be implemented are queued and can be executed at any time. Arguments are considered passed when the method is called.

count = 0

commands = []
(1..10).each do |i|
  commands << proc { count +=i }
end

puts "Count is initially #{count}"
commands.each { |cmd| cmd.call }
puts "Performed all commands. count is #{count}"

Strategy Pattern

The Strategy Pattern allows an algorithms behavior to be determined at runtime. It describes the definition of a family of interchangeable algorithm classes whose functionality is different for identically named methods.

class Fighter
 def initialize(&fighting_behavior)
   @finish_move = fighting_behavior
 end

 def finish_opponent
   @finish_move.call
 end
end
 
boxer = Fighter.new { puts 'Left hook to the body!' }
boxer.finish_opponent #=> Left hook to the body!
 
mortal_kombat_warrior = Fighter.new { puts 'Blast him with a lighting bolt' }
mortal_kombat_warrior.finish_opponent #=> Blast him with a lighting bolt
 
mma = Fighter.new { puts 'Put you to sleep, Good Night!' }
mma.finish_opponent #=> Put you to sleep, Good Night!
 
lion = Fighter.new { puts 'Bites your head off' }
lion.finish_opponent #=> Bites your head off!

Function Factory

A version of the classic Factory Pattern, but for use with functions, can be implemented easily with the help of closures.

#!/usr/bin/env python

def status():
    """Returns the status of the system. Just a stub, for demo.

    :returns: Always returns True. Just a demo.

    """
    return True

def messenger_factory(messenger_type):
    """Builds very lightweight messenger functions.

    :param messenger_type: Currently supported types are human and wire.
    :type messenger_type: string
    :returns: Function that creates messages of the required format.

    """
    version = "Version 1.0"
    dynamic_status = status
    if messenger_type == "human":
        def human_messenger():
            """Messenger with a format that is human-readable.

            :returns: Human-readable string of status and version.

            """
            return "Status is {}. Version is {}".format(dynamic_status(), version)
        return human_messenger
    elif messenger_type == "wire":
        def wire_messenger():
            """Messenger with format that is ready to be put on the wire.

            :returns: JSON (dict) message with status and version.

            """
            return {"version": version, "status": dynamic_status()}
        return wire_messenger
    else:
        raise ValueError("Unexpected messenger type: {}".format(messenger_type))

human_messenger = messenger_factory("human")
wire_messenger = messenger_factory("wire")

print "Human: {}".format(human_messenger())
print "Wire: {}".format(wire_messenger())

[~517/wiki]$ chmod ug+x func_factory.py
[~517/wiki]$ ./func_factory.py
Human: Status is True. Version is Version 1.0
Wire: {'status': True, 'version': 'Version 1.0'}

See Also

References

<references />