“关闭是穷人的目标,反之亦然” - 这是什么意思?

发布于 2024-08-26 08:24:20 字数 501 浏览 4 评论 0原文

闭包是穷人的对象,反之亦然。

我在 许多地点网络(包括SO),但我不太明白它的意思。有人可以解释一下它的确切含义吗?

如果可能,请在您的答案中包含示例。

Closures are poor man's objects and vice versa.

I have seen this statement at many places on the web (including SO) but I don't quite understand what it means. Could someone please explain what it exactly means?

If possible, please include examples in your answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

挽清梦 2024-09-02 08:24:20

对象是穷人的闭包。

考虑Java。 Java 是一种面向对象的编程语言,没有对真正的词法闭包的语言级别支持。作为一种解决方法,Java 程序员使用匿名内部类来关闭词法范围内可用的变量(前提是它们是final)。从这个意义上说,对象是穷人的封闭物。

闭包是穷人的对象。

考虑一下哈斯克尔。 Haskell 是一种函数式语言,没有对真实对象的语言级别支持。然而,它们可以使用闭包进行建模,如 Oleg Kiselyov 和 Ralf Lammel 的这篇优秀论文中所述。从这个意义上说,闭包是穷人的对象。


如果您有面向对象的背景,您可能会发现用对象来思考更自然,因此可能将它们视为比闭包更基本的概念。如果您有 FP 背景,您可能会发现闭包的思考更自然,因此可能将它们视为比对象更基本的概念。

这个故事的寓意是,闭包和对象是可以彼此表达的想法,并且没有一个比另一个更基本。这就是正在考虑的声明的全部内容。

在哲学中,这被称为模型依赖现实主义

Objects are poor man's closures.

