LINUX.ORG.RU

Что такое ООП

 ,


1

2

тут недвно был тред, что такое ооп, чем оно отличается от не-ооп, бла-бла-бла. Так ничего и не выяснилось толком.

Конечно, можно все-таки выделить характерную черту ООП — это семантика передачи сообщений. Остальное все в тумане...

Почему такой, казалось бы простой вопрос не имеет однозначного ответа?

Потому что ответ лежит на поверхности, поэтому его никто не видит.

Ответ заключается в том, что любая другая парадигма — есть частный случай ООП, в том смысле, что может быть выражена в терминах ООП, но не наооборот. Само название ООП тут не слишком удачно, кстати, поскольку объект в ООП — это скорей субъект. Карл Хьюитт придумал гораздо более подходящее название — акторы.

Именно в этом и кроется разгадка того, почему так трудно отделить ООП от иных парадигм.

Простой пример. Возьмем подстановочную модель, ака ФП. Центральным объектом данной парадигмы является функция. С точки зрения ООП, функция — это актор. Например, у нас есть функция, которая имеет такой вид sum(1, 2) // 3 Мы могли бы выразить это как-то так

Sum = new Function
Sum.code = a + b
theSum = new Sum 
theSum.setArguments(a: 1, b: 2)
theSum.call

Это некоторая декомпозиция, которая нам показывает, что функция — это просто сахар объекта.

То есть, грубо говоря, если мы берем некоторую полноценную ООП/Акторную семантику, и ограничиваем ее выразительные возможности, мы получаем на выходе другую парадигму. Такие вот дела:)



Последнее исправление: somequest (всего исправлений: 1)

Увезить этого поехавшего!

Deleted
()

Убейся. Твой пример - это ООП в упоротой степени.

Deleted
()

Нет в ООП никаких сообщений. Я работал с Java, C#, C++, Python, и нет сообщений никаких - просто тела функций дергают функции, принадлежащие каким-то классам, подставляя нужный this в качестве первого аргумента при записи его через точку.

hlebushek ★★
()
Ответ на: комментарий от hlebushek

Так это потому, что никакого ООП не существует; коллективная галлюцинация.

anonymous
()
Ответ на: комментарий от hlebushek

Это относится к реализации. Нет разницы, как это реализовано, хоть через те же подстановки, хоть как то еще.

somequest
() автор топика
Ответ на: комментарий от hlebushek

А вообще, полноценными сообщениями, конечно следует считать только такие, которые обрабатывает сам объект. То есть, лень на уровне реализации должна быть.

somequest
() автор топика
Ответ на: комментарий от hlebushek

просто тела функций дергают функции

И «тела функций» сами по себе ничего не дергают. Это реализация твоего ЯП, грубо говоря, делает так, чтобы тебе казалось, что функции что то там дергают. На самом деле это просо куски, в которых реализация производит подстановки и редукции.

somequest
() автор топика

Sum.code = a + b

То есть утверждение сводится к тому, что любую программу можно написать в виде

prog = new ProgramOnLanguageX
prog.code = "...."
prog.run

В этом смысле, разумеется, можно считать, что всё есть ООП.

Попробуй выразить в ООП

