Loop Abstraction with Blocks
Bill Venners: Ruby supports blocks and closures. What are blocks and closures, and how are they used?
Yukihiro Matsumoto: Blocks are basically nameless functions. You may be familiar with the lambda from other languages like Lisp or Python. Basically, you can pass a nameless function to another function, and then that function can invoke the passed-in nameless function. For example, a function could perform iteration by passing one item at a time to the nameless function. This is a common style, called higher order function style, among languages that can handle functions as first class objects. Lisp does it. Python does it .Even C does it with function pointers. Many other languages do this style of programming. In Ruby, the difference is mainly a different kind of syntax for higher order functions. In other languages, you have to specify explicitly that a function can accept another function as an argument. But in Ruby, any method can be called with a block as an implicit argument. Inside the method, you can call the block using the yield keyword with a value.
Bill Venners: What is the benefit of blocks?
Yukihiro Matsumoto: Basically, blocks are designed for loop abstraction. The most basic usage of blocks is to let you define your own way for iterating over the items.
For example, if you have a list, sequence, vector, or array, you can iterate forward by using the method provided by the standard library. But what if you want to iterate backwards from the end to the beginning? In C, you have to set up four things: an index, a start value, an end comparison, and an increment. This is not good, because it reveals internal details of the list. We want to hide that logic. By using blocks, we can hide the loop logic inside the method or function. So for example by calling list.reverse_each , you can do a reverse iteration over the list without knowing how the list is implemented on the inside.
Bill Venners: I just pass in a block that's going to do whatever I want to do with each element, and it's up to the list to know how to go backwards. In other words, I pass as a block whatever code I would have put inside the for loop in C.
Yukihiro Matsumoto: Yes, and that also means you can define many ways to iterate. You could provide a forward way to iterate, a backward way, and so on. It's up to you. C# has an iterator, but it has just one iterator per class. In Ruby you can have an arbitrary number of iterators if you want. If you have a tree class, for example, which you think people will want to traverse depth first and breadth first, you can provide both kinds of traversal by providing two different methods.
Bill Venners: Let me see if I understand this. In Java, they abstract iteration with Iterators. A client can ask a Collection for an Iterator, for example. But the client must use a for loop that runs through and processes the items returned by the Iterator. Inside the for loop, I have "the code" that I want to perform on each item, so that for loop always shows up in the client code. With blocks, I don't call a method to get an Iterator back, I call a method and pass as a block "the code" I want to process each item of the iteration. Is the benefit of the block approach that it takes a little bit of code, the for loop, out of each client?
Yukihiro Matsumoto: The details of how to iterate should belong to the service provider class. The client should know as little as possible. That was the original purpose of blocks. In fact, in early versions of Ruby, the methods called with blocks were referred to as iterators, because they were designed to iterate. But in the history of Ruby, the role of blocks was later enhanced from loop abstraction to anything.
Bill Venners: For example...
Yukihiro Matsumoto: For example, we can create a closure out of a block. A closure is a nameless function the way it is done in Lisp. You can pass around a nameless function object, the closure, to another method to customize the behavior of the method. As another example, if you have a sort method to sort an array or list, you can pass a block to define how to compare the elements. This is not iteration. This is not a loop. But it is using blocks.
Using Closures
Bill Venners: What makes a block a closure?
Yukihiro Matsumoto: A closure object has code to run, the executable, and state around the code, the scope. So you capture the environment, namely the local variables, in the closure. As a result, you can refer to the local variables inside a closure. Even after the function has returned, and its local scope has been destroyed, the local variables remain in existence as part of the closure object. When no one refers to the closure anymore, it's garbage collected, and the local variables go away.
Bill Venners: So the local variables are basically being shared between the closure and the method? If the closure updates the variable, the method sees it. And if the method updates the variable, the closure sees it.
Yukihiro Matsumoto: Yes, local variables are shared between the closure and the method. It's a real closure. It's not just a copy.
Bill Venners: What is the benefit of a real closure? Once I make a block into an object, what can I do with it?
Yukihiro Matsumoto: You can reconvert a closure back into a block, so a closure can be used anywhere a block can be used. Often, closures are used to store the status of a block into an instance variable, because once you convert a block into a closure, it is an object that can by referenced by a variable. And of course closures can be used like they are used in other languages, such as passing around the object to customize behavior of methods. If you want to pass some code to customize a method, you can of course just pass a block. But if you want to pass the same code to more than two methods -- this is a very rare case, but if you really want to do that -- you can convert the block into a closure, and pass that same closure object to multiple methods.
Bill Venners: OK, but what is the benefit of having the context? The distinction that makes Ruby's closure a real closure is that it captures the context, the local variables and so on. What benefit do I get from having the context in addition to the code that I don't get by just being able to pass a chunk of code around as an object?
Yukihiro Matsumoto: Actually, to tell the truth, the first reason is to respect the history of Lisp. Lisp provided real closures, and I wanted to follow that.
Bill Venners: One difference I can see is that data is actually shared between the closure objects and the method. I imagine I could always pass any needed context data into a regular, non-closure, block as parameters, but then the block would just have a copy of the context, not the real thing. It's not sharing the context. Sharing is what's going on in a closure that's different from a plain old function object.
Yukihiro Matsumoto: Yes, and that sharing allows you to do some interesting code demos, but I think it's not that useful in the daily lives of programmers. It doesn't matter that much. The plain copy, like it's done in Java's inner classes for example, works in most cases. But in Ruby closures, I wanted to respect the Lisp culture.
分享到:
相关推荐
克隆存储库并导航到该存储库git clone https://github.com/matz3/ui5con17-custom-theme.gitcd ui5con17-custom-theme 签出ui5-tooling分支git checkout ui5-tooling 安装所有npm依赖项npm install用法服务器运行...
《无线通信中的快速时变信道》是一本深入探讨无线通信领域中信道均衡的经典著作。这本书详尽地阐述了在快速变化的无线环境中,如何有效地传输数据并保证通信质量的关键技术。快速时变信道是指无线通信信道的特性(如...
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
- 它由日本的程序员松本行弘(Matz)于1995年设计并开发。 - Ruby的设计哲学强调程序员的生产力和代码的可读性,它具有强大的类库支持,并且语法简洁明了。 2. **面向对象编程(OOP)** - Ruby是一种纯面向对象的...
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
它由Yukihiro "Matz" Matsumoto在1990年代末创建,设计目标是提高开发者的生产力,强调代码的可读性和简洁性。Ruby的语法受到了Smalltalk、Perl、Eiffel、Lisp和Python等语言的影响,旨在提供一种更人性化、更直观的...
JRuby是一种开源的、完全兼容MRI(Matz Ruby Interpreter)的Ruby解释器,由Java编写,能够充分利用JVM的优势,如多线程、垃圾回收和丰富的类库。它的目标是提供与标准Ruby解释器相同的语义,同时利用Java平台的高...
Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro "Matz" Matsumoto在1990年代末创建。它强调代码的简洁性和可读性,支持多种编程范式,包括面向对象、函数式、命令式和过程式编程。Ruby的核心特性包括垃圾...
Ruby 语言的发明人是日本人松本行弘(Matsumoto Yukihiro),大家亲切的称呼他"Matz"。 可能会出乎大家的意料,Ruby并不是一种近年来才诞生的语言,它的历史可以追溯到1993年,Ruby之父Matz开始对脚本语言感兴趣。在通过...
Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro "Matz" Matsumoto于1995年创建。它的设计目标是让编程变得更加简洁、优雅,强调代码的可读性和开发者的生产力。Ruby 1.9.1是该语言的一个重要版本,引入了...
它由日本的开发者松本行弘(Yukihiro "Matz" Matsumoto)在1995年创建。Ruby语言的设计目标是简单、自然,同时具有强大的功能。Ruby语言受到了Perl、Smalltalk、Eiffel、Ada以及Lisp等语言的启发。 Ruby的一些特点...
由日本开发者松本行弘(Yukihiro Matsumoto,也被称为Matz)在1993年创建。Ruby语言的设计哲学强调了简单和生产力,它融合了多种编程范式,包括面向对象、命令式、函数式和过程式编程。 Ruby的主要特点包括: 1. *...
Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro Matsumoto(Matz)在1995年创建。它强调代码的简洁性和可读性,推崇“编程是人与人之间的交流”,因此具有很高的开发效率。Ruby 1.8.6是该语言的一个早期稳定...
Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro "Matz" Matsumoto在1990年代末创建。它强调代码的简洁性和可读性,支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。RubyInstaller是Windows...
- **发展历程**:1993 年由 Yukihiro Matsumoto(Matz)创建。2004 年随 Ruby on Rails 框架的兴起而逐渐流行。 - **应用场景**:适用于 Web 开发、脚本编写、系统管理等多个领域。 - **开发环境**:可在 Windows、...
Ruby是一种面向对象的、动态类型的编程语言,由Yukihiro "Matz" Matsumoto在1995年创建。它以其简洁、优雅的语法和强大的元编程能力而闻名,被广泛应用于Web开发、脚本编写、自动化任务等领域。RubyInstaller是...
它最初由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto,社区中常被称为 Matz)在 20 世纪 90 年代中期设计并开发。 - **特点**: - **面向对象**:Ruby 是一种纯粹的面向对象语言,几乎所有的数据类型都...
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的元编程能力而闻名,被广泛应用于Web开发、系统管理、自动化任务以及各种工具的编写。在Linux...