Consider Java. Java is an object-oriented programming language with no language level support for real lexical closures. As a work-around Java programmers use anonymous inner classes that can close over the variables available in lexical scope (provided they're final). In this sense, objects are poor man's closures.

Closures are poor man's objects.

Consider Haskell. Haskell is a functional language with no language level support for real objects. However they can be modeled using closures, as described in this excellent paper by Oleg Kiselyov and Ralf Lammel. In this sense, closures are poor man's objects.


If you come from an OO background, you'll probably find thinking in terms of objects more natural, and may therefore think of them as a more fundamental concept than closures. If you come from a FP background, you might find thinking in terms of closures more natural, and may therefore think of them as a more fundamental concept than objects.

Moral of the story is that closures and objects are ideas that are expressible in terms of each other, and none is more fundamental than the other. That's all there is to the statement under consideration.

In philosophy, this is referred to as model dependent realism.

温柔少女心 2024-09-02 08:24:20

要点是闭包和对象实现相同的目标:将数据和/或功能封装在单个逻辑单元中。

例如,您可以创建一个代表狗的 Python 类,如下所示:

class Dog(object):
    def __init__(self):
        self.breed = "Beagle"
        self.height = 12
        self.weight = 15
        self.age = 1
    def feed(self, amount):
        self.weight += amount / 5.0
    def grow(self):
        self.weight += 2
        self.height += .25
    def bark(self):
        print "Bark!"

然后我将该类实例化为对象

>>> Shaggy = Dog()

Shaggy 对象具有内置数据和功能。当我调用 Shaggy.feed(5),他增加了一磅。该磅存储在作为对象的属性存储的变量中,这或多或少意味着它位于对象的内部范围内。

如果我正在编写一些 Javascript,我会做类似的事情:

var Shaggy = function() {
    var breed = "Beagle";
    var height = 12;
    var weight = 15;
    var age = 1;
    return {
        feed : function(){
            weight += amount / 5.0;
        },
        grow : function(){
            weight += 2;
            height += .25;
        },
        bark : function(){
            window.alert("Bark!");
        },
        stats : function(){
            window.alert(breed "," height "," weight "," age);
        }
    }
}();

在这里,我不是在对象内创建作用域,而是在函数内创建作用域,然后调用该函数。该函数返回一个由一些函数组成的 JavaScript 对象。由于这些函数访问在本地范围内分配的数据,因此不会回收内存,从而允许您通过闭包提供的接口继续使用它们。

The point is that closures and objects accomplish the same goal: encapsulation of data and/or functionality in a single, logical unit.

For example, you might make a Python class that represents a dog like this:

class Dog(object):
    def __init__(self):
        self.breed = "Beagle"
        self.height = 12
        self.weight = 15
        self.age = 1
    def feed(self, amount):
        self.weight += amount / 5.0
    def grow(self):
        self.weight += 2
        self.height += .25
    def bark(self):
        print "Bark!"

And then I instantiate the class as an object

>>> Shaggy = Dog()

The Shaggy object has data and functionality built in. When I call Shaggy.feed(5), he gains a pound. That pound is stored in variable that's stored as an attribute of the object, which more or less means that it's in the objects internal scope.

If I was coding some Javascript, I'd do something similar:

var Shaggy = function() {
    var breed = "Beagle";
    var height = 12;
    var weight = 15;
    var age = 1;
    return {
        feed : function(){
            weight += amount / 5.0;
        },
        grow : function(){
            weight += 2;
            height += .25;
        },
        bark : function(){
            window.alert("Bark!");
        },
        stats : function(){
            window.alert(breed "," height "," weight "," age);
        }
    }
}();

Here, instead of creating a scope within an object, I've created a scope within a function and then called that function. The function returns a JavaScript object composed of some functions. Because those functions access data that was allocated in the local scope, the memory isn't reclaimed, allowing you to continue to use them through the interface provided by the closure.

你的笑 2024-09-02 08:24:20

最简单的对象只是状态和在该状态上运行的函数的集合。闭包也是状态和对该状态进行操作的函数的集合。

假设我调用了一个需要回调的函数。在这个回调中,我需要对函数调用之前已知的某些状态进行操作。我可以创建一个体现此状态(“字段”)并包含作为回调执行的成员函数(“方法”)的对象。或者,我可以采取快速而简单的(“穷人的”)路线并创建一个关闭。

作为对象:

class CallbackState{
    object state;

    public CallbackState(object state){this.state = state;}

    public void Callback(){
        // do something with state
    }
}

void Foo(){
    object state = GenerateState();
    CallbackState callback = new CallbackState(state);
    PerformOperation(callback.Callback);
}

这是伪 C#,但在概念上与其他 OO 语言类似。正如您所看到的,回调类涉及大量样板来管理状态。使用闭包会更简单:

void Foo(){
    object state = GenerateState();
    PerformOperation(()=>{/*do something with state*/});
}

这是一个 lambda(同样,在 C# 语法中,但这个概念在支持闭包的其他语言中类似),它为我们提供了类的所有功能,而无需编写、使用和维护一个单独的类。

您还会听到这样的推论:“对象是穷人的终结”。如果我不能或不会利用闭包,那么我就被迫使用对象来完成他们的工作,就像我的第一个例子一样。尽管对象提供了更多功能,但出于已经陈述的原因,在闭包起作用的情况下,闭包通常是更好的选择。

因此,一个没有对象的穷人通常可以使用闭包完成工作,而一个没有闭包的穷人可以使用对象完成工作。富人两者兼备,并在每项工作中使用正确的一种。

An object, at its simplest, is just a collection of state and functions that operate on that state. A closure is also a collection of state and a function that operates on that state.

Let's say I call a function that takes a callback. In this callback, I need to operate on some state known before the function call. I can create an object that embodies this state ("fields") and contains a member function ("method") that performs as the callback. Or, I could take the quick and easy ("poor man's") route and create a closure.

As an object:

class CallbackState{
    object state;

    public CallbackState(object state){this.state = state;}

    public void Callback(){
        // do something with state
    }
}

void Foo(){
    object state = GenerateState();
    CallbackState callback = new CallbackState(state);
    PerformOperation(callback.Callback);
}

This is pseudo-C#, but is similar in concept to other OO languages. As you can see, there's a fair amount of boilerplate involved with the callback class to manage the state. This would be much simpler using a closure:

void Foo(){
    object state = GenerateState();
    PerformOperation(()=>{/*do something with state*/});
}

This is a lambda (again, in C# syntax, but the concept is similar in other languages that support closures) that gives us all the capabilities of the class, without having to write, use, and maintain a separate class.

You'll also hear the corollary: "objects are a poor man's closure". If I can't or won't take advantage of closures, then I am forced to do their work using objects, as in my first example. Although objects provide more functionality, closures are often a better choice where a closure will work, for the reasons already stated.

Hence, a poor man without objects can often get the job done with closures, and a poor man without closures can get the job done using objects. A rich man has both and uses the right one for each job.

孤独岁月 2024-09-02 08:24:20

编辑:问题的标题不包括“反之亦然”,所以我会尽量不假设提问者的意图。

两个常见的阵营是函数式语言和命令式语言。两者都是可以以不同方式完成类似任务并关注不同问题的工具。

闭包是穷人的对象。

对象是穷人的闭包。

单独而言,每一个陈述通常都意味着作者有某种偏见,无论怎样,通常植根于他们对一种语言或一类语言与对另一种语言或语言的不适。如果没有偏见,他们可能会受到一种环境或另一种环境的限制。我读过的作者说这类事情通常是狂热者、纯粹主义者或语言宗教类型。如果可能的话,我会避免使用宗教类型的语言。

闭包是穷人的对象。对象是穷人的闭包。

其作者是一位“实用主义者”,而且也非常聪明。这意味着作者欣赏这两种观点,并且欣赏它们在概念上是相同的。这就是我的同类。

EDITED: The title of the question does not include "vice versa" so I'll try not to assume the asker's intent.

The two common camps are functional vs imperative languages. Both are tools that can accomplish similar tasks in different ways with different sets of concerns.

Closures are poor man's objects.

Objects are poor man's closures.

Individually, each statement usually means the author has a some bias, one way or another, usually rooted in their comfort with one language or class of language vs discomfort with another. If not bias, they may be constrained with one environment or the other. The authors I read that say this sort of thing are usually the zealot, purist or language religious types. I avoid the language religious types if possible.

Closures are poor man's objects. Objects are poor man's closures.

The author of that is a "pragmatist" and also pretty clever. It means the author appreciates both points of view and appreciates they are conceptually one and the same. This is my sort of fellow.

难理解 2024-09-02 08:24:20

糖分就这么多,就像封闭物将匿名物体隐藏在裙子下一样。

Just so much sugar, as closures hide anonymous objects under their skirts.

病女 2024-09-02 08:24:20

“对象是穷人的闭包”不仅仅是某种理论上等价的陈述——它是一个常见的 Java 习惯用法。使用匿名类来包装捕获当前状态的函数是很常见的。它的使用方式如下:

public void foo() {
    final String message = "Hey ma, I'm closed over!";
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            System.out.println(message);
        }
    });
}