(define tree->generator
  (lambda (tree)
    (let ((caller '*))
      (letrec
          ((generate-leaves
            (lambda ()
              (let loop ((tree tree))
                (cond ((null? tree) 'skip)
                      ((pair? tree)
                       (loop (car tree))
                       (loop (cdr tree)))
                      (else
                       (call/cc
                        (lambda (rest-of-tree)
                          (set! generate-leaves
                            (lambda ()
                              (rest-of-tree 'resume)))
                          (caller tree))))))
              (caller '()))))
        (lambda ()
          (call/cc
           (lambda (k)
             (set! caller k)
             (generate-leaves))))))))

Или Haskell (если уж речь зашла за ФП):

instance C Int where
    f = (+1)
    g = (+)
    h x y = x
    i = head
    j x = x - 1
    new = 0

instance C Double where
    f x = if x > 5 then 2 else 3
    g x y = x - truncate y
    h x y = x + 1
    i = length
    j x = fromRational (toRational x) / 3
    new = 0.5

const1 = (new :: Double) + 2.0  -- должно быть 2.5

const2 = (new :: Int) - 2 -- должно быть -2

test1 x = f x + j x
--> test1 2
--4
--> test1 3
--6

test2 x = if x == 0.5 then g 2 x else g 1 x
--> test2 2
-- -1
--> test2 4
-- -3
monk ★★★★★
()
Ответ на: комментарий от hlebushek

дергают функции, принадлежащие каким-то классам

Ты же в коде не пишешь имя класса. Вот это определение функции по первому параметру и есть «отправка сообщения».

monk ★★★★★
()
Ответ на: комментарий от somequest

На самом деле это просо куски, в которых реализация производит подстановки и редукции.

Какую подстановку делает printLn(«Hello, World!») ?

monk ★★★★★
()

Попробуй рассмотреть интересный случай: что ООП - паттерн поведения программиста, а не какой-то набор формальных признаков.

Solace ★★
()
Ответ на: комментарий от monk

Какую подстановку делает printLn(«Hello, World!») ?

пример не совсем корректен, потому что printLn — тут имеется в виду нейтив. Если определить myPrintLn = function(arg){printLn(arg)}, то происходит именно это. При вызове myPrintLn("foo") интерпретатор распознает аппликацию, фактический аргумент подставляется на место формального, выражение редуцируется до primtLn("foo") и выполняется. То есть, тут не мифическое «тело» что то дергает, а именно исполнитель. Концептуально, то же самое происходит и с нейтив-вызовом, просто нет *чисто синтаксического представления* в языке.

anonymous
()
Ответ на: комментарий от Deleted

ООП - это квадрат унаследованный от прямоугольника.

Наоборот, в ООП квадрат не является прямоугольником (нельзя наследовать, так как не выполняется принцип Лисков).

monk ★★★★★
()
Ответ на: комментарий от monk

А если рассматривать данное выражение с точки зрения ООП, то у нас объект, условно назовем его Global, получает сообщение printLn(«Hello, world»), и он знает, как обработать данное сообщение. Как конкретно он его обрабатывает, нас не волнует, объект — это черный ящик.

anonymous
()
Ответ на: комментарий от anonymous

выражение редуцируется до primtLn(«foo») и выполняется.

Ладно, до чего редуцируется

myReadPrintLn = function(arg){if read() = "ok" then printLn(arg) else printLn("bad input") }
?

read() — это ввод с клавиатуры.

monk ★★★★★
()
Ответ на: комментарий от monk

в ООП квадрат не является прямоугольником (нельзя наследовать, так как не выполняется принцип Лисков).

А где там нарушается принцип Лисков?

tailgunner ★★★★★
()
Ответ на: комментарий от monk

Смысл высказываения в его неоднозначности. ООП - это размытое понятие. Отдельные принципы хороши и полезны, но ООП - жупел. Квадрат и прямоугольник не связаны отношением наследования.

Deleted
()
Ответ на: комментарий от monk

Наоборот, в ООП квадрат не является прямоугольником (нельзя наследовать, так как не выполняется принцип Лисков).

Наоборот твоё наоборот, ты всё перепутал. Квадрат таки является прямоугольником по Лисков - частное наследуется от общего.

no-such-file ★★★★★
()

Objects are poor man's closures.

anonymous
()
Ответ на: комментарий от anonymous

if read() = «ok» then printLn(realArg) else printLn(«bad input»)

То есть отсюда следует, что функции «read» и «printLn» таки «дёргает» тело функции myReadPrintLn.

При этом printLn может быть не только «нейтив», но и просто функцией (методом) из другой единицы компиляции. Если исходник недоступен, то редуцировать невозможно.

monk ★★★★★
()
Ответ на: комментарий от monk

Наоборот, в ООП квадрат не является прямоугольником (нельзя наследовать, так как не выполняется принцип Лисков).

только если они мутабельные

MyTrooName ★★★★★
()
Ответ на: комментарий от no-such-file

Наоборот твоё наоборот, ты всё перепутал. Квадрат таки является прямоугольником по Лисков - частное наследуется от общего.

Принцип Лисков не в этом, а в том, что если, грубо говоря, класс обладает неким свойством, то и подкласс должен обладать тем же свойством. Это все чушь, на самом деле.

somequest
() автор топика
Ответ на: комментарий от MyTrooName

только если они мутабельные

Немутабельное ООП — это оксюморон. В том смысле, что объект в ООП подразумевает структуру данных с состоянием и методы для работы с этой структурой.

Как только мы отказываемся от состояния (значит нет ни одного поля, даже приватного), то ООП редуцируется до модулей (пространств имён).

monk ★★★★★
()
Ответ на: комментарий от somequest

Это все чушь, на самом деле.

Эта чушь позволяет на основе ООП писать расширяемые библиотеки без необходимости прогонять любой класс-наследник через все тесты библиотеки.

monk ★★★★★
()
Ответ на: комментарий от monk

Немутабельное ООП — это оксюморон

Это не оксюморон, это ФП, как часный случай ООП, как раз. Тот факт, даже, что объекты мутабельны, еще не означает, что их кто-то насильно заставляет менять.

somequest
() автор топика

ООП - зло, разрушающее неокрепшие умы. Иногда разбираем проекты, где психопаты лепят, например, 10-уровневое наследование классов.

King_Carlo ★★★★★
()
Ответ на: комментарий от somequest

ФП, как часный случай ООП

Нормальное ФП, где возможно

class C a where
    f :: a -> Int
    g :: Int -> a -> Int
    h :: Int -> (Int,a) -> Int
    i :: [a] -> Int
    j :: Int -> a
    new :: a

instance C Int where
    f = (+1)
    g = (+)
    h x y = x
    i = head
    j x = x - 1
    new = 0

instance C Double where
    f x = if x > 5 then 2 else 3
    g x y = x - truncate y
    h x y = x + 1
    i = length
    j x = fromRational (toRational x) / 3
    new = 0.5

ты в тесные рамки ООР не втиснешь. Так что, спорно, кто чей частный случай. ООП через ФП реализуется (через замыкания, например)

monk ★★★★★
()
Ответ на: комментарий от monk

Ценой отказа от здравого смысла, и тотального кастрирования, и, как следствие — растягивания время разработки в сотни раз. Если отсутствие огня служит гарантией пожаробезопасности, должны ли мы отказаться от его использования? Может и должны, но только в частных случаях.

somequest
() автор топика
Ответ на: комментарий от monk

ты в тесные рамки ООР не втиснешь

Я не понимаю, что в этом коде такого, что нельзя в ООП? Я хаскель плохо знаю. Опиши словами, пожалуйста, если не трудно.

Тот пример, который с продолжениями, это к ФП вообще никак не отностится, в том же руби, например, есть call/cc, и, более того, call/cc вообще не вписывается в рамки ФП. Всем известно, что в ФП нет никаких нелокальных выходов, любая функция должна возвращать значение.

через замыкания

Замыкания — это не часть ФП — прадигмы.

somequest
() автор топика
Ответ на: комментарий от monk

замыкания

К тому же через замыкания полноценное ООП все равно не получится, нет первоклассных окружений. Там уже вначале будет ограничение, которое придется преодолевать извращениями, либо реализовывать ООП поверх замыканий.

somequest
() автор топика
Ответ на: комментарий от monk

Как только мы отказываемся от состояния (значит нет ни одного поля, даже приватного)

ты как-то резко перескочил от немутабельности к отсутствию полей

MyTrooName ★★★★★
()
Ответ на: комментарий от somequest

Я не понимаю, что в этом коде такого, что нельзя в ООП? Я хаскель плохо знаю. Опиши словами, пожалуйста, если не трудно.

Определяем для типов Double и Int набор операций. g(x, y), например, раскрывается в x + y, если y — Int или в x - truncate y, если y — Double. Причём пользователь библиотеки может добавить этот набор операций к любому дополнительному типу.

Также должна работать унификация по типу: if x == 0.5 then g 2 x else g 1 x раскрывается в 1 - truncate x, так как из операции == следует, что типы x и 0.5 совпадают.

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

monk ★★★★★
()
Ответ на: комментарий от MyTrooName

Там иммутабельность вообще ни хрена не дает. Вместо изменения ты можешь возвращать экземпляр с другими полями, это вообще непринципиальная разница, и ничего не меняет.

somequest
() автор топика
Ответ на: комментарий от somequest

К тому же через замыкания полноценное ООП все равно не получится

Так есть же: CLOS, racket/class.

нет первоклассных окружений

В смысле?

либо реализовывать ООП поверх замыканий

Так я и говорю, что можно сделать ООП поверх замыканий. А ты «через замыкания полноценное ООП все равно не получится»

monk ★★★★★
()
Ответ на: комментарий от somequest

Вместо изменения ты можешь возвращать экземпляр с другими полями

Тогда метод сможет либо менять состояние, либо возвращать значение. Либо надо придумывать монады в стиле Хаскела

monk ★★★★★
()
Ответ на: комментарий от somequest

Замыкания — это не часть ФП — прадигмы.

Хорошо, пусть будет лямбда-исчисление. В нём замыкания есть. Так вот: лямбда-исчисление с замыканиями продолжениями через ООП не выражается. А наоборот (ООП через замыкания) — тривиально.

monk ★★★★★
()
Ответ на: комментарий от monk

В смысле?

Что такое замыкание по сути? Это ф-ция плюс окружение, только к этому окружению досуп есть только изнутри этой функции. Так как этого окружения нет ни в глобальном, ни в каком-то другом неймспейсе, у тебя нет к нему доступа со стороны других объектов, обратная сторона инкапсуляции, в плохом смысле этого слова. То есть, если я захочу в ООП иметь замыкания, мне ничего специально делать не нужно, просто надо скрыть имя. Например на JS, там хоть и есть замыкания, если бы их не было, мы свободно могли бы их изображать вот так

with({a: 1}) window.foo = function(){doSomethingWith(a)}
foo — замкнуто на контекст, который не имеет имени. Только разница в том, что я могу его и поименовать при желании, потсавить на него ссылку, а могу и не ставить. А тебе твоя реализация выбора не оставляет, вот в чем разница. Ты не можешь ссылаться на это окружение, не можешь его передавать в касестве аргумента, засовывать в структуры и так далее, короче все прелести НЕфёрсткласс объекта языка. А в остальном — разницы нет.

Так я и говорю, что можно сделать ООП поверх замыканий

Это уже совсем другая история. Ты можешь реализовать ООП вообще поверх чего угодно, не обязательно замыканий. Ты можешь язык написать, например, новый.

somequest
() автор топика
Ответ на: комментарий от monk

Хорошо, пусть будет лямбда-исчисление. В нём замыкания есть

Нет там замыканий. Не путай замыкания и лексическую область видимости. Как реализована эта лексическая область, лямбда-исчислению по-барабану (может через замыкания, а может и нет).

somequest
() автор топика
Ответ на: комментарий от monk

Я как раз говорю о том, что независимо от того, какие у нас объекты, муттабельные или нет, на принцип Лисков это повлиять не может.

somequest
() автор топика
Ответ на: комментарий от monk

лямбда-исчисление с замыканиями продолжениями через ООП не выражается

У Карла Хьюитта есть бумага, где показано, как в модели Акторов(считай — то же ООП) реализуется LC буквально в пару строк. Так же есть доказательство того, что обратное невозможно. Если тебе это интересно, я могу найти эти бумаги.

Кстати, есть интересный факт. Язык Scheme изначально был ни чем иным, как (неудачной) попыткой реализовать модель Акторов с помощью некоего подобия расширенного лямбда-исчисления. ИЧСХ, авторы скрывают факт неудачи.

somequest
() автор топика

Почему такой, казалось бы простой вопрос не имеет однозначного ответа?

Потому что у тебя шизофрения.

thesis ★★★★★
()
Ответ на: комментарий от monk

продолжениями

Кстати, продолжений в LC тоже нет.

somequest
() автор топика
Ответ на: комментарий от monk

Определяем для типов Double и Int набор операций. g(x, y), например, раскрывается в x + y, если y — Int или в x - truncate y, если y — Double. Причём пользователь библиотеки может добавить этот набор операций к любому дополнительному типу.

Ну и почему это невозможно в ООП? Это всего лишь 2 класса с определенным набором опрераций. Добавление набора операций к другому типу реализуется тупо наследованием.

somequest
() автор топика
Ответ на: комментарий от monk

g(x, y), например, раскрывается в x + y, если y — Int или в x - truncate y, если y — Double

Тут даже оверхед. В ООП мы могли бы реализовать это на порядок изящней. Допустим так:

foo := Double with(1)
bar := Integer with(1)

foo g 1
bar g 2

У каждого из объектов свое собственное поле g. А то что ты показал — это костыляние этой самой возможности, настоящего полиморфизма, так как напрямую это выразить нельзя.

somequest
() автор топика
Ответ на: комментарий от somequest

Ну и почему это невозможно в ООП?

Потому что в ООП метод определяется первым аргументом. А в примере g (x, y) зависит от типа y.

monk ★★★★★
()
Ответ на: комментарий от somequest

У каждого из объектов свое собственное поле g

При чём тут поле? g — функция определённая на множестве, где первый аргумент целый, второй — произвольный. Тип второго аргумента определяет тело функции.

Или оттуда же функция h

h :: Int -> (Int,a) -> Int

a = Int => h x y = x
a = Double => h x y = x + 1

то есть

> h 2 (3, 4) 
2
> h 2 (3, 5.0) 
3

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.