«Затворы - это объекты бедняков, и наоборот». Что это значит? - PullRequest
55 голосов
/ 23 марта 2010

Закрытия - это объекты бедняков, и наоборот.

Я видел это утверждение в много мест в Интернете ( включая SO ), но я не совсем понимаю, что это значит.Может кто-нибудь объяснить, что именно это означает?

Если возможно, приведите примеры в своем ответе.

Ответы [ 6 ]

60 голосов
/ 11 июля 2012

Объекты - это закрытие бедняков.

Рассмотрим Java. Java является объектно-ориентированным языком программирования без поддержки языкового уровня для реальных лексических замыканий. В качестве обходного пути Java-программисты используют анонимные внутренние классы, которые могут закрывать переменные, доступные в лексической области (при условии, что они final). В этом смысле объекты - это закрытие бедного человека.

Затворы - это предметы бедняков.

Подумайте о Хаскеле. Haskell - это функциональный язык без языковой поддержки реальных объектов. Однако их можно смоделировать с помощью крышек, как описано в этой превосходной работе Олега Киселева и Ральфа Ламмеля. В этом смысле замыкания являются объектами бедняков.


Если вы пришли из ОО-фона, вы, вероятно, найдете мышление в терминах объектов более естественным, и поэтому можете думать о них как о более фундаментальной концепции, чем замыкания. Если вы пришли из FP-фона, вы можете найти мышление в терминах замыканий более естественным, и поэтому можете думать о них как о более фундаментальной концепции, чем объекты.

Мораль истории заключается в том, что замыкания и объекты являются идеями, которые выражаются друг в друге, и ни один из них не является более фундаментальным, чем другой . Вот и все, что касается рассматриваемого заявления.

В философии это называется модельно-зависимым реализмом .

56 голосов
/ 23 марта 2010

Дело в том, что замыкания и объекты выполняют одну и ту же цель: инкапсуляция данных и / или функциональных возможностей в одну логическую единицу.

Например, вы можете создать класс 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, состоящий из некоторых функций. Поскольку эти функции обращаются к данным, которые были выделены в локальной области, память не освобождается, что позволяет вам продолжать использовать их через интерфейс, предоставленный закрытием.

14 голосов
/ 23 марта 2010

Объект, в самом простом случае, это просто набор состояний и функций, которые работают с этим состоянием. Закрытие - это также набор состояний и функция, которая работает с этим состоянием.

Допустим, я вызываю функцию, которая принимает обратный вызов. В этом обратном вызове мне нужно оперировать некоторым состоянием, известным до вызова функции. Я могу создать объект, который воплощает это состояние («поля») и содержит функцию-член («метод»), которая выполняет функцию обратного вызова. Или я мог бы пойти быстрым и легким ("бедным человеком") маршрутом и создать замыкание.

Как объект:

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 #, но концептуально он похож на другие языки ОО. Как видите, с классом обратного вызова для управления состоянием связано довольно много шаблонов. Это было бы намного проще, используя замыкание:

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

Это лямбда (опять же, в синтаксисе C #, но концепция аналогична в других языках, которые поддерживают замыкания), которая дает нам все возможности класса без необходимости писать, использовать и поддерживать отдельный класс.

Вы также услышите следствие: «объекты - это закрытие бедного человека». Если я не могу или не буду использовать преимущества замыканий, то я вынужден выполнять их работу, используя объекты, как в моем первом примере. Хотя объекты предоставляют больше функциональных возможностей, закрытие часто является лучшим выбором, когда закрытие будет работать по причинам, уже указанным.

Следовательно, бедняк без предметов может часто выполнять работу с замыканиями, а бедняк без замыканий может выполнять работу с использованием объектов. У богатого человека есть и то, и другое, и для каждой работы он подходит.

6 голосов
/ 23 марта 2010

РЕДАКТИРОВАНИЕ: название вопроса не включает «наоборот», поэтому я постараюсь не предполагать намерения аскера.

Два общих лагеря являются функциональными и императивными языками.Оба являются инструментами, которые могут по-разному решать похожие задачи с различными наборами задач.

Закрытия - это объекты бедняков.

Объекты - это замыкания бедняков.

По отдельности каждое утверждение, как правило, означает, что автор, так или иначе, имеет некоторую предвзятость, обычно основанную на его комфорте с одним языком или классом языка против дискомфорта с другим.Если нет предвзятости, они могут быть ограничены одной средой или другой.Авторы, которых я читаю, говорят, что подобные вещи обычно являются фанатичными, пуристскими или языковыми религиозными типами.Я избегаю языковых религиозных типов, если это возможно.

Закрытия - это объекты бедняков.Объекты - это замыкания бедняков.

Автор этого «прагматик», а также довольно умный.Это означает, что автор ценит обе точки зрения и ценит их концептуально одно и то же.Это мой парень.

5 голосов
/ 08 ноября 2010

Так много сахара, что затворы прячут анонимные предметы под юбками.

5 голосов
/ 23 марта 2010

«Объекты - это замыкания бедняков» - это не просто утверждение какой-то теоретической эквивалентности, это распространенная идиома 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]);
    }];
}

Единственное реальное отличие состоит в том, что функциональность заключена в экземпляр анонимного класса new Runnable() в Java.версия.

...