这甚至看起来很像另一种语言中使用闭包的等效代码。例如,使用 Objective-C 块(因为 Objective-C 与 Java 相当相似):

void foo() {
    NSString *message = @"Hey ma, I'm closed over!";
    [[NSOperationQueue currentQueue] addOperationWithBlock:^{
        printf("%s\n", [message UTF8String]);
    }];
}

唯一真正的区别是功能被包装在 Java 版本中的 new Runnable() 匿名类实例中。

"Objects are a poor man's closures" isn't just a statement of some theoretical equivalence — it's a common Java idiom. It's very common to use anonymous classes to wrap up a function that captures the current state. Here's how it's used:

public void foo() {
    final String message = "Hey ma, I'm closed over!";
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            System.out.println(message);
        }
    });
}

This even looks a lot like the equivalent code using a closure in another language. For example, using Objective-C blocks (since Objective-C is reasonably similar to Java):

void foo() {
    NSString *message = @"Hey ma, I'm closed over!";
    [[NSOperationQueue currentQueue] addOperationWithBlock:^{
        printf("%s\n", [message UTF8String]);
    }];
}

The only real difference is that the functionality is wrapped in the new Runnable() anonymous class instance in the Java version.

桃酥萝莉 2024-09-02 08:24:20

对象可以用作闭包的替代品,这很容易理解,您只需将捕获的状态放入对象中并将调用作为方法即可。事实上,例如,C++ lambda 闭包是作为对象实现的(对于 C++ 来说,这有点棘手,因为该语言不提供垃圾收集,并且由于捕获的上下文的生命周期,具有可变共享状态的真正闭包很难正确实现)。

相反的情况(闭包可以用作对象)较少被观察到,但在我看来,它是一种非常强大的技术......例如(Python)

def P2d(x, y):
    def f(cmd, *args):
        nonlocal x, y
        if cmd == "x": return x
        if cmd == "y": return y
        if cmd == "set-x": x = args[0]
        if cmd == "set-y": y = args[0]
    return f

函数 P2d 返回一个捕获 的两个值的闭包>xy。然后,闭包提供使用命令读取和写入它们的访问权限。例如

p = P2d(10, 20)
p("x") # --> 10
p("set-x", 99)
p("x") # --> 99

,闭包的行为就像一个对象;此外,由于任何访问都是通过命令接口进行的,因此很容易实现委托、继承、计算属性等。

这本好书“Let Over Lambda” 使用 Lisp 作为语言构建了这个想法,但是任何支持闭包的语言都可以使用这种技术(在 Lisp 中,优点是您还可以使用宏来弯曲语法并读取宏以提高可用性并自动生成所有样板代码)。这本书的标题正是关于这个......一个let包装一个lambda

(defun p2d (x y)
   (let ((x x) (y y))
     (lambda (cmd &rest args)
       (cond
          ((eq cmd 'x) x)
          ((eq cmd 'y) y)
          ((eq cmd 'set-x) (setq x (first args)))
          ((eq cmd 'set-y) (setq y (first args)))))))

实际上我不确定我是否同意这种方法中的“可怜”形容词。

That objects can be used as a replacement for closures is quite easy to understand, you just place the captured state in the object and the calling as a method. Indeed for example C++ lambda closures are implemented as objects (things are sort of tricky for C++ because the language doesn't provide garbage collection and true closures with mutable shared state are therefore hard to implement correctly because of the lifetime of captured context).

The opposite (closures can be used as objects) is less observed but it's IMO a very powerful technique... consider for example (Python)

def P2d(x, y):
    def f(cmd, *args):
        nonlocal x, y
        if cmd == "x": return x
        if cmd == "y": return y
        if cmd == "set-x": x = args[0]
        if cmd == "set-y": y = args[0]
    return f

The function P2d returns a closure that captured the two values of x and y. The closure then provide access for reading and writing to them using a command. For example

p = P2d(10, 20)
p("x") # --> 10
p("set-x", 99)
p("x") # --> 99

so the closure is behaving like an object; moreover as any access is going through the command interface it's very easy to implement delegation, inheritance, computed attributes etc.

The nice book "Let Over Lambda" builds over this idea using Lisp as a language, but any language that supports closures can use this technique (in Lisp the advantage is that you can also bend the syntax using macros and read macros to improve usability and automatically generate all boilerplate code). The title of the book is exactly about this... a let wrapping a lambda:

(defun p2d (x y)
   (let ((x x) (y y))
     (lambda (cmd &rest args)
       (cond
          ((eq cmd 'x) x)
          ((eq cmd 'y) y)
          ((eq cmd 'set-x) (setq x (first args)))
          ((eq cmd 'set-y) (setq y (first args)))))))

Actually I'm not sure I agree with the "poor" adjective in this approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文