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

Несколько высказываний Кэя для тех, кто пропустил
I made up the term “object-oriented”, and I can tell you I didn't have C++ in mind

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.

I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. The big idea is “messaging”.

The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.

Late binding allows ideas learned late in project development to be reformulated into the project with exponentially less effort than traditional early binding systems (C, C++, Java, etc.)

I’m not against types, but I don’t know of any type systems that aren’t a complete pain, so I still like dynamic typing.

В связи с этими обсуждениями, часто всплывает мысль о том, что Erlang/Elixir очень хорошо удовлетворяют критериям, которые Кэй предъявлял к понятию «объектно-ориентированный». Но далеко не все знакомы с этими языками, поэтому возникает непонимание как функциональные языки могут быть более объектно-ориентированными, чем популярные C++, Java, C#.

В этой статье я хочу на простом примере с exercism.io показать как выглядит ООП на Elixir.

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

В конце концов, вы должны быть в состоянии:

  • Добавить имя школьника в класс
  • Получить список всех школьников, обучающихся в классе
  • Получить отсортированный список всех учащихся во всех классах. Классы должны быть отсортированы по возрастанию (1, 2, 3 и т.д.), а имена школьников — по алфавиту.


Начнём с тестов, чтобы посмотреть как будет выглядеть код, вызывающий наши функции. Взглянем на тесты, которые Exercism подготовил для Ruby, в котором ООП дошло до того, что даже операторы — это чьи-то методы.

И напишем аналогичные тесты для Elixir-версии этой программы:
Code.load_file("school.exs")
ExUnit.start

defmodule SchoolTest do
  use ExUnit.Case, async: true
  import School, only: [add_student: 3, students_by_grade: 1, students_by_grade: 2]

  test "get students in a non existant grade" do
    school = School.new
    assert [] == school |> students_by_grade(5)
  end

  test "add student" do
    school = School.new
    school |> add_student("Aimee", 2)

    assert ["Aimee"] == school |> students_by_grade(2)
  end

  test "add students to different grades" do
    school = School.new
    school |> add_student("Aimee", 3)
    school |> add_student("Beemee", 7)

    assert ["Aimee"] == school |> students_by_grade(3)
    assert ["Beemee"] == school |> students_by_grade(7)
  end

  test "grade with multiple students" do
    school = School.new
    grade = 6
    students = ~w(Aimee Beemee Ceemee)
    students |> Enum.each(fn(student) -> school |> add_student(student, grade) end)
    
    assert students == school |> students_by_grade(grade)
  end

  test "grade with multiple students sorts correctly" do
    school = School.new
    grade = 6
    students = ~w(Beemee Aimee Ceemee)
    students |> Enum.each(fn(student) -> school |> add_student(student, grade) end)
    
    assert Enum.sort(students) == school |> students_by_grade(grade)
  end

  test "empty students by grade" do
    school = School.new
    assert [] == school |> students_by_grade
  end

  test "students_by_grade with one grade" do
    school = School.new
    grade = 6
    students = ~w(Beemee Aimee Ceemee)
    students |> Enum.each(fn(student) -> school |> add_student(student, grade) end)
    
    assert [[grade: 6, students: Enum.sort(students)]] == school |> students_by_grade
  end

  test "students_by_grade with different grades" do
    school = School.new
    everyone |> Enum.each(fn([grade: grade, students: students]) ->
      students |> Enum.each(fn(student) -> school |> add_student(student, grade) end)
    end)

    assert everyone_sorted == school |> students_by_grade
  end

  defp everyone do
    [
      [ grade: 3, students: ~w(Deemee Eeemee) ],
      [ grade: 1, students: ~w(Effmee Geemee) ],
      [ grade: 2, students: ~w(Aimee Beemee Ceemee) ]
    ]
  end

  defp everyone_sorted do
    [
      [ grade: 1, students: ~w(Effmee Geemee) ],
      [ grade: 2, students: ~w(Aimee Beemee Ceemee) ],
      [ grade: 3, students: ~w(Deemee Eeemee) ]
    ]
  end
end

Если не вдаваться в тонкости написания тестов, то нас больше всего интересуют получившиеся «методы» для работы с «классом» School:

    school = School.new
    school |> add_student("Aimee", 2) # => :ok
    school |> students_by_grade(2) # => ["Aimee"]
    school |> students_by_grade # => [[grade: 2, students: ["Aimee"]]]

Конечно, на самом деле, тут нет ни класса, ни методов, но об этом чуть позже. А пока обратите внимание, насколько это похоже на работу с экземпляром класса в рамках привычных реализаций ООП. Только вместо точки или стрелочки -> используется pipe-оператор |>.

Хотя сразу признаюсь, для того, чтобы вызвать одну функцию, pipe-оператор обычно не используют, да и сами функции размещаются в модулях, а не в классах. Поэтому более идиоматической записью для Elixir будет:

    school = School.new
    School.add_student(school, "Aimee", 2) # => :ok
    School.students_by_grade(school, 2) # => ["Aimee"]
    School.students_by_grade(school) # => [[grade: 2, students: ["Aimee"]]]

Однако суть от смены синтаксиса не меняется! Идентификатор «объекта» просто передаётся в качестве первого аргумента во все функции. Но ведь в функциональных языках нет объектов. Давайте разберёмся, что же тут происходит на самом деле…

Дело в том, что все программы, что на Erlang, что на Elixir, строятся на базе OTP, де-факто это часть стандартной библиотеки языка, обеспечивающая ту самую отказоустойчивость и масштабируемость, которой славится Erlang. OTP включает в себя очень богатый и мощный арсенал модулей и поведений (это типа абстрактных классов). Но сегодня мы поговорим только об одном, но очень часто используемом поведении — GenServer. Оно позволяет превратить обычный модуль в своеобразный генератор акторов (легковесные процессы виртуальной машины Erlang).

Каждый процесс-актор имеет своё изолированное состояние, которое можно изменять или получать информацию из него, исключительно посредством отправки ему сообщений. Если сообщения поступают конкурентно, то они обрабатываются в порядке очереди, исключая даже теоретическую возможность получить race condition на состоянии, хранимом в процессе. Таким образом каждый процесс ведёт себя с одной стороны подобно серверу — отсюда и название GenServer, а с другой стороны подобно объекту — согласно описанию Кэя.

Он так же, как объект, имеет состояние и предоставляет возможности работы с этим состоянием при помощи обработки сообщений колбеками handle_call (c возвратом ответа) и handle_cast (без ответа). То самое позднее связывание, о котором постоянно говорит Алан. А за отправку сообщений чаще всего отвечают т.н. API-функции, размещенные в том же модуле, но вызываемые из других процессов.

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

Впрочем, хватит слов. Давайте посмотрим, как это выглядит в коде:

defmodule School do
  use GenServer

  # API

  @doc """
  Start School process.
  """
  def new do
    {:ok, pid} = GenServer.start_link(__MODULE__, %{})
    pid
  end

  @doc """
  Add a student to a particular grade in school.
  """
  def add_student(pid, name, grade) do
    GenServer.cast(pid, {:add, name, grade})
  end

  @doc """
  Return the names of the students in a particular grade.
  """
  def students_by_grade(pid, grade) do
    GenServer.call(pid, {:students_by_grade, grade})
  end

  @doc """
  Return the names of the all students separated by grade.
  """
  def students_by_grade(pid) do
    GenServer.call(pid, :all_students)
  end

  # Callbacks

  def handle_cast({:add, name, grade}, state) do
    state = Map.update(state, grade, [name], &([name|&1]))
    {:noreply, state}
  end

  def handle_call({:students_by_grade, grade}, _from, state) do
    students = Map.get(state, grade, []) |> Enum.sort
    {:reply, students, state}
  end

  def handle_call(:all_students, _from, state) do
    all_students = state
      |> Map.keys
      |> Enum.map(fn(grade) ->
        [grade: grade, students: get_students_by_grade(state, grade)]
      end)

    {:reply, all_students, state}
  end

  # Private functions

  defp get_students_by_grade(state, grade) do
    Map.get(state, grade, []) |> Enum.sort
  end
end

Как правило, модуль, реализующий поведение GenServer, делится на 3 части:

  • API — функции для взаимодействия с процессом извне, они вызывают функции модуля GenServer для посылки сообщений, старта/остановки процесса и т.д. А также скрывают от вызывающего кода детали реализации
  • Callbacks — функции, реализующие поведение GenServer: обработка сообщений и т.п.
  • Private functions — вспомогательные функции, которые используются внутри модуля

При старте процесса мы получаем его идентификатор — pid, который можно потом передавать в качестве первого аргумента API-функциям. Обычно процессы стартуются функцией start_link, это соглашение позволяет удобно описывать целые деревья процессов, которые запускаются одной командой, но тут (для упрощения аналогий) я назвал её new.

Если у вас в системе есть какой-то system-wide процесс, для которого достаточно одного экземпляра, то можно дать ему имя. В этом случае вы можете обойтись без передачи pid в API-функции, т.к. они смогут отправлять сообщения процессу по имени.

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

P.S. Таким образом, Elixir позволяет вам применять ООП там, где оно действительно работает, — на верхнем уровне проектирования системы. И при этом не усложнять нижние уровни системы надуманными абстракциями и контрпродуктивными тезисами типа «Всё есть объект».
Поделиться с друзьями
-->

Комментарии (385)


  1. thepry
    15.08.2016 16:49

    school = School.new
    school |> add_student("Aimee", 2)

    Такой код вернет undefined function add_student/3, разве нет? Эликсир ведь не знает, что add_student находится в модуле School?


    1. Source
      15.08.2016 16:52
      +1

      В коде теста (на 6-й строке) явно импортируются используемые функции, поэтому доступ к ним возможен без указания имени модуля:

      import School, only: [add_student: 3, students_by_grade: 1, students_by_grade: 2]
      


  1. sulnedinfind
    15.08.2016 18:08
    +1

    Если self-параметр передается первым, то пайпы работают не за счет каррирования?
    Вот, например, функция students_by_grade. Первый параметр — школа, второй — оценка. Но функция передается в пайп с оценкой, т. е. вторым параметром.
    Специальный хак для первого параметра? Частичное применение задом-наперед?


    1. Source
      15.08.2016 19:00

      Пайпы — это не каррирование, а синтаксический сахар для инверсии записи вложенных функций.

      c(b(a))) 
      # эквивалентно
      a |> b |> c
      
      c(b(a1, a2), b2, b3)) 
      # эквивалентно
      a1 |> b(a2) |> c(b2, b3)
      


      1. sulnedinfind
        15.08.2016 19:45

        Я не говорил, что они каррирование, а имел в виду, что привык, что в ML-семействе пайпы обычно определяются примерно так:

        f |> g = g f
        


        И, соответственно, нет никаких специальных правил про первый аргумент и прочее. Впрочем, это не мешает эргономике — просто self-аргумент последний, а не первый.

        Не подкинете ссылок на какие-нибудь заметки о дизайне Elixir? Интересно, почему авторы решили отойти от проторенной дорожки.


        1. Source
          15.08.2016 20:45

          Я думаю, это в-первую очередь связано с тем, что Elixir поддерживает опциональные параметры.
          Ну и как по мне, это логичнее, когда, допустим, функции для работы со списками принимают список в качестве первого аргумента, а не последнего.
          Заметок о дизайне на эту тему я не встречал, но можно почитать в дискуссии в google-группе, например эту.


  1. begemot_sun
    15.08.2016 18:44
    -1

    Вообще делать для каждого объекта свой gen_server и как-то с этим работать — это не гуд. Почитайте про ADT ( https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%82%D0%B8%D0%BF_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85 ).

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

    Нотации для записи вообще не имеют значения:
    что ты напишешь: a->add_something(value)
    что add_something(a, value)
    Всё это дело вкуса.

    Другой вопрос. Многие говорят о вреде глобального состояния (всякие глобальные переменные и т.п.).
    Но почему-то никто не поднимает вопрос, о вреде глобального состояния в контексте объекта.
    Когда с помощью прямых присваиваний типа:
    this->my_property = 1 мы по сути изменяем глобальное свойство в объекте.
    Т.о. когда внутри метода встречаются такого рода вызовы, то метод априоры не может быть чистым. А это уже как раз к вопросу «о глобальных состояниях».
    Чистый метод (функция) всегда берет объект и возвращает новый.


    1. lair
      15.08.2016 18:50
      +1

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

      Может быть, потому что это не глобальное состояние, а локальное?


      1. begemot_sun
        15.08.2016 19:13

        Я имею ввиду глобальное по отношению к конкретному методу объекта.


        1. lair
          15.08.2016 21:19

          Проблема в том, что вы таким образом лишаетесь возможности различать "истинно глобальное" состояние — то, которое глобально для всей системы и "слегка глобальное" — которое на самом деле локально для объекта. Учитывая, что локального для метода состояния, считай, и нет (бессмысленно считать незамкнутые переменные состоянием), то это вообще теряем смысл.


          С другой же стороны, если лишить объекты mutable-состояния, то вам придется нарушать инкапсуляцию: каждый метод должен будет оповещать всех его потребителей о том, что он изменил состояние, теперь они должны иметь дело с новым объектом (кстати, а что делать тем, у кого осталась старая ссылка?). И, что веселее, это распространяется по каскаду вверх: у пользователей объекта тоже меняется состояние, об этом тоже надо оповещать, и так до корня. Очень весело. И это мы еще не касались вопросов производительности.


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


          При всем при этом я отдаю должно уважение иммутабельным объектам. Просто они не везде удобны.


          1. begemot_sun
            16.08.2016 23:56

            Я всего лишь хотел донести мысль что использование актора для всех «объектов», ну очень не хорошая идея.
            Акторы нужны там, где есть действительно объект который живет своей жизнью.

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


            1. lair
              16.08.2016 23:59
              +1

              В контексте статьи описывается принцип когда каждый школьник — актор.

              Это где, простите? В статье описана ситуация, когда актор — это реестр школьников.


              Но в данном случае, школьник лишь некая запись, с которой можно работать как с объектом, любая функция которая изменяет внутренее состояние школьника, возвращает новый «объект» школьника.

              Зачем? (не говоря уже о том, что это не "как с объектом" в моем понимании)


            1. Source
              17.08.2016 01:36

              школьник лишь некая запись, с которой можно работать как с объектом, любая функция которая изменяет внутренее состояние школьника, возвращает новый «объект» школьника.
              В Elixir для этого есть структуры, которыми и оперируют «ORM» типа Ecto. В Erlang для этого же есть записи.
              И как правильно заметил lair в статье нет никакого призыва использовать акторы вместо структур. Зато есть призыв с точностью до наоборот, не тащить ООП на уровень, где оно не нужно. В вашем примере функции будут работать со структурой Школьник, как со структурой, а не как с объектом. Грубо говоря, примут на вход одну структуру, а на выход вернут совсем другую.


              1. begemot_sun
                17.08.2016 08:52

                Да, и этого я добиваюсь.
                Чтобы сначала была имплементация модуля для такой структуры с основными операциями, а уже потом gen_server должен содержать минимальный код для приема собщений и вызова соотвествующих операций с данной структурой.


                1. Source
                  17.08.2016 12:44
                  +1

                  Так а разве кто-то с этим спорит? В статье вместо структуры Student вообще используется просто строка для упрощения примера. Но от замены на структуру код вообще не изменится, только в паре мест name на student заменить надо будет.
                  Ну и вызывающий код незначительно поменяется:

                  school |> add_student(%Student{name: "Aimee"}, 2)
                  


    1. Source
      15.08.2016 19:39

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

      По поводу состояния, в Elixir оно надёжно спрятано в процессе, никакой рефлексией и уж тем более прямыми присваиваниями до него не достать. Только отправкой сообщений можно опосредованно влиять на состояние. Ну и как в любом функциональном языке все данные неизменяемы. Т.о. ситуация, когда вы получили часть состояния объекта по ссылке, передали в другой метод, а он взял его и изменил, тоже невозможны by design.


  1. lair
    15.08.2016 18:51

    Что будет, если я сделаю вот так?


    pid = Airplane.new
    School.add_student(pid, "Aimee", 2)


    1. Source
      15.08.2016 19:28

      Процесс с этим pid упадёт с ошибкой типа
      (FunctionClauseError) no function clause matching in Airplane.handle_cast/2
      airplane.ex:38: Airplane.handle_cast({:add, "Aimee", 2}, %{})

      Вообще Erlang и Elixir стимулирует разработку по принципу «Let it crash». Поэтому чуть что не так — процесс падает и перезапускается с чистого листа одним из супервизоров.


      1. lair
        15.08.2016 21:20

        То есть я правильно понимаю, что (а) это ошибка периода выполнения (а не компиляции/статического анализа) и (б) падает не вызывающий процесс, а вызываемый?


        1. Virviil
          15.08.2016 21:54

          Теоретически такое можно отследить каким-нибудь статическим анализом, но я не встречал реализации пока что. И такие ошибки надо отлавливать в тестах.


          А падает в данном случае зацикленный GenServer. Если add_student внутри использует cast — вызывающий процесс ничего не заметит. Если call — зависит от реализации, но если вы не отлавливаете ошибки — упадёт вызывающий процесс тоже.


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


        1. Source
          15.08.2016 22:06

          Да, всё верно. Предельно позднее связывание в действии :-)
          Если Вы хотите, чтобы процесс не падал в таких ситуациях, можно определить catch-all обработчики сообщений, которые просто проигнорируют «левые» сообщения. Но с учётом того, что подобное может произойти только из-за ошибки/опечатки в коде, лучше пусть падает.


  1. Virviil
    15.08.2016 20:23

    Если вы решите делать такое в реальном коде — функция new не приветствуется.


    {:ok, school} = School.start_link
    school |> School.add_student("Aimee", 2) # => :ok
    school |> School.students_by_grade(2) # => ["Aimee"]
    school |> School.students_by_grade # => [[grade: 2, students: ["Aimee"]]]


    1. Source
      15.08.2016 20:50

      Об этом написано в статье. В четвёртом с конца абзаце.


      1. Virviil
        15.08.2016 21:00

        В принципе да, но мой комментарий не для автора статьи, а для читателей — ещё раз акцентирую внимание и представляю "правильный" кусок кода.


  1. chaetal
    16.08.2016 09:22
    -1

    Таким образом каждый процесс ведёт себя с одной стороны подобно серверу — отсюда и название GenServer, а с другой стороны подобно объекту — согласно описанию Кэя.
    <…>
    Таким образом, Elixir позволяет вам применять ООП там, где оно действительно работает, — на верхнем уровне проектирования системы. И при этом не усложнять нижние уровни системы надуманными абстракциями и контрпродуктивными тезисами типа «Всё есть объект».

    Посыл понятен (в части второй цитаты), но тогда не надо сюда привлекать Кэя, который первым пунктом почему-то (видимо, по наивности своей думал о простоте) поставил именно «надуманный и контр-продуктивный» принцип «все есть объект». А то как-то прям не честно получается :)


    1. Source
      16.08.2016 11:09
      +4

      Почему не честно? На уровне архитектуры всё и остаётся объектами, а как там эти объекты внутри реализованы уже другой вопрос. Контрпродуктивным этот тезис стал, когда спустился на уровень примитивных типов и простых структур данных. Там он никогда простоте не служил.
      Как Вам помогает в проектировании системы то, что 1 — это не 1, а экземпляр класса Integer с внутренним состоянием равным 1, к которому никто по идее не должен иметь доступ напрямую?


      1. chaetal
        16.08.2016 11:35
        -1

        Как Вам помогает в проектировании системы то, что 1 — это не 1, а экземпляр класса Integer с внутренним состоянием равным 1, к которому никто по идее не должен иметь доступ напрямую?
        Помогает тем, что с Integer-объектом я общаюсь ровно так же, как с любым другим объектом в системе — через сообщения. А что там у него внутрях мне как раз безразлично. Система, где есть несколько разнотипных сущностей, при прочих равных будет сложнее системы, где все сущности одинаковы. Вопрос заключается в «прочих равных» — не факт, что там не будет каких-то («контр-продуктивных») потерь…

        Вообще, хорошо или плохо, когда все единообразно — вопрос отдельный (не по теме статьи, как я понимаю?). Но то, что ваше определение объектности не совпадает с Кэйевским — факт: убран первый пункт. А если убрать этот пункт, то остается, по сути, только позднее связывание (так как из сообщений уходит получатель). А это было в LISP-е (о чем тот же Кэй неоднкратно говорил). Соответственно, речь таки не идет об ООП в исходном «Кэевском» смысле слова. Получается, скорее, некая имитация «антуража» ООП… Похожий на объектно-ориентированный DSL в внутри ФЯП, что ли? Это, впрочем, совсем не означает, что данный подход хуже — это тема отдельного исследования и обсуждения. Просто в IT/программировании и так все не слишком ясно, не стоит вносить дополнительную путаницу, не так ли?


        1. Source
          16.08.2016 12:10

          Помогает тем, что с Integer-объектом я общаюсь ровно так же, как с любым другим объектом в системе — через сообщения.
          Так а Integer-объект то зачем? Был у нас обычный всем понятный числовой литерал, а стал «объект», у которого внутреннее состояние выставлено наружу. Почему никто не пишет 1.getValue()? Почему возникают проблемы с boxing/unboxing? Потому что нет тут никакого единообразия. Потому что число — это число, а не объект. Вот и получается, что в теории хотели упростить, а на практике только усложнили.

          ваше определение объектности не совпадает с Кэйевским — факт: убран первый пункт.
          Насколько я понимаю, Вы ссылаетесь на Early History Of Smalltalk. Но там нигде не написано, что список идей для реализации интерпретаторов Smalltalk, является определением ООП. Не всё, что обязательно для Smalltalk, является обязательным для ООП. Иначе мы подменяем общую идею конкретной реализацией.


          1. lair
            16.08.2016 12:34
            +1

            Но там нигде не написано, что список идей для реализации интерпретаторов Smalltalk, является определением ООП. Не всё, что обязательно для Smalltalk, является обязательным для ООП

            Уиии! (И да, я с вами согласен)


            В какой-то момент Стефан Рам заинтересовался этим вопросом, и пристал к Кэю с уточнением. Вот ответ:


            OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.

            (еще там есть смешная приписка "It can be done in Smalltalk and in LISP")


            1. chaetal
              16.08.2016 12:58
              -2

              … И мы с автором уже разбирали этот ответ и обсуждали детали в «домашнем» чате. Надеюсь, не придется все повторять теперь и здесь :)


          1. chaetal
            16.08.2016 12:55
            -1

            Был у нас обычный всем понятный числовой литерал, а стал «объект», у которого внутреннее состояние выставлено наружу.
            1. Насчет состояния наружу — вы крепко ошибаетесь. Либо не на те системы смотрите. Фишка как раз в том, что никакого состояния наружу не торчит: объекту можно посылать сообщения и использовать его в качестве аргумента в сообщениях других объектов. А вот вести он себя будет в соответствии со своим значением — как и полагается объекту. Если вам это все не видно на примере целого числа, возьмите другой пример: null или true/false. Реализация их как объектов дала возможность не только сильно упростить синтаксис того же Smalltalk, но и позволяет делать красивые дизайны там, где необъектные аналоги прилично портят картину. Впрочем, это можно увидеть и на примере чисел — почитайте (а лучше попробуйте на практике), как в Smalltalk-е реализовано преобразование между «целыми короткими», «длинными», «очень длинными», дробями и т.д. Если это не удобно и элегантно, тогда что?
            2. Литералом же (в объектной системе, кстати, тоже объектом) 1 будет являться до момента компиляция (в зависимости от реализации, может еще таковым стать в момент представления пользователю) — это уже не зависит от языка и парадигмы (см. определение термина).
            3. Ну, и насчет «обычный» и «всем понятный… В объектной системе получателями и аргументами сообщения являются объекты (а что еще?). И если у вас все объекты — тут как раз все понятно и обычно. Но вот как только у вас появляются не-объекты, все сразу становится сложнее: надо придумать отдельный(-ые) механизм(-ы) для работы с такими сущностями и передачи таких сущностей.


            Но там нигде не написано, что список идей для реализации интерпретаторов Smalltalk, является определением ООП.
            Это уже не раз обсуждалось — в том числе совсем недавно на Хабре. Разумеется, каждый может выискивать нужные ему нюансы и придираться к словам. Можно разделить понятия „объект“ и „объектно-ориентированное программирование“. Можно утверждать, что если человек, работал над некоторой идеей (название для которой он и придумал) и получил некий результат, то этот результат совсем не отражает эту самую его идею. Но если этого не делать, то слова The first three principles are what objects „are about“—how they are seen and used from „the outside“ и The last three—objects from the inside—were tinkered with in every version of Smalltalk (and in subsequent OOP designs) четко отделяют принцип от реализации: первое — что такое объекты вообще, второе — как мы их реализовали в нашей системе. Обратите также внимание на то, что когда мы пытаемся определить нечто (в данном случае термин „объект“), мы едва ли будем говорить „все является этим нечто (объектом)“. Эта фраза явно относится к чему-то большему… В общем, надо сильно постараться, чтобы, прочитав данную книгу, заявить, что это не принципы ООП.
            Ну, и, наконец, есть аргумент „от здравого смысла“ — я его изложил выше. Если убрать данный пункт, окажется, что никакого ООП нет, так как все уже было до этого. Но тогда и смысла в статье нет.


            1. Source
              16.08.2016 14:01
              -1

              Насчет состояния наружу — вы крепко ошибаетесь.
              Зачем Вы спорите с очевидными вещами? То, что внутреннее состояние 1 равно 1, видно без каких-либо сообщений. То же самое с null, true и false.

              Вообще идея и реализация — это всегда разные вещи. Реализация может демонстрировать идею, но не ограничивать. Да и есть цепляться за эти 6 пунктов, то они не выполняются вообще нигде, даже в Smalltalk:
              Apparently, «everything isn't an object» afterall — some things are primitives.
              © Heart Of Smalltalk

              все уже было до этого
              Ничто не ново под Луною…


              1. chaetal
                16.08.2016 15:06
                -1

                Зачем Вы спорите с очевидными вещами? То, что внутреннее состояние 1 равно 1, видно без каких-либо сообщений.
                Жаль, что для вас это «очевидно».
                Отступление
                Как-то мы пытались объяснить человеку необходимость использования алгоритма определения попадания точки внутрь многоугольника; он не соглашался: это же очевидно — либо внутри, либо снаружи!


                1. Source
                  16.08.2016 15:41
                  +2

                  ООП относится к верхнему уровню абстракции в системе, именно на этом уровне всё является объектом… Что там внутри объектов происходит ООП не описывает и не интересуется, потому что объект действует как чёрный ящик, принимающий и отсылающий сообщения. Всё! Дальше уже идут ненужные фантазии на тему ООП внутри объектов. Фантазий на эту тему достаточно много, но все они провальные и приводящие к усложнению простых вещей. И именно от них Алан постоянно пытается откреститься )))


                  1. chaetal
                    16.08.2016 16:19

                    Где проходит черта между «верхним» и «нижним» уровнем абстракции?


                    1. Source
                      16.08.2016 18:37

                      Примерно там же, где между API и его реализацией )))
                      Обработчик сообщения, в принципе, может обращаться к другим объектам, но не обязан. А когда вы запихиваете ООП на нижние уровни, то у вас и сообщения — это объекты, состоящие из объектов, и обработчик сообщений обязан работать с другими объектами. Вот именно в этот момент «всё есть объект» уничтожает базовые идеи ООП.


                      1. chaetal
                        16.08.2016 19:00

                        Не уходите от ответа. API — это уже сама по себе граница готового объекта (приложения, если понимать термин дословно). А вот когда я разработчик, и у меня стоит задача не только это самое API сформировать, но и реализовать. А внутри у меня — каша из чего-то там и объектов. Где мне начинать использовать объекты, а где нет? Как мне не-объекты превратить в объекты и наоборот (когда надо)? Насколько это усложнит мою задачу (значительную часть времени я буду думать не о решении ее, а о там как получить нужные сущности)?

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


                        1. lair
                          16.08.2016 19:03
                          +3

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

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


                          1. chaetal
                            16.08.2016 19:16

                            Так, в соответствии с принципом «не все есть объект», API получается разнородным. И мне надо всегда помнить и себя одергивать: здесь объект и сообщения, а здесь — уже функция и тип (или что-то еще).

                            Это кстати, даже в синтаксисе языков прекрасно видно, хотя никто не замечает так как привыкли. Но привычки они не всегда полезны.


                            1. lair
                              16.08.2016 22:18
                              +2

                              Так, в соответствии с принципом «не все есть объект», API получается разнородным. И мне надо всегда помнить и себя одергивать: здесь объект и сообщения, а здесь — уже функция и тип (или что-то еще).

                              Проблема в том, что вы не можете сделать все API в соответствии с принципом "все есть объект". Соответственно, эта разнородность сохранится — как внутри API, так и между разными API. А вот сделать API вида "сервис — объект, сообщения — не объекты" — легко, причем я не могу себе представить API, которое на это не ложится. А эта "разнородность" (а) минимальна и (б) семантически легко объяснима (поэтому не добавляет понятийной сложности).


                              1. chaetal
                                16.08.2016 22:20

                                Проблема в том, что вы не можете сделать все API в соответствии с принципом «все есть объект».
                                Доказательства?


                                1. lair
                                  16.08.2016 22:21
                                  +1

                                  Попробуйте сделать API для физически распределенной системы, где сообщения будут объектами (с настоящим, а не вырожденным, поведением).


                                  Да, система мало того, что физически распределенная, так еще и ее узлы написаны на разных языках. Типичный случай кровавой ынтырпрайз-ынтыграции.


                                  1. chaetal
                                    17.08.2016 07:25

                                    Мне ли вам объяснять, что если я попробую и у меня не получится, это все равно не доказывает невозможности построения такой системы в принципе? Так что доказательство остается за вами. Как и пояснение, что такое «объекты с настоящим, а не вырожденным поведением».


                                    1. lair
                                      17.08.2016 11:57
                                      +1

                                      Мне ли вам объяснять, что если я попробую и у меня не получится, это все равно не доказывает невозможности построения такой системы в принципе?

                                      Если бы вы попробовали, то, возможно, поняли бы, почему это невозможно.


                                      Но окей, пойдем с конца.


                                      пояснение, что такое «объекты с настоящим, а не вырожденным поведением».

                                      Объект, все поведение которого сводится к хранению-передаче (без трансформации) данных. Оно же Anemic Data Model. Иными словами, это когда все операции, поддерживаемые объектом, сводятся к парам setX/getX, где X — какое-то свойство объекта.


                                      А теперь собственно мыслительный процесс.


                                      Предположим, у нас есть две системы, одна из них — реестр пользователей, вторая — обработчик уведомлений. Пользователь — это сущность, имеющая атрибуты email, firstName, lastName. При создании пользователя в реестре мы уведомляем обработчик о создании такого пользователя (сообщением created(user)). Одно из сконфигуренных уведомлений в обработчике — это отправка емейла пользователю, причем этот емейл должен содержать полное имя пользователя.


                                      С точки зрения хорошего дизайна, формирование полного имени — это ответственность сущности "пользователь" (потому что мы можем формировать это имя конкатенацией, или хранить отдельно, или делать что-то третье). Но… если реестр и обработчик уведомлений стоят на разных континентах и написаны на разных языках, у нас просто нет способа передать между ними "пользователя", как объект, имеющий поведение — во-первых, технологически сложно реализовать трансляцию поведения между языками, во-вторых, в этот момент у нас станет объект "пользователь" склонируется, что приведет к расхождениям.


                                      Окей, давайте передавать не "пользователя", а ссылку на объект "пользователь", по которой и реестр, и обработчик смогут послать любое сообщение, и получить ответ. Но вот незадача… ответ на сообщение getFullName — это что? Объект? Тогда мы попали в замкнутый круг. Или это значение-строка? Но тогда мы нарушили униформность.


                                      В гетерогенных распределенных системах (посмотрите на то же SOA, посмотрите на Enterprise Integration Patterns) сообщения между системами — это не объекты. У них нет поведения, у них есть только данные. И еще к ним не применимо сокрытие: любой агент на пути, будь то маршрутизатор или адаптер или что угодно еще, может полностью прочитать сообщение, изменить его произвольным образом, и переслать дальше. Или не переслать.


                                      1. chaetal
                                        17.08.2016 12:27

                                        Если отбросить аргумент «электроны — не объекты», то вся проблема сводится к передаче метаинформации в нужный момент времени, нет?

                                        Когда реестр уведомляет обработчик о появлени нового пользователя, первый передает второму всю необходимую информацию (да, это не объект — см. выше, но это не проблема). А на стороне обработчика из этой информации строят полноценный объект. Так что никто пропажу объекта не замечает.

                                        Какая именно информация необходима — само собой, «зависит». Как вы сказали, можно передать один идентификатор и сооружать прокси. Можно при желании передать полное состояние и сказать экземпляр какого класса нужно создать — если они «похожи» (тот же String, к примеру). А при отсутствии нужного класса на удаленной стороне используем либо первый вариант (как основной в нашем несовершенном современном мире), либо (если есть техническая возможность — вдруг таки на обеих сторонах умеют говорить на одном языке… или, в случае с гетерогенными системам, появится в будущем) можно спросить «что за класс?» и поделиться его реализацией. В самом общем случае сегодня второй вариант не прокатывает, но это же не означает принципиальную невозможность?

                                        Я не имел возможности попользоваться WCF, но «по слухам» считал, что там такая схема и реализована, нет? В Smalltalk-ах примерно так работает OpenTalk (VisualWorks). Или вот — удаленная отладка в Pharo. Это я к тому, что отладчик в Smalltalk весьма такая объектная штука.


                                        1. lair
                                          17.08.2016 12:42
                                          +1

                                          Если отбросить аргумент «электроны — не объекты», то вся проблема сводится к передаче метаинформации в нужный момент времени, нет?

                                          Нет, конечно.


                                          Когда реестр уведомляет обработчик о появлени нового пользователя, первый передает второму всю необходимую информацию (да, это не объект — см. выше, но это не проблема).

                                          Это как раз проблема, потому что это и нарушает принцип "все — объект".


                                          А на стороне обработчика из этой информации строят полноценный объект. Так что никто пропажу объекта не замечает.

                                          Вот только в интерфейсе это не объект, а "вся необходимая информация". А что на стороне обработчика — вы и не знаете (потому что инкапсуляция).


                                          Можно при желании передать полное состояние и сказать экземпляр какого класса нужно создать — если они «похожи» (тот же String, к примеру)

                                          Вот только сообщение, посланное объекту на стороне получателя (обработчика в моем примере) не будет получено объектом на стороне отправителя (реестра в моем примере). У вас объект раздвоился.


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


                                          И да, как раз это "зависит" и приводит к не-униформности API: вы что-то передаете с поведением, что-то как ссылку, что-то как значение. Намного проще (и униформнее) все передавать как значение.


                                          А при отсутствии нужного класса на удаленной стороне используем либо первый вариант

                                          В нашем технически несовершенном мире это (а) очень медленно и (б) просто передает проблему на следующий уровень.


                                          Я не имел возможности попользоваться WCF, но «по слухам» считал, что там такая схема и реализована, нет?

                                          Нет. В WCF как раз реализована схема с передачей чистых данных в том или ином формате. На любой стороне эти данные могут десериализовать в объект с поведением (если эта сторона это умеет), но это будет объект "этой стороны" — а в контракте все равно описана просто структура данных. Иными словами, для WCF-сообщения в контракте указано, какие данные в нем есть, но не описано, какие операции оно умеет.


                                          В Smalltalk-ах примерно так работает OpenTalk (VisualWorks). Или вот — удаленная отладка в Pharo. Это я к тому, что отладчик в Smalltalk весьма такая объектная штука.

                                          Это гомогенные среды, в них все иначе устроено.


                                          1. lair
                                            17.08.2016 13:00

                                            Иными словами, для WCF-сообщения в контракте указано, какие данные в нем есть, но не описано, какие операции оно умеет.

                                            … уточнение: это точно верно для WSDL/SOAP, я не очень помню, как это устроено в случае с пропьетарными биндингами.


                                          1. chaetal
                                            17.08.2016 14:18

                                            Это как раз проблема, потому что это и нарушает принцип «все — объект».
                                            Он в любом случае рано или поздно нарушается (мы это давно установили, да и секрета в этом никогда не было). Весь вопрос в том, рано или поздно.
                                            Вот только в интерфейсе это не объект, а «вся необходимая информация». А что на стороне обработчика — вы и не знаете (потому что инкапсуляция).
                                            Простите, не понял, о каком интерфейсе речь, и что мне нужно знать на стороне обработчика?
                                            Вот только сообщение, посланное объекту на стороне получателя (обработчика в моем примере) не будет получено объектом на стороне отправителя (реестра в моем примере).
                                            Почему же оно не будет получено-то? У нас же есть слой, передающий сообщения по сети?
                                            У вас объект раздвоился.
                                            На каждой из сторон я имею дело с объектом. Про то, что он раздвоился (детали реализации) никому из пользователей объекта знать не надо.
                                            Это как раз тот момент, когда то, что вы передали — не объект. Его поведение на разных сторонах не униформно.
                                            При правильной реализации на обеих сторонах может быть очень даже униформно. А правильную реализацию, кстати, можно при старте приложения согласовать.
                                            И да, как раз это «зависит» и приводит к не-униформности API: вы что-то передаете с поведением, что-то как ссылку, что-то как значение. Намного проще (и униформнее) все передавать как значение.
                                            Какая разница как я что-то передаю? Это детали реализации. Я могу вообще байт-код передавать. Могу нужную виртуальную машину на ту сторону загрузить.
                                            В нашем технически несовершенном мире это (а) очень медленно и (б) просто передает проблему на следующий уровень.
                                            Мы же говорим про принципиальную возможность, не так ли? Пункт (а) не релевантен. А что значит «передает проблему на следующий уровень»? Рано или поздно системы должны начать разговаривать «на одном языке». И даже, вроде бы, не важно когда именно — это детали реализации, от разработчиков на обеих сторонах они должны быть скрыты.
                                            Это гомогенные среды, в них все иначе устроено.
                                            Во! Может быть проблема-то как раз в том, чтобы реализовать объекты на том же уровне абстракции, где среды начинают понимать друг друга (становятся гомогенными)? Другими словами «протащить» объекты максимально далеко в бутстрэппинг? Что эквивалентно вопросу «минимально возможной объектной системы»? Не об этом говорит тот же Кэй, когда расхваливает Internet (в противовес Web-у)?


                                            1. Source
                                              17.08.2016 14:35
                                              +1

                                              Другими словами «протащить» объекты максимально далеко в бутстрэппинг?
                                              Кстати, Erlang позволяет посылать сообщения процессам на удалённых нодах, их даже никуда тащить не надо и тем более раздваивать. Вот только ответ на сообщение придёт в виде данных. Что весьма удобно на практике, но не вписывается в Вашу теоретическую концепцию.


                                            1. lair
                                              17.08.2016 16:27

                                              Простите, не понял, о каком интерфейсе речь, и что мне нужно знать на стороне обработчика?

                                              Об API. И на стороне обработчика вам не надо знать, на каком языке написан реестр и наоборот.


                                              Почему же оно не будет получено-то? У нас же есть слой, передающий сообщения по сети?

                                              Потому что вы подняли копию объекта на стороне получателя, и теперь сообщения принимает она.


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

                                              Не надо?


                                              repository.createUser(user)
                                              notificationEngine.notifyCreation(user) //notificationEngine - удаленный
                                              user.firstName = "newName" //в notificationEngine он изменился или нет?
                                              
                                              > При правильной реализации на обеих сторонах может быть очень даже униформно.
                                              
                                              Не в реальном мире.
                                              
                                              > Могу нужную виртуальную машину на ту сторону загрузить.
                                              
                                              Тем самым нарушив право той стороны на собственную реализацию.
                                              
                                              > Рано или поздно системы должны начать разговаривать «на одном языке». 
                                              
                                              И этот язык, неизбежно, данные.
                                              
                                              > Может быть проблема-то как раз в том, чтобы реализовать объекты на том же уровне абстракции, где среды начинают понимать друг друга (становятся гомогенными)?
                                              
                                              Это эквивалентно "запретить всем писать на не-ООП-языках". Спасибо, но нет.
                                              
                                              > Не об этом говорит тот же Кэй, когда расхваливает Internet (в противовес Web-у)?
                                              
                                              Вот только в интернете между узлами гуляют данные, а не объекты. Что как бы лишний раз подтверждает.


                                              1. chaetal
                                                17.08.2016 16:54

                                                Потому что вы подняли копию объекта на стороне получателя, и теперь сообщения принимает она.
                                                А потом транслирует на другую сторону, там сообщения принимают, обрабатывают (не зная, откуда они поступили), возвращают ответ, который транслируется назад, и там создается впечатление, что ответил мне тот объект, которому я послал исходное сообщение.
                                                Тем самым нарушив право той стороны на собственную реализацию.
                                                Что это за право? :) У компьютерных систем уже появились права?
                                                И этот язык, неизбежно, данные.
                                                А данных будет достаточно? Они не предполагают общей семантики? Вот вам данные: 124 343 32 23 123. Что я попросил вас сделать? :) Это не говоря о том, что и последовательность электрических сигналов превратить в «данные» без предварительной договоренности не выйдет. Так что общий язык не с данных начинается, увольте.
                                                Это эквивалентно «запретить всем писать на не-ООП-языках». Спасибо, но нет.
                                                Почему же всем и так категорично? Я понимаю русский язык. Это не мешает мне худо-бедно понимать английский. И какой-нибудь JSON спокойненько передается по TCP/IP так же, как SNMP.
                                                Вот только в интернете между узлами гуляют данные, а не объекты. Что как бы лишний раз подтверждает.
                                                Это только кажется, что проблему снимают именно данные. См. выше про общий язык. Это пока предпочитают об интерпретации данных договориться заранее и обходными маршрутами. Когда-нибудь придумают, как договариваться на ходу и по той же сети.

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


                                                1. lair
                                                  17.08.2016 17:01

                                                  А потом транслирует на другую сторону, там сообщения принимают, обрабатывают (не зная, откуда они поступили), возвращают ответ, который транслируется назад, и там создается впечатление, что ответил мне тот объект, которому я послал исходное сообщение.

                                                  То есть это опять прокси, а не "передать полное состояние и сказать экземпляр какого класса нужно создать — если они «похожи» (тот же String, к примеру)".


                                                  Что это за право?

                                                  Мое право как разработчика использовать ту технологию, которую я считаю более оправданной для решения задачи.


                                                  Так что общий язык не с данных начинается, увольте.

                                                  Я не сказал, что он с них начинается, я сказал, что он ими заканчивается.


                                                  Почему же всем и так категорично?

                                                  Потому что для не-ООП-сервиса поддерживать ООП для сообщений нелогично.


                                                  Когда-нибудь придумают, как договариваться на ходу и по той же сети.

                                                  Или не придумают.


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

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


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


                                                  1. chaetal
                                                    17.08.2016 17:18

                                                    То есть это опять прокси, а не «передать полное состояние и сказать экземпляр какого класса нужно создать — если они «похожи» (тот же String, к примеру)».
                                                    Тогда я не понял, какой мы вариант обсуждаем, и в чем вы видите проблему?
                                                    Я не сказал, что он с них начинается, я сказал, что он ими заканчивается.
                                                    Тогда надо определиться, где начало, а где конец :)

                                                    Вы предлагаете именно гомогенизировать среду. Это, конечно, похвально, но мне это банально не нравится.
                                                    Я предлагаю подумать над возможностью динамически «учить» программные системы общаться на том языке, который удобен разработчику. В том числе и на объектном.

                                                    Я имею привычку считать, что пока возможность не доказана — ее и нет.
                                                    К сожалению, эта привычка противоречит банальной логике. А оставаясь в ее рамках, …
                                                    Когда-нибудь придумают, как договариваться на ходу и по той же сети.
                                                    Или не придумают.
                                                    … мы договорились: не определено, что опровергает исходный тезис.


                                                    1. lair
                                                      17.08.2016 17:41

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

                                                      Я обсуждаю как раз вариант "создадим экземпляр класса на стороне получателя". Не прокси.


                                                      Я предлагаю подумать над возможностью динамически «учить» программные системы общаться на том языке, который удобен разработчику. В том числе и на объектном.

                                                      Динамически переключаться между stateful- и stateless-моделями? Свежо предание...


                                                      мы договорились: не определено, что опровергает исходный тезис.

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


                                                      Вы пока так и не предложили решения, позволяющего гетерогенным системам иметь полностью униформное объектное поведение.


                                                      1. chaetal
                                                        17.08.2016 20:06

                                                        Я обсуждаю как раз вариант «создадим экземпляр класса на стороне получателя». Не прокси.
                                                        Если объект не завязан на «контекст», который невозможно перетащить на другую сторону — никаких проблем не вижу. Если же таки завязан, то проксируем этот самый контекст.
                                                        Извините, но мы не договорились.
                                                        Ну как же, вы же признали: «Или не придумают». То есть, допустили возможность? :) Ладно, я думаю мы здесь друг друга поняли и нет смысла дальше препираться. Вы отсутствие подтверждения существования считаете доказательством отсутствия. Соответственно, черных лебедей не существовало, пока их не обнаружили в Австралии (если не врут на этот счет). И Земля была плоской, пока не доказали, что она имеет форму апельсина :)


                                                        1. lair
                                                          17.08.2016 21:08

                                                          никаких проблем не вижу.

                                                          … а дублирование объекта?


                                                          Ну как же, вы же признали: «Или не придумают». То есть, допустили возможность?

                                                          Нет, не допускал. Я продолжаю считать, что идея тотальных объектно-ориентированных API невозможна (в гетерогенных средах), потому что какое-то API будет возвращать примитивные значения (иначе вы не сможете выполнить примитивные операции).


                                                          1. chaetal
                                                            18.08.2016 07:46

                                                            … а дублирование объекта?
                                                            — деталь реализации, скрытая от пользователей (разработчиков) на обоих «концах».


                                                            1. lair
                                                              18.08.2016 11:47

                                                              Да как же она скрыта, если ее надо учитывать при программировании?


                                                              1. chaetal
                                                                18.08.2016 13:17

                                                                Учитывать надо только в момент создания объекта, представляющего удаленную сторону, что это именно удаленный объект (и соответствующим образом его сконфигурировать)… Хотя и это можно «скрыть» при желании. Все остальное «прозрачно» — ничем не отличается от обычной разработки.


                                                                1. lair
                                                                  18.08.2016 13:33

                                                                  Учитывать надо только в момент создания объекта, представляющего удаленную сторону, что это именно удаленный объект (и соответствующим образом его сконфигурировать)…

                                                                  "объект, представляющий удаленную сторону" — это обработчик уведомлений (и у него как раз прокси). А "раздвоившийся" объект — это пользователь, которого туда передали.


                                                                  Повторюсь, проблема в том, что — в рамках распределенной системы — вы не знаете, с каким объектом вы работаете: локальным, удаленным (через прокси) или раздвоившимся.


                                                                  1. chaetal
                                                                    18.08.2016 13:45

                                                                    «раздвоившийся» объект — это пользователь, которого туда передали.
                                                                    Он раздвоился только для наблюдателя со стороны. Для того, кто его передал, ничего не изменилось — объект как получал (откуда-то) сообщения, так и продолжает их получать. Для того, кому передали — то же самое: появился объект, я могу с ним работать как и с остальными; а где он на самом деле находится и как внутри устроен — мне «по барабану».
                                                                    вы не знаете, с каким объектом вы работаете: локальным, удаленным (через прокси) или раздвоившимся
                                                                    «Не знаю и знать не хочу!» — основной принцип и признак «правильного» ООП :)


                                                                    1. lair
                                                                      18.08.2016 13:54

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


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


                                                                      1. chaetal
                                                                        18.08.2016 14:00

                                                                        Побочные эффекты лишь говорят о несовершенстве используемых инструментов (в частности фреймворка, обеспечивающего удаленное взаимодействие объектов; но не только его). Вы же сами говорили про инкапсуляцию как одном из основных (едва ли не основном?) принципов ООП. А тут, оказывается, надо лезть внутрь объекта. Не сходится?


                                                                        1. lair
                                                                          18.08.2016 14:05

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


                                                                          1. chaetal
                                                                            18.08.2016 14:16

                                                                            Так потому и не сходится, что в момент перехода к распределенным системам инкапсуляция на сообщениях перестает работать. Что и говорит нам о плохой применимости ООП в этом месте.
                                                                            Тогда с этого места поподробнее: что значит «инкапсуляция перестает работать в распределенных системах». Особенно в контексте того же Erlang (который, как я понял, инкапсулирован «по самое не хочу»).


                                                                            1. lair
                                                                              18.08.2016 14:18

                                                                              Так в Erlang то, что вы посылаете (сообщение) — не объект. И именно такая модель (системы — объекты, сообщения — нет) наиболее жизнеспособна.


                                                                              1. chaetal
                                                                                18.08.2016 14:30

                                                                                Но вы-то про инкапсуляцию говорили, а не про объекты? Вы меня запутать хотите?


                                                                                1. lair
                                                                                  18.08.2016 14:37

                                                                                  У сообщения инкапсуляция минимальна. Его поведение тривиально, предсказуемо и известно снаружи.


                                                                                  1. chaetal
                                                                                    18.08.2016 14:47

                                                                                    Видимо, все-таки хотите запутать :) — я перестал понимать ход вашей мысли.


                                                                                    1. lair
                                                                                      18.08.2016 14:50

                                                                                      Ход моей мысли очень прост: в распределенной системе есть неотъемлимая (inherent) сложность, которая приводит к тому, что использование объектов-с-поведением в качестве сообщений становится нерентабельно (как технически, так и когнитивно). Я не знаю ни одной акторной системы, где сообщения имели бы собственное поведение.


                                                                                      И это приводит к тому, что удобным униформным решением для API становится ситуация, когда системы являются объектами, а вот сообщения между ними — не являются.


                                                                                      1. chaetal
                                                                                        18.08.2016 15:34

                                                                                        То есть, проблема именно в сообщениях? Просто ранее была

                                                                                        проблема в том, что — в рамках распределенной системы — вы не знаете, с каким объектом вы работаете: локальным, удаленным (через прокси) или раздвоившимся.
                                                                                        Они как-то связаны?


                                                                                        1. lair
                                                                                          18.08.2016 16:34

                                                                                          То есть, проблема именно в сообщениях?

                                                                                          Да, проблема именно в сообщениях.


                                                                                          Они как-то связаны?

                                                                                          Это одна и та же проблема.


                                                                                          Когда вы работаете с объектом-сервисом (т.е., отвечающим за API удаленной системы), у вас нет проблемы знать, какой он: он не может быть раздвоившимся (для сервисов это невозможно), а с локальным вы общаетесь так же, как с удаленным. Иными словами, вы всегда думаете, что этот объект удаленный, и эта мысль не нарушает процесс разработки.


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


                                                                                          1. chaetal
                                                                                            20.08.2016 10:59

                                                                                            В какой замкнутый круг? Я по-прежнему не понимаю! Доказательства не намечаются, есть какие-то общие рассуждения. При условии, что мы не сходимся в базовых логических основаниях, на данный момент не вижу смысла в продолжении обсуждения по данной теме.


                                                                                            1. lair
                                                                                              20.08.2016 17:59
                                                                                              +1

                                                                                              В какой замкнутый круг?

                                                                                              Да в простой.


                                                                                              Рано или поздно для какой-то операции вам нужны локальные данные. Не удаленный объект, которому вы послали сообщение, и он что-то сделал, а локально присутствующие данные. И либо у вас какие-то данные локальные, а какие-то — удаленные, и тогда у вас нет униформности, либо у вас все данные… какие?


                                                                                              1. chaetal
                                                                                                20.08.2016 18:42

                                                                                                Локальные данные — они же внутри объекта?


                                                                                                1. lair
                                                                                                  20.08.2016 18:59

                                                                                                  Если следовать идее "все объект" — то да.


                                                                                                  1. chaetal
                                                                                                    20.08.2016 19:00

                                                                                                    Так где нарушается «униформность»?


                                                                                                    1. lair
                                                                                                      20.08.2016 19:28

                                                                                                      Там, где у вас одни данные — локальные, а другие — удаленные.


                                                                                                      1. chaetal
                                                                                                        20.08.2016 19:33

                                                                                                        Эти данные — внутри объекта. А работаю я с объектами извне. А извне все объекты одинаковы.


                                                                                                        1. lair
                                                                                                          20.08.2016 19:35

                                                                                                          Ах если бы. Во-первых, у вас принципиально разная стоимость вызова (что ведет к chatty vs chunky). Во-вторых, вы не можете передать удаленный объект в произвольную систему (потому что вы не знаете, имеет ли эта произвольная система доступ к этому объекту).


                                                                                                          1. chaetal
                                                                                                            20.08.2016 19:54

                                                                                                            Я собираю систему из таких объектов, которые соответствуют предъявляемым к этой системе требованиям. При необходимости я создаю нужные объекты.


                                                                                                            1. lair
                                                                                                              20.08.2016 20:26

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


                                                                                                              1. chaetal
                                                                                                                20.08.2016 20:37

                                                                                                                Поведение будет разным (поэтому и объекты разные), но однородным — они все остануться объектами и будут отвечать на сообщения.


                                                                                                                1. lair
                                                                                                                  20.08.2016 20:42
                                                                                                                  +2

                                                                                                                  Вот только степень разницы, вызванная требованиями (в частности, как мы только что выяснили, [не]изменяемость состояния), намного выше, чем разница "отвечает на сообщение/или нет".


                                                                                                                  Собственно, если просто закрыть глаза на то, что DTO не имеют поведения — то да, все так и выглядит, "все есть объекты", только некоторые объекты не такие, как другие объекты.


                                                                                                                  1. chaetal
                                                                                                                    20.08.2016 21:13

                                                                                                                    «все есть объекты», только некоторые объекты не такие, как другие объекты.
                                                                                                                    Почти все объекты — не такие (в том или ином смысле) как другие объекты. И существенно не такие. И при этом все они однородны — отвечают на сообщения.

                                                                                                                    И, кстати, оформилась хорошая мысль: можно «необъекты» присыпать сахарочком, чтобы они выглядели как объекты — путь мейнстрима; а можно «необъекты» реализовать в виде объектов — путь исходного ООП?


                                                                                                                    1. lair
                                                                                                                      20.08.2016 22:25

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


                                                                                                                      1. chaetal
                                                                                                                        21.08.2016 11:37

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


                                                                                                                        1. lair
                                                                                                                          21.08.2016 13:00

                                                                                                                          Пример?


                                                                                                                          1. chaetal
                                                                                                                            21.08.2016 13:08

                                                                                                                            Примитивные типы. Например, int.


                                                                                                                            1. lair
                                                                                                                              21.08.2016 13:12

                                                                                                                              … и чем int в C# отличается от SmallInteger в Smalltalk?


                                                                                                                              1. chaetal
                                                                                                                                21.08.2016 13:23

                                                                                                                                Начнем с того, что int — это тип, а SmallInteger — это объект?


                                                                                                                                1. lair
                                                                                                                                  21.08.2016 13:27

                                                                                                                                  Ну нет. SmallInteger — это класс, а значит — тоже тип. Конкретное x в x := 1 — это объект.


                        1. Source
                          17.08.2016 01:27

                          Где мне начинать использовать объекты, а где нет? Насколько это усложнит мою задачу (значительную часть времени я буду думать не о решении ее, а о там как получить нужные сущности)?
                          Если исходить из определения «объект — это изолированный процесс со своей областью памяти» и учитывая, что в ФП никакого shared state не бывает в принципе, то все ваши вопросы выглядят надуманными и на практике возникают исключительно редко. По крайней мере за год программирования на Elixir у меня ни разу не было дилеммы «что делать процессом, а что нет». Т.е. ни на сколько это не усложнит вашу задачу, исходя из практики — только упростит.

                          Как мне не-объекты превратить в объекты и наоборот (когда надо)?
                          Никогда не надо. Не бывает задачи превратить процесс в, допустим, список или наоборот — список в процесс.


                          1. chaetal
                            17.08.2016 08:12

                            Что такое Map в вашем коде?

                            Подскажите, где здесь ООП, а где ФП?

                                all_students = state
                                  |> Map.keys
                                  |> Enum.map(fn(grade) ->
                                    [grade: grade, students: get_students_by_grade(state, grade)]
                                  end)
                            


                            1. lair
                              17.08.2016 09:47
                              +1

                              Map — это модуль в терминологии Elixir.


                              А приведенный вами фрагмент кода — полностью функциональный.


                            1. Source
                              17.08.2016 13:24

                              Собственно, мне нечего добавить, кроме ссылки на доку
                              lair уже абсолютно правильно ответил.


                              1. chaetal
                                17.08.2016 14:22

                                То есть, объектность кончается на уровне описания «интерфейса»? Внутри «объекта» у меня объектов больше нет? А если мне все-таки нужен объект, я за это должен платить созданием процесса? И, обращаясь к объекту, я перехожу на «объектный язык», а как только пришел ответ — возвращаюсь на функциональный?


                                1. Source
                                  17.08.2016 14:47
                                  +2

                                  Да, всё верно. Внутри «объекта» у нас сплошное ФП :-)
                                  Впрочем если хотите некую композицию «объектов», то это тоже не вопрос, стартуйте нужный процесс из обработчика сообщения.
                                  Плата за создание процесса не так велика, оверхэд примерно того же порядка как при создании объектов в Java.
                                  В общем, смысл в том, чтобы в качестве объектов рассматривать только те сущности, которые реально живут какой-то своей жизнью. У которых есть понятный жизненный цикл или миссия «бесконечно» обрабатывать некоторые запросы.
                                  Всё остальное — это просто данные, которые обрабатываются при помощи ФП.


  1. Cryvage
    16.08.2016 09:26

    I made up the term “object-oriented”, and I can tell you I didn't have C++ in mind

    Видимо, даже внеся значительный вклад в «изобретение будущего», предсказать его все равно невозможно.


    1. chaetal
      16.08.2016 10:12
      +1

      Просто некоторые под будущим понимают нечто светлое и красивое :)


  1. naneri
    16.08.2016 10:36
    +3

    «Как выглядит ООП в функциональном языке?» — почти что также как и в любом другом…


    1. chaetal
      16.08.2016 12:56
      -1

      … почти также как в любом другом необъектном :)


  1. chaetal
    16.08.2016 13:03
    +1

    Чуть не забыл! Мое внимание привлекла эта фраза:

    в котором ООП дошло до того, что даже операторы — это чьи-то методы
    Поясните, пожалуйста, что вы имели ввиду?


    1. Source
      16.08.2016 13:30

      Имеется в виду, что нет такой разницы между операторами и методами, как в Java или в C#, например можно написать так:

      [1, 2, 3, 4, 5].<<(2.+(2.*(2))) # => [1, 2, 3, 4, 5, 6]
      


      1. chaetal
        16.08.2016 13:36
        +1

        А почему дошло? В ООП изначально понятие операции (над значением определенного типа) заменили на сообщение (посылаемое объекту). А метод — это просто реализация, описывающая как объект реагирует на конкретное сообщение.

        Собственно, это еще раз про чистоту, которую мы обсуждаем в соседней ветке, если я правильно понял? Тогда данную можно закрыть.


        1. Source
          20.08.2016 14:45

          А почему дошло? В ООП изначально понятие операции (над значением определенного типа) заменили на сообщение (посылаемое объекту).
          Потому что это тонкий стёб над мейнстрим-реализациями ООП.


  1. nwalker
    16.08.2016 13:37

    Я вообще не понимаю, зачем вам терминология ООП в данном случае.
    Ну есть у вас сущность и набор операций над ней, причем тут ООП?


    1. chaetal
      16.08.2016 13:45

      Спасибо! Вы просто и коротко написали то, что я долго и нудно пытаюсь сказать!


    1. Source
      16.08.2016 14:22

      А почему бы нет? На мой взгляд отличная реализация метафоры, которая легла в основу ООП:

      biological scheme of protected universal cells interacting only through messages that could mimic any desired behavior

      Тем более мейстрим-реализации ООП свели ценность этой аналогии к нулю, не обеспечивая реальную защиту внутреннего состояния и увлёкшись странной идеей, что ядро клетки — это тоже клетка, митохондрия — это тоже клетка, рибосома — тоже клетка и т.д… Но нет, внутреннее состояние клетки — это не набор других клеток. В биологии у вас не получится спуститься на уровень кварков и заявить, что кварк — это тоже клетка :-)


      1. chaetal
        16.08.2016 14:49
        -1

        My biology major had focused on both cell metabolism and larger scale morphogenesis with its notions of simple mechanisms controlling complex processes and one kind of building block able to differentiate into all needed building blocks.


        Вообще, интересная манера: схватиться за одну фразу (к тому же метафорическую) и на ней строить какие-то теории, ссылаясь на автора фразы, но при этом игнорируя 99,999% его труда. Тогда и статью надо назвать: «Как выглядит метафора клеток в функциональном языке»


        1. Source
          16.08.2016 15:29
          +1

          Ну, able to — это не то же самое, что has to.
          У Вас свои стойкие предубеждения и Вы интерпретируете всё в пользу Вашей точки зрения. Вплоть до того, что «initial premises in designing the Smalltalk interpreter» внезапно превращаются в определение ООП. И все, кто не согласен, с Вашей интерпретацией книги про раннюю историю Smalltalk, сразу признаются ничего не понимающими в ООП, похоже, включая и самого Алана )))
          Вот его мнение от 2010 года в тему этой статьи:

          Many of Carl Hewitt’s Actors ideas which got sparked by the original Smalltalk were more in the spirit of OOP than the subsequent Smalltalks. Significant parts of Erlang are more like a real OOP language than the current Smalltalk, and certainly the C based languages that have been painted with “OOP paint”.
          пруф


          1. chaetal
            16.08.2016 16:17
            -2

            Не надо путать предубеждения и убеждения (основанные на чем-то, и это далеко не одна упомянутая книга, уж поверьте). У меня есть своя точка зрения и я имею не меньше прав отстаивать ее, чем вы — свою. И аналогично вашим придиркам к словам я могу сказать что «spirit of OOP» это не то же самое, что «OOP». А уж «main ideas that were in accord with the initial premises in designing the interpreter» вдруг превращаются в сами «initial premises» — извините, не у меня. Да и аппелировать к Кэю приходится не от хорошей жизни — без ссылок на авторитеты почему-то никто не хочет даже задуматься над сутью идеи.

            Кроме того, я-то как раз не считаю C#, Java или даже Smalltalk идеальными выразителями идей OOP. Если вы (или кто-то еще) покажете эти самые «parts of Erlang», которые «more like a real OOP language than the current Smalltalk» — я буду вам (или кому-то еще) очень признателен. Серьезно. Но пока что как-то не получилось. Может быть, в данном случае, потому что вы уделяете внимание каким-то не тем вопросам? В общем, из наших с вами дискуссий мне пока не удалось понять, чем же Erlang лучше (проще, мощнее) того же Smalltalk-а. Но это, разумеется, мои проблемы.

            Ну, и еще один вопрос. Где и кого я лишь на основании несогласия с моей точкой зрения назвал ничего не понимающим в ООП?! Если такое было, я приношу тому человеку свои глубочайшие и искренние извинения. Вот, мне интересно, только честно: до наших с вами дискуссий вы много времени посвятили тому, чтобы вникнуть в суть ООП и его настоящие базовые идеи?


            1. Source
              16.08.2016 18:29
              +2

              Согласен, у Вас есть такое же право на свою точку зрения. Просто меня удивляет, как Вы интерпретируя и опираясь на то, что пишет Кэй, приходите к несогласию с ним же. Я не говорю, что Elixir или Erlang лучше реализуют ООП, чем Smalltalk, это просто разные реализации. Идея в том, что все преимущества ООП можно использовать и в этих языках. При этом ещё и получив все преимущества ФП на уровне реализации.
              Вот ещё Вам цитата из совсем свежего:


              Что Вы ещё хотите понять про Erlang/Elixir в плане ООП, мне уже непонятно. Для полноценного сравнения со Smalltalk, если Вы его ждёте, мне пришлось бы освоить Smalltalk. Поэтому я сравниваю их с языками, которые мне уже хорошо известны, типа Ruby или C#. И они в плане соответствия идеям Кэя сильно проигрывают Elixir, хоть и достаточно полно (особенно Ruby) реализуют «Всё есть объект».

              Вот, мне интересно, только честно: до наших с вами дискуссий вы много времени посвятили тому, чтобы вникнуть в суть ООП и его настоящие базовые идеи?
              Достаточно много. Где-то 3 года назад заинтересовался истоками ООП.


              1. chaetal
                16.08.2016 18:52

                Просто меня удивляет, как Вы интерпретируя и опираясь на то, что пишет Кэй, приходите к несогласию с ним же.
                А в чем несогласие-то?
                Что Вы ещё хотите понять про Erlang/Elixir в плане ООП, мне уже непонятно.
                Ничего страшного — мне тоже непонятно. :) Просто вы попробовали. Для кого-то этого было достаточно. А мне вот оказалось мало. Мое понимание ООП не изменилось, и в него сказанное не вкладывается. Нет, я честно пытался не «победить в споре», а понять вашу точку зрения. Но «не сходится». Smalltalk (с поправками на реальную жизнь) — он сходится. А здесь — пока нет.
                Про сравнение со Smalltalk, разумеется, и речи нет. Возможно (нет, точно!), это мне надо взять и попробовать плотно Erlang. А если вопрос был не риторическим, то хорошей заманухой был бы показ интересных, нетривиальных задач с красивым ООП-решением. А то ведь (вы помните, исходное обсуждение в нашем чате?) даже ваши коллеги по Erlang-у выражали сильное недоумение по поводу ООП-программирования на это языке.


                1. Source
                  17.08.2016 01:06

                  А в чем несогласие-то?
                  Ну вот Вы говорите:
                  Соответственно, речь таки не идет об ООП в исходном «Кэевском» смысле слова. Получается, скорее, некая имитация «антуража» ООП…

                  А он про то же самое говорит, что это один из двух путей понять «real OOP». По-моему тут явное противоречие Вашей точки зрения с точкой зрения Кэя.

                  показ интересных, нетривиальных задач с красивым ООП-решением
                  ну, это надо что-то из open source посмотреть, не писать же нетривиальный проект чисто в демо-целях )))

                  даже ваши коллеги по Erlang-у выражали сильное недоумение по поводу ООП-программирования на это языке.
                  Не забывайте, что имеет место сильная зашоренность на тему ООП. Для многих ООП == [«Инкапсуляция», «Наследование», «Полиморфизм»]. Для некоторых вообще ООП — это там где классы. В этом плане я согласен, с nwalker, когда говоришь ООП, никогда точно не знаешь, что подумал собеседник.


                  1. sl_bug
                    17.08.2016 01:28

                    Я бы хотел добавить огонька в дискуссию :)


                    1. Source
                      17.08.2016 02:34

                      Ну, прикольное видео… Только оно как раз скорее про Java, а не про ООП в изначальном смысле. Я досмотрел до момента, когда он нарисовал дерево супервизоров и сказал, что нормальная инкапсуляция возможна только в таком случае, но так никто не пишет. Забавно, что на Erlang/Elixir практически только так и пишут, даже есть отладочный инструмент, который эти деревья визуализирует, observer называется.
                      image


                  1. lair
                    17.08.2016 01:29

                    Заметим, кстати, что в модели акторов есть и инкапсуляция, и полиморфизм.


                    1. Source
                      17.08.2016 01:50

                      Есть. Но без усердного пиара. А так, инкапсуляция в плане сокрытия гораздо лучше как раз в модели акторов реализована на мой взгляд.
                      Ещё и композиция есть. Наследование же давно уже не в почёте xD


                    1. chaetal
                      17.08.2016 08:06

                      Учитывая «широту трактовки» этих терминов — не удивительно.


                  1. chaetal
                    17.08.2016 08:04

                    Ну вот Вы говорите:
                    Соответственно, речь таки не идет об ООП в исходном «Кэевском» смысле слова. Получается, скорее, некая имитация «антуража» ООП…

                    А он про то же самое говорит, что это один из двух путей понять «real OOP». По-моему тут явное противоречие Вашей точки зрения с точкой зрения Кэя.
                    Не, вы, пожалуйста, не путайте, и не перемещайте слова из одного контекста в другой. Я охотно допускаю, что Erlang с моделью акторов может развивать идею ООП или, по крайней мере, помогать ее лучше понять. Этот язык давно стоит в моем списке на изучение… слишком давно, к сожалению. И мне очень интересно, что там Кэй обнаружил (это интервью я читал почти сразу после его появления), и посмотреть действительно ли это круто на практике. Другое дело: я не смог этого понять из вашей статьи. Собственно, я уже об этом писал.
                    Планка того как может работать ООП после Smalltalk-а поднята довольно высоко. И, к примеру, чистота там играет довольно существенную роль. По крайней мере, очень часто наиболее красивые и мощные решения получаются там, где «все есть объект». И напротив: много проблем возникает именно там, где от этого принципа отходят. А уж после мейнстримовых языков к отрицанию данного принципа относишься оооочень настороженно :)
                    Не забывайте, что имеет место сильная зашоренность на тему ООП.
                    Именно против этой зашоренности я и возражаю! И поймите мое этакое разочарование(: вы начинаете с разбора «истоков», что просто замечательно, но в итоге скатываетесь туда же, куда и мейнстрим, да еще и подгоняете цитаты и определения под это дело. Я прекрасно понимаю, что и меня обвиняют в том же ;) И мне данная дискуссия помогла понять, что в отличие от споров с поклонниками триады «инкапсуляция–наследование–полиморфизм» (которые зачастую даже не хотят четко сформулировать свою позицию), мы как раз сходимся в том, что ООП шире и мощнее, чем попытка его пародии в мейнстримовом сознании. Пытаться трактовать цитаты в данном случае — скорее всего, путь в никуда. Тем более, ограничиваясь только цитатами Кэя — учитывая, что он таки не один работал над проблемой… Судя по всему (или даже наверняка), даже в коллективе разработчиков того же Smalltalk были разные точки зрения.

                    В общем, если вы примите совет, то я бы на вашем месте попробовал найти хорошие примеры использования «силы» :) настоящего ООП в Erlang-е.


                    1. Source
                      17.08.2016 14:28

                      В принципе я понял Вашу позицию. Для Вас «всё есть объект» имеет некий практический смысл. А в моей картине мира это лишь интересная теоретическая идея, типа абсолютно чистого функционального языка.
                      На практике зачастую вырождающаяся в «объекты ради объектов» и «чистоту ради чистоты». Как говорится, гладко было на бумаге, да забыли про овраги.


                      1. chaetal
                        17.08.2016 14:47

                        А как насчет «чистоты ради простоты»?


                        1. Source
                          17.08.2016 14:56
                          +1

                          Ну да, оборачивать всё в монады и смиряться с побочными эффектами, куда уж проще… Хотя допускаю, что при определенном типе мышления, и это может стать простым.
                          Однако что одна, что другая идея на практике не реализуема на 100%. Программа без побочных эффектов никому не нужна. То же самое и с объектами, программа, которая работает только с объектами — это вещь в себе, она не пишет в файлы, не рендерит странички в html, не принимает пользовательский ввод, не пишет в БД (хотя может ООСУБД ещё кто-то использует?) и т.д.


                          1. chaetal
                            17.08.2016 16:36

                            Как ни странно, разрабатывая все на том же Smalltalk-е, я на практике имею дело только с объектами. А про монады и слышать не хочу :) И при этом я могу и писать в файлы, и делать веб-приложиения, и работать с БД (и с реляционными, и с нереляционными, в том числе и с объектными — да используют, и весьма успешно), и даже принимать пользовательский ввод (как это ни удивительно для интерактивной среды). :)


                            1. Source
                              17.08.2016 17:35

                              Это не странно. Это просто неизбежное нарушение концепции «всё есть объект». Не можете Вы послать объекты ни в файл, ни в реляционную БД, там будет что угодно: строки, бинарные последовательности, числа, массивы, но только не объекты :-)
                              Наличие хотя бы автораспаковывания/упаковывания данных необходимо для всех вышеперечисленных задач.


                              1. chaetal
                                17.08.2016 19:59

                                Да мне не интересно, что там «внутри», для меня — все это объекты, поскольку работаю я с ними всеми как с объектами. И никакого нарушения, если не буду залезать слишком глубоко и придираться, не обнаружу. Это в Smalltalk-е. Даже когда буду не то что коллекцию обрабатывать, а банальный цикл или даже «if» писать — все равно буду объектам слать сообщения. Вот ни на секундочку не прекращу… А в Erlang-е — и обнаружу, и буду постоянно переключаться между ООП и ФП (если я вас правильно понял).

                                :) Вы меня реально за идиота принимаете? Уже не в первый раз притом :) Вы действительно считаете, что я не понимаю, что рекурсия где-то должна кончится? что не имею представления о том, как работает современный компьютер? что не понимаю, что рекурсия должна где-то закончится?


                                1. Source
                                  17.08.2016 23:29

                                  Да мне не интересно, что там «внутри»
                                  Вот! Именно это я Вам вчера и писал!
                                  ООП не интересует что там внутри. В нашем случае внутри акторов: ФП и обычные типы данных.

                                  Даже когда буду не то что коллекцию обрабатывать, а банальный цикл или даже «if» писать — все равно буду объектам слать сообщения.
                                  И какому же объекту уйдёт ваше while или if сообщение? Я понимаю, что можно фантазию подключить и выдумать вспомогательные объекты. Вопрос только нафига?

                                  Вы меня реально за идиота принимаете? Уже не в первый раз притом :) Вы действительно считаете, что я не понимаю, что рекурсия где-то должна кончится?
                                  Я просто не понимаю, почему Вы считаете принципиальным на каком моменте эта рекурсия закончится.
                                  Вот на мой взгляд, добавление к числу объектного поведения капитально усложняет работу с числами, зачем тогда мне рекурсивно превращать их в объекты?
                                  Попробуйте в ООП-стиле написать код для вычисления суммы квадратов натуральных чисел от 1 до n. Для примера реализация на Elixir:
                                  Enum.reduce(1..n, &(&1*&1 + &2))
                                  


                                  1. chaetal
                                    18.08.2016 07:45

                                    ООП не интересует что там внутри.<…>Я просто не понимаю, почему Вы считаете принципиальным на каком моменте эта рекурсия закончится.
                                    У меня есть ощущение, что вы просто не хотите это понять :) Могу ошибаться. Но все же очень просто. Есть ведь разница между «меня не интересует» и «ООП не интересует»? Я сомневаюсь, что ООП обладает сознанием, но даже если так, то со мной своими переживаниями не делится. А вот меня действительно мало интересует устройство объектов — до тех пор, пока они остаются объектами и мне не приходится постоянно переключать «режим» сознания при работе с сущностями различного рода. Понимаете? Граница проходит либо по языку либо «где-то за ним» — и это существенно. В первом случае мне приходится разговаривать на двух языках одновременно — и это сложнее, чем на одном (во втором случае). В Smalltalk-е граница совсем чуть-чуть залезает в язык, что изредка мешает.
                                    И какому же объекту уйдёт ваше while или if сообщение?
                                    (someObject checkCondition) ifTrue: […] ifFalse: [].
                                    [someObject checkCondition] whileTrue: […].
                                    
                                    Соответственно, if уходит экземпляру подкласса Boolean (там отдельно есть True и False), а while — блоку.
                                    Попробуйте в ООП-стиле написать код для вычисления суммы квадратов натуральных чисел от 1 до n.
                                    (1 to: n) inject: 0 into: [:sum :each | sum + each squared]
                                    Для примера реализация на Elixir:
                                    Enum.reduce(1..n, &(&1*&1 + &2))
                                    
                                    Вы уверены, что это сработает правильно? Видимо, в Smalltalk reduce работает иначе, приходится фокусничать:
                                    (0 to: n) reduce: [:a :b | a + b squared]. 
                                    


                                    1. chaetal
                                      18.08.2016 08:01

                                      Да, можно же с 1, ведь 1*1 = 1. Но все равно фокус :)


                                      1. Source
                                        18.08.2016 12:22

                                        Ok, пусть будет так:

                                        Enum.reduce(1..n, 0, &(&1*&1 + &2))
                                        

                                        чтобы без фокусов )))


                                        1. chaetal
                                          18.08.2016 13:19

                                          Я имею ввиду, что, если последовательность аргументов совпадает с их порядков в коллекции, то, вроде бы, надо написать &1 + &2*&2. Нет? А то сумма будет все время возводится в квадрат, а добавляться будет очередное число без квадрата. Нет?


                                    1. Source
                                      18.08.2016 11:39

                                      Есть ведь разница между «меня не интересует» и «ООП не интересует»? Я сомневаюсь, что ООП обладает сознанием, но даже если так, то со мной своими переживаниями не делится.
                                      Не придирайтесь… Это всего лишь сокращение для «Во время применения ООП нас не интересует»

                                      мне не приходится постоянно переключать «режим» сознания при работе с сущностями различного рода. Понимаете?
                                      Честно говоря, не понимаю в чём проблема. Мы в жизни постоянно переключаемся между сущностями различного рода, можно сказать, это дефолтное восприятие человека. Вы по-любому переключаетесь, когда говорите о массивах, строках, числах. Просто делаете вид, что это типа тоже объекты. Если бы можно было бы оставаться всегда на уровне объектов, не переключаясь, Вы бы названия обычных типов данных вообще забыли бы.

                                      (0 to: n) reduce: [:a :b | a + b squared].
                                      Кхм, и в каком месте тут униформность?
                                      если вызов метода записывается как
                                      object method: arg
                                      то что такое квадратные скобки? что такое a + b? что такое b squared? что такое ":a :b |"?
                                      Даже реализация такого микропримера совсем не униформна, о каком отсутствии «переключений» тогда вообще говорить…


                                      1. chaetal
                                        18.08.2016 13:11

                                        что такое a + b?
                                        Объекту в a посылается сообщение + b.
                                        что такое b squared?
                                        Объекту в b посылается сообщение squared.
                                        что такое квадратные скобки?
                                        Синтаксический сахар для создания объекта, представляющего лексическое замыкание.
                                        что такое ":a :b |"?
                                        Синтаксический сахар для помещения в лексическое замыкание объектов, представляющих переменные с соответствующими именами.

                                        Я уже много раз говорил: Smalltalk не идеален с точки зрения чистоты ООП (да и с некоторых других точек зрения). И, к примеру, последний синтаксис реально выбивается из концепции посылки сообщений — в процессе программирования это прерывает поток.

                                        Но: 1) все то же самое можно (несколько длиннее) написать на «чистых» сообщениях; 2) все то же самое (с некоторым усложнением парсера и, возможно, ВМ) можно реализовать примерно на таком же синтаксисе при сохранении «чистых» сообщений.

                                        Просто Smalltalk в какой-то момент оказался (о чем жаловался тот же Кэй) сложным и соответственно инертным в развитии. Есть веские причины полагать, что основным виновником стала как раз обсуждаемая тема: от объектов отказались слишком рано на пути от верхних уровней абстракции к нижним уровням реализации. Сделать это пришлось, как я понимаю, главным образом в угоду производительности. Не забываем — это середина и вторая половина 70-х с соответствующими скоростями и объемами памяти в компьютерной технике. Скажем, уже в Self (середина 80-х) от части таких проблем уже удалось уйти. Думаю, если бы мейнстрим и массовые сознание не властвовали над нами, давно уже могло бы развиться и дальше.


                                        1. Source
                                          18.08.2016 13:38

                                          Понимаете, наличие синтаксического сахара говорит о том, что концепция в чистом виде не слишком удобна и/или трудна для понимания. И тут встаёт выбор «вам шашечки (чистоту концепции) или ехать (возможность эффективно решать задачи)».
                                          То, что теоретически что-то возможно, не делает это автоматически удобным для всех. C Lisp похожая ситуация, концепция изящна и удивительно проста. Но для легкости восприятия требуется либо отходить от привычного мышления, либо увешиваться синтаксическим сахаром.
                                          Поэтому ни Smalltalk, ни Lisp и не захватили мейнстрим… среднестатистическому программисту банально не удобно с любой униформностью. Да и в физической реальности нас окружает наблюдаемое многообразие, а униформность остаётся теоретической концепцией.


                                          1. chaetal
                                            18.08.2016 13:54

                                            Понимаете, наличие синтаксического сахара говорит о том, что концепция в чистом виде не слишком удобна и/или трудна для понимания.
                                            … или для реализации.
                                            И тут встаёт выбор «вам шашечки (чистоту концепции) или ехать (возможность эффективно решать задачи)».
                                            Если бы тут было «исключающее или», мы бы до сих пор программировали на ассемблере. Вы продолжаете настаивать на «чистоте» как некоторой никому не нужной блажи. Из ваших высказываний получается, что логика такая: нет систем, которые бы я знал и где соблюдался этот принцип => принцип не нужен (да и не реализуем). Если вы так и не видите язъяна здесь, что ж… я признаю свою бессилие :)
                                            Поэтому ни Smalltalk, ни Lisp и не захватили мейнстрим… среднестатистическому программисту банально не удобно с любой униформностью.
                                            Давайте не будем касаться это темы: вы не в курсе, почему Smalltalk «не завхватил мейнстрим», да и «среднестатистический программист» не излагал вам свои проблемы.


                                            1. Source
                                              18.08.2016 14:59

                                              … или для реализации.
                                              В Lisp же принцип реализован, можно униформно программировать на голом AST, а синтаксический сахар всё равно добавляют.

                                              Из ваших высказываний получается, что логика такая: нет систем, которые бы я знал и где соблюдался этот принцип => принцип не нужен
                                              Не совсем, во-первых системы есть. А во-вторых, логика такая: увеличение уровня чистоты принципа не даёт соразмерного увеличения практической пользы. И даже наоборот отход от чистоты частенько позволяет решать задачи эффективнее.
                                              К примеру, b squared — чище, b * b — понятнее
                                              a +: b — чище (только не работает почему-то),
                                              a + b — понятнее.


                                              1. chaetal
                                                18.08.2016 15:40

                                                К примеру, b squared — чище, b * b — понятнее
                                                Ну, напишите там b * b — это тоже сообщение. Только squared как раз показывает намерение и понятнее, вы же сами сформулировали: «сумма квадратов», а не «сумма произведений на самого себя».
                                                увеличение уровня чистоты принципа не даёт соразмерного увеличения практической пользы
                                                От принципа, я так понимаю, это по-вашему не зависит?


                                                1. Source
                                                  18.08.2016 16:02

                                                  Ну, напишите там b * b — это тоже сообщение.
                                                  Я хотел написать b *: b, чтобы униформно было, но оказалось, что так нельзя (

                                                  Только squared как раз показывает намерение и понятнее, вы же сами сформулировали: «сумма квадратов»
                                                  С этим согласен… Только вот мне интересно, для кубов тоже библиотечный метод есть? )

                                                  От принципа, я так понимаю, это по-вашему не зависит?
                                                  Это уже философия… но вообще да, если принцип направлен на предельную минимизацию кол-ва концепций.
                                                  Потому что на каком-то этапе наступает конфликт с другим принципом: «Всё должно быть так просто, как только возможно, но не проще»


                                                  1. chaetal
                                                    18.08.2016 16:12

                                                    Я хотел написать b *: b, чтобы униформно было, но оказалось, что так нельзя (
                                                    В синтаксисе Smalltalk-а предусмотрено три вида сообщений (в их названиях можно проследить функциональные корни, кстати — получатель считается как аргумент): унарные (без аргументов; squared — как раз пример такого), бинарные (ровно один аргумент; + и * — примеры) и «с ключевыми словами» (сколько угодно аргументов; 1 to: 10 do: [] — два аргумента: 10 и []).

                                                    А что значит «униморфно»? Не знаю такого слова.

                                                    Только вот мне интересно, для кубов тоже библиотечный метод есть? )
                                                    Может и есть — зависит от реализации, я точно не помню. Но вся фишка в том, что если «нету, а нужен», то просто берете и добавляете. Мы этого, вроде как, даже не касались? «Все объект» — означает в том числе и то, что я могу изменить в системе все что угодно. В том числе «библиотечные» объекты. Но вы же скажете, что это не нужно…


                                                    1. lair
                                                      18.08.2016 16:37
                                                      +1

                                                      «Все объект» — означает в том числе и то, что я могу изменить в системе все что угодно.

                                                      Э нет. Можно иметь систему, в которой все объект, но при этом ничего не мочь изменить. А можно иметь систему, в которой вообще нет объектов, но мочь изменить что угодно. Это не связанные вещи.


                                                      1. chaetal
                                                        20.08.2016 11:12

                                                        Можно иметь систему, в которой все объект, но при этом ничего не мочь изменить.
                                                        Зависит от нашего желания. Если у нас «все объект», и мы заложили в понятие объекта (не в смысле определения) возможность менять его поведение (что логично для системы, в которой мы собираемся что-то разрабатывать), то мы сможем это делать с любым объектом (если, опять же — по своему желанию — не захотим это запретить). На случай если захочется здесь развернуть дискуссия — я не собираюсь в этот тезис «упарываться». По факту в (более-менее) «нормальных» объектных системах (Smalltalk, Self — как минимум) это так.


                                                        1. lair
                                                          20.08.2016 18:00

                                                          Зависит от нашего желания.

                                                          Вот именно, что зависит. И если у нас было такое желание, то мы его реализовали, и с постулатом "все есть объект" оно не связано.


                                                          . Если у нас «все объект», и мы заложили в понятие объекта (не в смысле определения) возможность менять его поведение (что логично для системы, в которой мы собираемся что-то разрабатывать

                                                          А вот для меня это не логично. Я хочу, чтобы части системы были стабильны, и их нельзя было менять.


                                                          1. chaetal
                                                            20.08.2016 18:44

                                                            Я хочу, чтобы части системы были стабильны, и их нельзя было менять.
                                                            Ну и не меняйте.


                                                            1. lair
                                                              20.08.2016 18:59

                                                              Нельзя было.


                                                              1. chaetal
                                                                20.08.2016 19:04

                                                                Запретите.


                                                                1. lair
                                                                  20.08.2016 19:29

                                                                  … вот и нет возможности менять поведение любого объекта.


                                                                  1. chaetal
                                                                    20.08.2016 19:35

                                                                    Это было ваше желание — соответственно ваша проблема. Собственно, в мейнстриме так и делают, а потом борются с созданными проблемами.


                                                                    1. lair
                                                                      20.08.2016 19:36

                                                                      Вот только у меня нет проблемы: я не считаю, что отсутствие возможности поменять стандартную библиотеку — проблема.


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


                                                                      1. chaetal
                                                                        20.08.2016 20:12

                                                                        Да пожалуйста! Если вам нравится делать одно и то же много раз — это не связанные вещи.

                                                                        А вот если вам вдруг покажется логичным сделать один объект с «базовой функциональностью», включающей возможность создавать новые объекты с отличным от исходного поведением (а значит, менять их) — исходный тезис вдруг может показаться более осмысленным. Но я не настаиваю.


                                                                        1. lair
                                                                          20.08.2016 20:28

                                                                          … а если мне покажется логичным сделать один модуль с базовой функциональностью, включающей возможность создавать новые модули с отличающимся поведением — то у меня "все есть модули", а возможность изменения осталась.


                                                                          Вообще, связывать ООП и легкость повторного использования — это как раз та ловушка, которая приводит к "ООП — это наследование".


                                                                          1. chaetal
                                                                            20.08.2016 20:39

                                                                            А я где-то утверждал, что возможность все изменить есть только в ООП?


                                                                            1. lair
                                                                              20.08.2016 20:42

                                                                              Нет, вы говорили, что из тезиса "все есть объект" автоматически вытекает изменяемость чего угодно.


                                                                              1. chaetal
                                                                                20.08.2016 21:13

                                                                                И я объяснил почему я допустил такую неточность, не так ли?


                                                    1. Source
                                                      18.08.2016 16:49

                                                      А что значит «униморфно»? Не знаю такого слова.
                                                      А почему Вы меня об этом спрашиваете? Я это слово не употреблял.

                                                      я могу изменить в системе все что угодно. В том числе «библиотечные» объекты. Но вы же скажете, что это не нужно…
                                                      Мне этого в Ruby хватило выше крыше. Поверьте, на практике при разработке крупных проектов это ни фига не круто.


                                                      1. chaetal
                                                        20.08.2016 11:16

                                                        А что значит «униморфно»? Не знаю такого слова.

                                                        А почему Вы меня об этом спрашиваете? Я это слово не употреблял.
                                                        Прошу прощения, «обчитался» :)
                                                        Поверьте, на практике при разработке крупных проектов это ни фига не круто.
                                                        «Вы просто не умеете их готовить» :) Либо зря обобщаете свой негативный опыт Ruby.


                                                        1. Source
                                                          20.08.2016 14:20
                                                          +1

                                                          Проблема не в «готовке», а в том, что десятки программистов, не входящие в одну команду, меняют одни и те же классы.
                                                          Приходится всякие хитрости придумывать. Чтобы очередное обновление зависимостей не сломало эти переопределения.
                                                          А как эта проблема решается в Smalltalk?


                                                          1. chaetal
                                                            20.08.2016 18:54

                                                            Я TDD-шник, и побочный эффект этого — тесты — обычно помогают. Smalltalk здесь особо не выделяется, разве что TDD в нем проходит с минимальным «скрипом». А во стольном — все как и везде.


                                                            1. Source
                                                              20.08.2016 19:17

                                                              Не, погодите, что значит «как везде»? Далеко не везде можно переопределить любой метод/функцию из чужой библиотеки, не прибегая к форкам и пулл-реквестам )
                                                              Тесты — ok, допустим у нас 200% покрытия и они даже упали:
                                                              1) Как быстро понять, что дело именно в переопределении? Вы ведь не пишете тесты на стандартную библиотеку и на все зависимости.
                                                              2) Как быстро найти какая из зависимостей в этом виновата?


                                                              1. chaetal
                                                                20.08.2016 19:31

                                                                Далеко не везде можно переопределить любой метод/функцию из чужой библиотеки, не прибегая к форкам и пулл-реквестам )
                                                                Везде есть код, который не контролирует автор и который при обновлении может сломать то, что автор написал.
                                                                1) Как быстро понять, что дело именно в переопределении? Вы ведь не пишете тесты на стандартную библиотеку и на все зависимости.
                                                                Тест есть на поведение моего объекта, непосредственно зависящего от не моего объекта.
                                                                2) Как быстро найти какая из зависимостей в этом виновата?
                                                                Я сталкивался с таким когда-то в VisualWorks — там (насколько я помню) приходилось искать. Но метод же — объект. Нет проблем протащить туда информацию о том, откуда растут ноги. Так ли это в Pharo — надо уточнить. Почему-то больших проблем с этим не возникало — может из-за (меньшего) размера сообщества, может из-за того что не злоупотребляют.


                                      1. chaetal
                                        18.08.2016 13:41

                                        Честно говоря, не понимаю в чём проблема. Мы в жизни постоянно переключаемся между сущностями различного рода, можно сказать, это дефолтное восприятие человека.
                                        Вот, как раз некоторые считают, что дефолтное состояние человека — воспринимать окружающий мир и все сущности в нем как объекты: идентифицировав объект, мы начинаем пытаться на него воздействовать и смотреть, что же будет в ответ. Вроде как это более общая метафора, чем выполнение операций (из наперед заданного, строго ограниченного множества), поскольку я могу попытаться что угодно сделать с объектом — нет ограничений по возможным операциям. Все это спорно, конечно…
                                        Вы по-любому переключаетесь, когда говорите о массивах, строках, числах. Просто делаете вид, что это типа тоже объекты. Если бы можно было бы оставаться всегда на уровне объектов, не переключаясь, Вы бы названия обычных типов данных вообще забыли бы.
                                        Я переключаюсь только между ожидаемым поведением разных объектов и его соответствием тем задачам, которые я хочу решить. Я не переключаюсь между разными способами общения с объектами. Если возникает необходимость так делать, приходится отвлекаться — поток прерывается — решать задачу становится сложнее и дольше. Да, большинство из нас привыкло работать в таком режиме — это не значит, что такой режим лучший.

                                        После долгого (многомесячного, скажем) программирования на Java (где тоже постоянно приходится скакать, так как сам язык «мало-объектный») к Smalltalk привыкаешь минут за 15 и с удовольствием. После даже часового программирования на Smalltalk обратно к Java привыкаешь гораздо дольше и, что самое противное, с неудовольствием. И сразу чувствуешь, как падает производительность — постоянно с объектного мышления по схеме «найти подходящий объект и передать ему нужное сообщение» приходится перепрыгивать на языковые конструкции. Если «к хорошему привыкаешь быстро» говорят не зря, то становится понятным что есть хорошо, а что не очень.

                                        Но, да — это мои личные ощущения. Более объективных обоснований (кроме попыток формально «поймать простоту» — но там пока мне самому не все ясно) у меня нет. Так что, разумеется, есть полное право не соглашаться и продолжать совмещать «типы и объекты». А для меня этот момент является хоть и не самым сильным, но все же аргументом против подробного знакомства с Erlang для изучения ООП.


                                        1. Source
                                          18.08.2016 13:58

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


                                          1. chaetal
                                            18.08.2016 14:02

                                            Как минимум, мы отличаем объекты с поведением (акторы) от объектов без поведения (данные) и принципиально по-разному к ним относимся. Благодаря чему у нас не возникает дилеммы «человек пишет ручкой» или «ручка пишет, используя человека».
                                            Ручка у вас — это данные?


                                            1. Source
                                              18.08.2016 15:03

                                              Да, структура данных. Она обладает свойствами, но не обладает собственным поведением.


                                              1. chaetal
                                                18.08.2016 15:42

                                                А какие свойства есть у ручки?


                                                1. Source
                                                  18.08.2016 16:42
                                                  -1

                                                  Да полно у неё свойств, а какие переносить в программу зависит от задачи. Можно, например, тип и цвет.


                                                  1. chaetal
                                                    20.08.2016 11:18

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

                                                    Если вы не против, то давайте все-таки уточним набор свойств, а так же что понимается под типом?


                                                    1. Source
                                                      20.08.2016 14:32

                                                      Под типом подразумевается тип ручки, допустим: с колпачком или с кнопкой. В зависимости от него актор выберет стратегию работы с ручкой, ну или кинет исключение, если он не умеет работать с ручкой неопознанного типа.
                                                      А по поводу набора свойств, чем Вас не устраивает предложенный? Для большинства реальных применений ручек указанного набора свойств вполне хватает. Естественно, у неё как у любого физического объекта очень много свойств: масса, объём, длина, диаметр корпуса, цвет корпуса и т.д. Но это всё очень редко имеет значение. Так что «тип и цвет чернил» вполне достаточный набор.


                                                      1. chaetal
                                                        20.08.2016 18:59

                                                        Хорошо. А если я захотел дать возможность писать карандашом? пером с чернильницей? палочкой на глиняных таблицах? «пальцем на запотевшем стекле трамвая»?… Я для каждого нового «типа» ручки должен обучать актор работать с ним?


                                  1. iCpu
                                    18.08.2016 07:59
                                    -1

                                    > Попробуйте в ООП-стиле написать код для вычисления суммы квадратов натуральных чисел от 1 до n. Для примера реализация на Elixir:
                                    Попробуйте в функциональном стиле описать работу с пользовательским интерфейсом. Я понимаю, тут постановка задачи — показать несостоятельность ООП подхода, но, например, плюсы
                                    Number Range::reduce(Range range, std::function[Number(Number,Number)],Number init = Number(0)) {
                                    Number val(init); for (i: range) val = function (val, ш); return val;
                                    }
                                    //struct fn { Number operator() (Number a, Number b) {return a + b*b;} };
                                    auto fn = [](Number a,Number b){return a + b*b;};
                                    Range::reduce(Range(1,100),fn); // fn());
                                    Очень лаконично всё описывают.


                                    1. Source
                                      18.08.2016 11:54
                                      +2

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

                                      но, например, плюсы
                                      В Вашем примере куча не-ООП… 0 — это не объект в плюсах, for — не метод, +, * и даже return — это тоже не методы. Так что на униформную ООП-реализацию это точно не тянет.
                                      Очень лаконично всё описывают.
                                      А вот это Вы зачётно пошутили )))


                                  1. Cryvage
                                    18.08.2016 09:53
                                    +3

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

                                    Очень не хотел влезать в спор, но все же хочу кое-что сказать по этому поводу. Лично для меня, придание примитивным типам объектности, всегда имело смысл не в том, чтобы, собственно, работать с примитивными типами, как с объектами, а в том, чтобы иметь возможность работать с объектами, как с примитивными типами. Просто если в языке нет разницы между примитивным типом и объектом (а основной смысл добавления объектности к примитивному типу в том, чтобы стереть эту разницу), то я могу создать свой тип, который со стороны сможет вести себя так же как, например, дробное число (реализовывать все его интерфейсы), а внутри все будет устроено так, как мне надо. Вот не понравилось мне, что есть только float и double. Мало мне показалось. Написал свой тип и назвал triple. И он ничем не «хуже» встроенных типов. Язык получается расширяемым. Можно так же добавить quadruple, quintuple и т.д. пока не надоест.
                                    Что касается усложнения примитивных типов, то лично я его не заметил. Серьезно, я ни разу не замечал, чтобы мне, например, в C# делать арифметику со встроенными типами было сложнее, чем в Си. Внутри типы может быть и сложнее устроены, но мне-то, как разработчику, пишущему на этом языке, что с того? Я работаю с ними не внутри, а снаружи, как с черными ящиками. Зато, если понадобится использовать нестандартный числовой тип, то в том же Си будет существенное синтаксическое отличие. Вот решили мы отказаться от чисел с плавающей точкой, и до последнего все расчеты делать в простых дробях. По сути, все операции над пользовательской структурой (числитель/знаменатель) придется делать с помощью функций. А в C# достаточно заменить тип у переменных, а все остальное останется как было. Куда уж проще? Я не говорю, что без ООП подобного не добиться. И даже не говорю, что подобный функционал необходим. Просто не вижу проблем от того, что простые типы стали объектами. Зато у нас появляется унификация. Все типы равны между собой. И даже встроенные типы не «равнее» пользовательских. По-моему это здорово.


                                    1. lair
                                      18.08.2016 11:50
                                      +2

                                      … вот только для описанного вами не надо, чтобы примитивные типы были объектами. Надо, чтобы в языке было как можно меньше операций, на которые вы не можете повлиять. В частности, в вашем случае вы можете определить математические операции (но, к сожалению, не операции в модуле Math) не только для встроенных математических типов, но и для своих.


                                      Все типы равны между собой.

                                      Вот в C#-то это точно не так. Чего стоит одна только разница между value types и reference types.


                                      1. chaetal
                                        18.08.2016 14:04

                                        Надо, чтобы в языке было как можно меньше операций, на которые вы не можете повлиять.
                                        …а в идеале?…


                                        1. lair
                                          18.08.2016 14:06

                                          А в идеале — ни одной.


                                    1. Source
                                      18.08.2016 12:13

                                      Лично для меня, придание примитивным типам объектности, всегда имело смысл не в том, чтобы, собственно, работать с примитивными типами, как с объектами, а в том, чтобы иметь возможность работать с объектами, как с примитивными типами.
                                      Хорошее дополнение в дискуссию. На мой взгляд, для расширения примитивных типов хватит и структур, над которыми имеется возможность определить любые операторы. Так ведь?

                                      я ни разу не замечал, чтобы мне, например, в C# делать арифметику со встроенными типами было сложнее, чем в Си.
                                      Загляните в IL-код, там нет никаких объектов для чисел. Но не задумываясь о разнице между числами и объектами, Вы легко можете написать код, где в цикле возникнет какой-нибудь box int32. И удар по производительности обеспечен. Смысл не в том, что нельзя работать с числами как с объектами. Смысл в том, что нельзя забывать, что число — это число, а объектом оно только притворяется. Поэтому переключение сознания между объектами и примитивными типами данных неизбежно для написания нормального кода.


                                  1. chaetal
                                    18.08.2016 13:56

                                    Вот на мой взгляд, добавление к числу объектного поведения капитально усложняет работу с числами,
                                    Забыл уточнить: на основании чего вы это утверждаете?


                                    1. Source
                                      18.08.2016 15:10

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


                                      1. chaetal
                                        18.08.2016 15:45

                                        Раз восприятие, значит это относится к программисту по всей видимости? Тогда каким образом это усложняет его восприятие, если он про это даже не знает?


                                        1. lair
                                          18.08.2016 16:40

                                          … если про это не знать, то можно получить много прекрасных побочных эффектов, начиная с уже описанной невозможности блокировки.


                                          1. chaetal
                                            20.08.2016 11:31

                                            Мы же уже обсуждали эти самые «побочные эффекты»? Или я уже путаюсь? :)

                                            Если обсуждали, повторюсь: «побочные эффекты» (в широком смысле слова) являются следствием неудачной реализации; при их обнаружении — поправьте ее так, чтобы поведение объектов было ожидаемым. Не всегда это просто. Более того, допускаю, что это и не всегда возможно — но это не доказано. Я на практике таких примеров не встречал.


                                            1. lair
                                              20.08.2016 18:02

                                              при их обнаружении — поправьте ее так, чтобы поведение объектов было ожидаемым

                                              Легко сказать.


                                              d = a
                                              c = a add b

                                              Чему равно d?


                                              d = a
                                              c = a + b

                                              А теперь?


                                              1. chaetal
                                                20.08.2016 19:08

                                                d равно a в обоих случаях, если сравнение a c самим собой дает «истина»


                                                1. lair
                                                  20.08.2016 19:31
                                                  +1

                                                  А вот и нет Если при d = a происходит копирование, а при a + b — увеличение a, то d не равно a.


                                                  Впрочем, более интересный вопрос состоит в том, равны ли d и c.


                                                  1. chaetal
                                                    20.08.2016 19:52

                                                    А вот и нет
                                                    Так вы пример чистого ООП рассматриваете? У вас d = a — это сообщение = a, посылаемое d? Вы бы формулировали вопросы как-то поаккуратнее и точнее что ли? А то сложно следить за полетом вашей мысли. И создается впечатление, что вы стараетесь просто «подловить» собеседника.

                                                    В этом случае вообще ничего не гарантируется, да. Одни сплошные «побочные эффекты» в широком смысле этого слова. Но вы-то говорите о тех из них, которые приводят к неправильному поведению софта, не так ли? Придется еще подбирать правильные объекты (которые не будут копировать, когда требуется в переменную положить объект).


                                                    1. lair
                                                      20.08.2016 20:25
                                                      +1

                                                      У вас d = a — это сообщение = a, посылаемое d?

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


                                                      В этом случае вообще ничего не гарантируется, да. Одни сплошные «побочные эффекты» в широком смысле этого слова. Но вы-то говорите о тех из них, которые приводят к неправильному поведению софта, не так ли?

                                                      Так побочные эффекты формата "изменилось состояние объекта, от которого я этого не ожидал" — как раз самые страшные (и, кстати, именно поэтому в функциональном программировании так любят неизменное состояние).


                                                      1. chaetal
                                                        20.08.2016 20:36

                                                        А это не принципиально. Это может быть как сообщение, так и поведение языка.
                                                        Если это обычное присваивание, то d = a.
                                                        Так побочные эффекты формата «изменилось состояние объекта, от которого я этого не ожидал» — как раз самые страшные (и, кстати, именно поэтому в функциональном программировании так любят неизменное состояние).
                                                        Ну, да. Проблема известная — надо придумывать, как ее решать. Например, использовать объекты, которые не изменяют свое состояние, если это не нужно.


                                                        1. lair
                                                          20.08.2016 20:39
                                                          +1

                                                          Если это обычное присваивание, то d = a.

                                                          А что такое "обычное присваивание"? Оно для всех объектов работает одинаково?


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

                                                          Воот. Теперь какие-то объекты у нас меняют состояние, а какие-то — нет (иногда еще и при одних и тех же операциях).


                                                          1. chaetal
                                                            20.08.2016 21:01

                                                            А что такое «обычное присваивание»? Оно для всех объектов работает одинаково?
                                                            «Обычное присваивание» обычно означает помещение в объект, представляющий переменную с именем слева от «обычного присваивания», ссылки на объект, представляющий результат вычисления выражения справа от него же. Кстати (упреждая возможные скучные вопросы), в Smalltalk-е (в отличие от Self-а) присваивание — это не сообщение.
                                                            Воот. Теперь какие-то объекты у нас меняют состояние, а какие-то — нет (иногда еще и при одних и тех же операциях).
                                                            У нас всегда одни объекты меняли свое состояние, а другие — нет. Даже при одних и тех же сообщениях. Даже одни и те же объекты при одних и тех же сообщениях.


                                                            1. lair
                                                              20.08.2016 22:24
                                                              +1

                                                              У нас всегда одни объекты меняли свое состояние, а другие — нет. Даже при одних и тех же сообщениях. Даже одни и те же объекты при одних и тех же сообщениях.

                                                              Вы не поверите, как это ужасно звучит для человека, попробовавшее функциональное программирование и чисто immutable-программы. Намного страшнее, чем "не все — объекты".


                                                              1. chaetal
                                                                21.08.2016 11:35

                                                                Охото верю. И давно хочу понять и попробовать, как жить в неизменяемом мире. Есть ощущение, что там — свои проблемы.

                                                                А еще меня успокаивает, что в реальной-то жизни (по крайней мере как я ее воспринимаю) любое воздействие на объект может изменить его состояние — но ничего, как-то оно не падает с Runtime Exception (или я этого не замечаю)… :)


                                                                1. lair
                                                                  21.08.2016 13:01

                                                                  … в реальной жизни вообще многое не так, как в программировании. Например, нельзя легко сделать идентичную копию объекта, меньше проблем с конкурентностью, ну и так далее.


                                                1. Source
                                                  20.08.2016 19:38

                                                  Но не в обоих случаях d равно первоначальному значению a.

                                                  |a b c d|
                                                  a := 1.
                                                  b := 2.
                                                  d := a.
                                                  c := a + b.
                                                  d. "-> 1"
                                                  

                                                  |a b c d|
                                                  a := OrderedCollection newFrom: #(1).
                                                  b := OrderedCollection newFrom: #(2).
                                                  d := a.
                                                  c := a addAll: b.
                                                  d. "-> an OrderedCollection(1 2)"
                                                  


                                                  1. Source
                                                    20.08.2016 19:52

                                                    Вот, кстати, я и на первые грабли Smalltalk наступил:
                                                    «Take care that addAll: also returns its argument, and not the receiver!»
                                                    С чего это вдруг?

                                                    Исправленная версия:

                                                    |a b c d|
                                                    a := 1.
                                                    b := 2.
                                                    d := a.
                                                    c := a + b.
                                                    c. "-> 3"
                                                    d. "-> 1"
                                                    

                                                    |a b c d|
                                                    a := OrderedCollection newFrom: #(1).
                                                    b := OrderedCollection newFrom: #(2).
                                                    d := a.
                                                    c := a addAll: b; yourself.
                                                    c. "-> an OrderedCollection(1 2)"
                                                    d. "-> an OrderedCollection(1 2)"
                                                    


                                                  1. chaetal
                                                    20.08.2016 20:15

                                                    |a b c d|
                                                    a := OrderedCollection newFrom: #(1).
                                                    b := OrderedCollection newFrom: #(2).
                                                    d := a.
                                                    c := a addAll: b.
                                                    d = a.  "-> true"


                                                    1. Source
                                                      20.08.2016 20:34

                                                      Вы за примерами кода пропустили текст комментария:
                                                      «Но не в обоих случаях d равно первоначальному значению a.»


                                                      1. chaetal
                                                        20.08.2016 21:16

                                                        В исходном вопросе слово «первоначальный» не фигурировало, вроде? Я на него отвечал. А то, что объект может изменить свое состояние, получив сообщение, вроде бы и так очевидно?


                                                        1. lair
                                                          20.08.2016 22:27
                                                          +1

                                                          А почему объект 1, получив сообщение + b, не меняет свое состояние?


                                                          1. chaetal
                                                            21.08.2016 11:38

                                                            Потому что это объект, представляющий единицу. Ему не надо менять свое состояние.


                                                        1. Source
                                                          21.08.2016 00:16

                                                          Так исходный вопрос не я задавал )))
                                                          Я дополнил своим уточнением…

                                                          А то, что объект может изменить свое состояние, получив сообщение, вроде бы и так очевидно?
                                                          Это да. И это показывает, что числа — это не совсем объекты даже в Smalltalk. На самом деле закос под объекты очень сильно увеличивает когнитивную нагрузку при программировании.
                                                          Для сравнения, в Elixir акторы при получении сообщения могут менять своё состоянии. А данные — наоборот всегда неизменны.

                                                          P.S. Ну а в ответ на сообщение addAll вернуть аргумент — это вообще саботаж )))


                                                          1. chaetal
                                                            21.08.2016 11:57

                                                            это показывает, что числа — это не совсем объекты даже в Smalltalk
                                                            Может не означает обязан. Существует масса объектов, не изменяющих свое состояние. Я вообще склоняюсь к тому, чтобы не упоминать про состояние (внутреннюю память объекта) в «универсальной» части определения ООП.

                                                            И я никак не пойму, что же вас не устраивает в числах-объектах?
                                                            На самом деле закос под объекты очень сильно увеличивает когнитивную нагрузку при программировании.
                                                            Для сравнения, в Elixir акторы при получении сообщения могут менять своё состоянии. А данные — наоборот всегда неизменны.
                                                            Что такое когнитивная нагрузка? Обращаясь к объекту, вы каждый раз стараетесь вспомнить/понять, изменит объект свое состояние или нет? Если так, то зачем?


                                                            1. Source
                                                              21.08.2016 12:43

                                                              Может не означает обязан. Существует масса объектов, не изменяющих свое состояние.
                                                              Вы правы, не обязан. Только в этом и есть когнитивная нагрузка — каждый раз вспоминать:
                                                              * какие объекты мутабельны, какие иммутабельны
                                                              * на какие сообщения объект вернёт yourself, на какие один из аргументов сообщения, а на какие вернёт новый объект того же типа, что и получатель сообщения

                                                              Получается, что на практике никакого единообразия и в помине нет. Хотя мы ещё даже не добрались до сообщений, результат обработки которых нам не нужно ждать. В Smalltalk есть такие? Или поток выполнения всегда ждёт ответа на сообщение?

                                                              И я никак не пойму, что же вас не устраивает в числах-объектах?
                                                              То, что они только маскируются под объекты.


                                                              1. chaetal
                                                                21.08.2016 13:05

                                                                каждый раз вспоминать:
                                                                * какие объекты мутабельны, какие иммутабельны
                                                                Я как раз выше спросил: зачем это нужно каждый раз знать?
                                                                * на какие сообщения объект вернёт yourself, на какие один из аргументов сообщения, а на какие вернёт новый объект того же типа, что и получатель сообщения
                                                                А когда вы вызываете функцию, вы не должны учитывать, что она вернет?
                                                                То, что они только маскируются под объекты.
                                                                Что вы имеете ввиду? Напомню: это int где-нибудь в Java «маскируется» под объект; а числа в Smalltalk-е являются объектами.


                                                                1. Source
                                                                  21.08.2016 13:49

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

                                                                  А когда вы вызываете функцию, вы не должны учитывать, что она вернет?
                                                                  С функциями всегда очевидно, что она вернёт результат вычисления на базе переданных аргументов.

                                                                  Напомню: это int где-нибудь в Java «маскируется» под объект; а числа в Smalltalk-е являются объектами
                                                                  Неа, даже технически экземпляры SmallInteger в Smalltalk не совсем объекты.
                                                                  Ну а уж концептуально, числа вообще не могут быть объектами, т.к. не обладают собственным поведением.


                                                                  1. chaetal
                                                                    21.08.2016 14:06

                                                                    Мутабельный объект может…
                                                                    Это же не повод пытаться полностью просчитывать все возможные последствия от каждой строчки кода? Есть масса вещей, которые могут заставить систему отработать не так, как мы ожидали. Наверное, даже в Erlang-е или даже в самом Haskell-е?

                                                                    Понятно, что хочется свести это к минимуму. Но есть два пути: стараться как можно больше запретить и «не пущать», а можно не париться и дать возможность пользователю (разработчику) самому сформировать стратегию и тактику написания надежного кода. Сейчас преобладает первая точка зрения, отсюда вся это шумиха вокруг статической типизации и чистого ФП… Но не доказано (по крайней мере пока), что это единственный или более правильный подход. Мне как-то ближе второй.
                                                                    С функциями всегда очевидно, что она вернёт результат вычисления на базе переданных аргументов.
                                                                    С методом тоже очевидно: он вернет результат вычисления на базе переданных аргументов и своего состояния, возможно изменив свое состояние :)
                                                                    Неа, даже технически экземпляры SmallInteger в Smalltalk не совсем объекты.
                                                                    Поясните.
                                                                    Ну а уж концептуально, числа вообще не могут быть объектами, т.к. не обладают собственным поведением.
                                                                    Откройте протокол класса Magnitude или его подкласса и убедитесь, что многие люди считают иначе :)


                                                                    1. lair
                                                                      21.08.2016 14:08
                                                                      +1

                                                                      Откройте протокол класса Magnitude или его подкласса и убедитесь, что многие люди считают иначе :)

                                                                      Сколько из этих методов меняют внутреннее состояние объекта, представляющего число?


                                                                    1. Source
                                                                      21.08.2016 14:47
                                                                      +1

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

                                                                      С методом тоже очевидно: он вернет результат вычисления на базе переданных аргументов и своего состояния, возможно изменив свое состояние :)
                                                                      Так вот нифига. Я выше уже писал про OrderedCollection>>addAll, который с какого-то перепугу тупо вернул свой аргумент, а не результат вычисления. А на тему «возможно изменив свое состояние», зачем я должен об этом думать, когда можно принципиально разделить эти 2 варианта на уровне языка?

                                                                      Откройте протокол класса Magnitude или его подкласса и убедитесь, что многие люди считают иначе :)
                                                                      Ну открыл, вижу что эти люди и с SRP кардинально не согласны :)
                                                                      А вот примеров объектного поведения я там не вижу. Все эти методы можно было бы распределить в несколько подходящих модулей. И это было бы лучше, чем «свалка» в классе Number.


                                                                      1. chaetal
                                                                        23.08.2016 09:07

                                                                        «Не париться» при таком подходе у Вас не получится, ну или надёжный код не получится ) Потому что для надёжности Вам придётся держать в уме детали реализации каждого используемого метода, как бы он там что не изменил.
                                                                        «Не париться» — относилось к системным программистам (разработчикам языка, в частности) и подразумевало «не стараться быть умнее всех разработчиков и не пытаться наставить их на путь истинный, запрещая делать неправильные вещи».

                                                                        А по поводу связи между «надежным кодом» и «держать в уме» — очень спорно, но мне уже не хватает ни времени ни сил развивать эту тему здесь.

                                                                        Я выше уже писал про OrderedCollection>>addAll, который с какого-то перепугу тупо вернул свой аргумент, а не результат вычисления.
                                                                        Авторы метода посчитали, что будет удобнее сделать результатом вычислений добавляемую коллекцию. Я не знаю почему. Возможно, первым пользователям метода было так удобнее, а потом сработал принцип «здесь так принято». По крайней мере, беглый просмотр «посыльщиков» #addAll: дает несколько примеров collection addAll: elements; yourself и ни одного использования аргумента.

                                                                        Но я хочу обратить внимание на другое обстоятельство. ООП предлагает следовать следующей концепции: раз объект сам решает как обработать сообщение, то нельзя жестко «закладываться» на предположения о том, как этот объект обработает сообщение. Вроде бы очень алогичная вещь: как мы вообще можем писать программы в таких условиях?!? И у вас постоянно проскальзывает это недоумение… Но ведь пишут :) И довольно неплохо получается… Предлагаю обдумать этот момент с непредвзятых позиций. Правда, не уверен, что стоит обсуждать это именно здесь.
                                                                        Ну открыл, вижу что эти люди и с SRP кардинально не согласны :)
                                                                        Может, и не согласны — в том смысле, в котором этот принцип трактуете вы. Или есть какие-то другие, более важные принципы, в свете которых SRP — опять же — принимает несколько иное «звучание». Меня лично идеи дяди Боба не очень вдохновляют.
                                                                        Все эти методы можно было бы распределить в несколько подходящих модулей.
                                                                        А они разделены: на категории, на пакеты… На самом деле, это вопрос о соотношении «определяющих принципов» (которые часто очень хочется высечь в камне — и сделать себе жизнь проще, потому что можно будет не думать), и практики (которая зачем-то все время опровергает все эти принципы). Кент Бек в Smalltalk Best Practice Patterns представил концепцию Talking Programs, проиллюстрировав ее прекрасным и очень простым примером.

                                                                        Это очень интересная тема для обсуждения, но (как я уже писал где-то рядом) я не выдерживаю данный формат дискуссии — надо куда-то ее переносить.


                                                                        1. Source
                                                                          23.08.2016 13:10

                                                                          Возможно, первым пользователям метода было так удобнее, а потом сработал принцип «здесь так принято»
                                                                          О том и речь. Когда можно сайд-эффекты замутить над примитивными данными — это рано или поздно приводит к WAT.

                                                                          Вроде бы очень алогичная вещь: как мы вообще можем писать программы в таких условиях?!? И у вас постоянно проскальзывает это недоумение…
                                                                          У меня? У меня на эту тему никакого недоумения нет, потому как процессы в Elixir действительно принимают сообщения, и тот, кто посылает сообщение, даже не догадывается какой функцией оно будет обработано и когда (можно задать только таймаут, после которого сообщение теряет актуальность).
                                                                          А вот в Smalltalk это не так, насколько я понял из PBE. Там посылка сообщения от вызова метода отличается только в теоретическом плане. На практике сообщение обрабатывается одноименным методом и технически от вызова метода это ничем не отличается. Да есть детали реализации, о которых они пишут, типа методы класса-экземпляра. Но фундаментально это ничего не меняет.
                                                                          Хотя может я что-то недопонял… Буду благодарен, если Вы продемонстрируете практическое отличие сообщений в Pharo от вызова метода в Ruby.

                                                                          я не выдерживаю данный формат дискуссии — надо куда-то ее переносить.
                                                                          придётся всё-таки митап по ООП организовывать )))


                                                                          1. chaetal
                                                                            24.08.2016 08:32

                                                                            Когда можно сайд-эффекты замутить над примитивными данными — это рано или поздно приводит к WAT.
                                                                            А в других случаях WAT просто исключен, да?
                                                                            посылка сообщения от вызова метода отличается только в теоретическом плане. На практике сообщение обрабатывается одноименным методом и технически от вызова метода это ничем не отличается.
                                                                            И опять по кругу? Мы уже даже здесь выясняли, чем даже «будничное» связывание по имени метода отличается от вызова метода — ключевые слова: «позднее связывание». Это если не учитывать возможность обработать сообщение, для которого у объекта метода нет вообще. Например, таким образом очень просто и красиво реализуются Mock-и. Подозреваю, что в Ruby присутствуют аналогичные механизмы.


                                                                            1. Source
                                                                              24.08.2016 11:55

                                                                              А в других случаях WAT просто исключен, да?
                                                                              Нет, конечно. Какие-то WAT есть практически в любом ЯП, но больше всего их от сайд-эффектов и от неявного приведения типов.

                                                                              ключевые слова: «позднее связывание»
                                                                              Так позднее связывание сейчас очень во многих ЯП есть. И возможность «обработать сообщение, для которого у объекта метода нет вообще». Точнее метод то есть, он просто работает как fallback, в Ruby он method_missing называется. А в целом это обычный dynamic dispatch.
                                                                              Я ожидал от Smalltalk гораздо большего в этом плане…


                                                                              1. chaetal
                                                                                24.08.2016 12:38

                                                                                Я ожидал от Smalltalk гораздо большего в этом плане…
                                                                                Не знаю, что именно ожидалось :) Smalltalk — это не только язык. Но и язык в своем роде уникален. Собственно, я с другой стороны на это дело смотрю: я ожидал (бы) большего от (ООП-)языков, которые были созданы 10 – 15 – 20 – … лет после Smalltalk. Что, собственно, было существенно хорошего добавлено?


                                                                                1. Source
                                                                                  24.08.2016 13:31

                                                                                  Не знаю, что именно ожидалось :)
                                                                                  Ну как, реальных сообщений, хотя бы как в Erlang :)
                                                                                  В остальном согласен, действительно весьма прогрессивная платформа разработки.


                                                                    1. Source
                                                                      21.08.2016 19:54
                                                                      +1

                                                                      Поясните.

                                                                      LargePositiveInteger new. "-> 0"
                                                                      SmallInteger new. "-> Error: SmallIntegers can only be created by performing arithmetic"
                                                                      

                                                                      Ну и Formal Specification of the Primitive Methods заодно.
                                                                      P.S. Чем больше читаю про Smalltalk, тем сильнее у меня ощущение, что Вы рассказывали про какой-то другой ЯП, потому что в этом униформности точно нет. Не то что бы в этом есть что-то плохое, но это факт.


                                                                      1. chaetal
                                                                        23.08.2016 09:54

                                                                        Нежелание класса отвечать на какое-любо сообщение не делает его экземпляры не объектами.

                                                                        У меня никак не получается сформулировать общее понимание вашего непонимания :) Оно раз за разом повторяется в рамках одного и того же паттерна, но я никак не могу это дело «схватить» и сформулировать… Сюда относятся и утверждение про числа-необъекты, и про примитивы и отход от объектов «внутри», и возврат «не результата вычислений», и что-то еще там в других комментариях… и, судя по всему, эта самая «униформность»… Давайте попробуем через частности:
                                                                        — Что вы понимаете под униформностью?
                                                                        — Где я говорил про униформность Smalltalk? Или в какой части мои «россказни» про Smalltalk не соответствуют действительности?


                                                                        1. lair
                                                                          23.08.2016 11:18

                                                                          Нежелание класса отвечать на какое-любо сообщение не делает его экземпляры не объектами

                                                                          Если объект не отвечает ни на одно сообщение, остается ли он объектом?


                                                                          1. chaetal
                                                                            23.08.2016 11:23

                                                                            Формально, наверное, да. Но держать такой объект в системе смысла нет — все равно его использовать не получится. Так что, к примеру, «данные» в ООП — это не объект без методов, а объект, для которого определены методы, представляющие операции по работе с данными. (Прошу прощения за вложенность, некогда формулировать.)


                                                                        1. Source
                                                                          23.08.2016 14:00

                                                                          Не, ну это не просто нежелание отвечать на какое-то сообщение, это не желание инстанцироваться так же как концептуально аналогичный класс. Они ещё и сравниваются по значению, а дроби уже по ссылке.

                                                                          5 == 5. 
                                                                          "--> true"
                                                                          (1/5) == (1/5). 
                                                                          "--> false"
                                                                          LargePositiveInteger new == LargePositiveInteger new.  
                                                                          "--> false"
                                                                          


                                                                          Что вы понимаете под униформностью?
                                                                          Единообразие, как концептуальное, так и синтаксическое. И как следствие отсутствие неожиданного поведения на уровне языка и стандартной библиотеки.
                                                                          Хороший пример униформности — Scheme, вот ранее обсуждаемая задачка на Racket Scheme:
                                                                          (define (sum-squared-up-to n)
                                                                            (foldl
                                                                              (lambda (x acc) (+ (* x x) acc))
                                                                              0
                                                                              (range 1 (+ n 1))))
                                                                          

                                                                          Синтаксис абсолютно однороден. Концепция чистая, даже без сахара. Всё есть список. Первый элемент списка — имя вызываемой функции, остальные — аргументы для неё.

                                                                          Где я говорил про униформность Smalltalk?
                                                                          Хм, а что мы тогда тут обсуждаем? Насколько я уловил Вашу позицию: «В Elixir униформности нет, не то что в Smalltalk, а как же жить без униформности возможно»


                                                                          1. chaetal
                                                                            24.08.2016 09:19

                                                                            Не, ну это не просто нежелание отвечать на какое-то сообщение, это не желание инстанцироваться так же как концептуально аналогичный класс.
                                                                            Инстанцирование — это всего лишь результат (или сайд-эффект) посылки сообщения.
                                                                            Они ещё и сравниваются по значению, а дроби уже по ссылке.
                                                                            В обоих случаях сообщение == означает сравнение, как вы пишите, по ссылке (сравнение на идентичность). Просто в одном случае (с дробями) в ответ на сообщения возвращается один и тот же объект (что логично: число 1/5 как объект существует в единственном экземпляре), а в другом — разные (поскольку вы просите создать новый экземпляр, передавая сообщение new). Никакого нарушения изначальных договоренностей здесь не наблюдаю: в ответ на сообщение объект возвращает какой-то объект, не оговаривается будет это новый или созданный когда-то ранее. Ясно, что в реальной жизни нужны оба варианта. В чем проблема?


                                                                            1. Source
                                                                              24.08.2016 12:04
                                                                              +1

                                                                              Просто в одном случае (с дробями) в ответ на сообщения возвращается один и тот же объект (что логично: число 1/5 как объект существует в единственном экземпляре)
                                                                              Было бы логично, только в том то и фишка, что возвращаются разные.
                                                                              Обратите внимание, что 1/5 не равна 1/5 в Smalltalk, несмотря на то, что в данном случае это рациональные дроби, а не десятичные.


                                                                              1. chaetal
                                                                                24.08.2016 12:57

                                                                                Ох, это ж надо так лажануть! :) С чего-то я решил, что это 1/5 — это литерал, бредил, видимо… 1/5 — это вычисление и, разумеется, хранить и потом искать все существующие дроби не имеет смысла (производительность упадет). Я почему-то держал в голове Symbol — но там другая история.


                                                                                1. lair
                                                                                  24.08.2016 13:04

                                                                                  … а что будет, если мы заменим 1/5 на 1*5?


                                                                                  1. Source
                                                                                    24.08.2016 13:39

                                                                                    как ни странно будет true

                                                                                    (1*5) == (1*5) "--> true"
                                                                                    

                                                                                    кажется, я совсем запутался с == в Smalltalk :facepalm:


                                                                                    1. lair
                                                                                      24.08.2016 13:50
                                                                                      +1

                                                                                      Если поинтересоваться реализацией SmallInteger (который как раз типичный value type), то ничего странного в этом true нет. Лишнее подтверждение идеи о том, что все абстракции текут.


                                                                                      1. Source
                                                                                        24.08.2016 14:23

                                                                                        Да, это понятно. Странно, что эта несогласованность даже глубже, чем я предполагал:

                                                                                        (10 factorial) == (10 factorial) "--> true"
                                                                                        (15 factorial) == (15 factorial) "--> false"
                                                                                        

                                                                                        Хотя я нашёл всё-таки метод сравнения по значению:
                                                                                        (10 factorial) = (10 factorial) "--> true"
                                                                                        (15 factorial) = (15 factorial) "--> true"
                                                                                        


                                                                                        1. lair
                                                                                          24.08.2016 14:25

                                                                                          Странно, что эта несогласованность даже глубже, чем я предполагал:

                                                                                          Опять-таки, ничего странного. "Smalltalk never overflows", так что результат factorial может иметь разные типы в зависимости не только от типа получателя, но и от его значения.


                                                                                          Но да, для людей с привычкой к статической типизации (включая меня) звучит дико.


                                                                                          1. Source
                                                                                            24.08.2016 15:03

                                                                                            Да не, дико, что разные алгоритмы сравнения для однотипных типов используются, на мой взгляд LargePositiveInteger тоже должен быть value-type. Впрочем, одинарное = частично решает эту несостыковку.


                                                                                            1. lair
                                                                                              24.08.2016 15:04

                                                                                              … и вот тут мы впадаем в ересь "что-то — объекты, а что-то — value types". Ну и понеслась.


                                                                                        1. chaetal
                                                                                          24.08.2016 15:20

                                                                                          Так вы были не в курсе про равенство vs. идентичность?! А я не могу взять в толк, почему вас вопрос о порождении новых объектов в процессе арифметических вычислений так беспокоит… Довольно много лет уже занимаюсь Smalltalk-ом — ни разу из практических соображений не задавался им. …А тут аж какие-то текущие абстракции всплыли :)

                                                                                          По поводу факториала:

                                                                                          10 factorial class. "-> SmallInteger"
                                                                                          15 factorial class. "-> LargeInteger"
                                                                                          


                                                                                          1. Source
                                                                                            24.08.2016 16:05

                                                                                            Я был не в курсе как это в Smalltalk реализовано )))
                                                                                            Понятно, что Smalltalk в этом не виноват, но сейчас = для сравнения редко, где используется.
                                                                                            А абстракция действительно протекает… SmallInteger и LargePositiveInteger ведут себя совсем по-разному и при этом между ними есть неявное приведение типов.


                                                                                            1. chaetal
                                                                                              24.08.2016 17:01

                                                                                              А абстракция действительно протекает… SmallInteger и LargePositiveInteger ведут себя совсем по-разному и при этом между ними есть неявное приведение типов.
                                                                                              Какая именно абстракция протекает? Кто запрещает объектам разных классов (да даже одного класса) вести себя по-разному? Приведения типов — это ваша интерпретация. (Вообще, в Smalltalk-е есть ли типы? «Строгая динамическая типизация» есть, а типов вроде как и нету?:) По факту, есть создание в процессе обработки сообщения объектом некоторого класса экземпляра другого класса. Вы же не это называете «протеканием абстракции»?


                                                                                1. Source
                                                                                  24.08.2016 13:36

                                                                                  Все существующие символы тоже никто не хранит, только те, которые в программе используются. Но это не суть.
                                                                                  Я правильно понял, что привычные «операторы» сравнения никогда не сравнивают по значению в Smalltalk? А иллюзия сравнения по значению возникает только в случаях, когда по факту имеется один объект для обеих сторон сравнения.


                                                                          1. chaetal
                                                                            24.08.2016 09:46

                                                                            Единообразие, как концептуальное, так и синтаксическое. И как следствие отсутствие неожиданного поведения на уровне языка и стандартной библиотеки.
                                                                            Вы действительно считаете, что первое (униформность) гарантирует второе (отсутствие неожиданного поведения)? В программах на Scheme не бывает багов?
                                                                            Синтаксис абсолютно однороден. Всё есть список. Первый элемент списка — имя вызываемой функции, остальные — аргументы для неё.
                                                                            Функция — это тоже список? Да, она задается списком, но это же объект другого рода? И кто-то (кстати кто? это тоже исключение из концепции?) ведь превращает список в функцию? В одних случаях. А в других — в вызов функции. А еще, как я понимаю, тут тоже есть примитивные конструкции, которые не совсем соответствуют исходной концепции? Мне это все кажется полной аналогией того же Smalltalk (что и понятно — последний делался по образцу Lisp-а). Я ошибаюсь?
                                                                            Хм, а что мы тогда тут обсуждаем? Насколько я уловил Вашу позицию: «В Elixir униформности нет, не то что в Smalltalk, а как же жить без униформности возможно»
                                                                            Самое время (спустя много дней и массы букв) это выяснить :)
                                                                            На данный момент я наверное так сформулирую свою позицию. Мне (1) нравятся максимально простые и при этом максимально мощные концепции; (2) хочется перенести такую концепцию в максимально чистом (по крайней мере, в неиспорченном) виде в язык.

                                                                            Концепция, в которую вовлечено два компонента (объект и сообщение) скорее всего проще, чем та, в которой присутствует большее количество. Про мощность — разговор отдельный, но по моим ощущениям ООП не менее мощная, чем ФП, так как в объектах можно смоделировать любую концепцию ФП; к примеру, на том же Smalltalk-е можно построить (был реализован, насколько я знаю) интерпетатор того е Lisp-а.

                                                                            Не уверен, возможно ли в принципе абсолютно выполнить пункт (2) — подтверждающих примеров нет. Smalltalk, хоть он и далек от совершенства, является одним из лучших на сегодняшний компромиссов между этим желанием и реальностью. При этом (на мой взгляд) в Smalltalk-е не «коверкуются» те интенции, которые стояли за ООП (насколько я смог их уловить).


                                                                            1. chaetal
                                                                              24.08.2016 10:07

                                                                              Кстати, давно хотел дать эту ссылку, но всегда за мелочами забывал: Десять вещей, которые я терпеть не могу в ООП. Там можно найти, казалось бы, существенные противоречия с моими утверждениями (в частности и по поводу «все есть объект»), но я вот возьму и заявлю, что я почти со всем в той статье почти согласен :)
                                                                              (Если посмотреть, к примеру, на публикации автора — многое станет понятно)


                                                                              1. Source
                                                                                24.08.2016 13:06

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


                                                                            1. Source
                                                                              24.08.2016 12:48
                                                                              +1

                                                                              гарантирует второе (отсутствие неожиданного поведения)? В программах на Scheme не бывает багов?
                                                                              А как отсутствие неожиданного поведения связано с отсутствием багов? С неожиданным поведением только часть багов связана, причём чаще меньшая, т.к. программисты привыкают к «особенностям» используемого языка.

                                                                              Функция — это тоже список? Да, она задается списком, но это же объект другого рода?
                                                                              Определение функции — это список с вызовом функции define. Да, разумеется, есть с десяток функций, которые реализуются внутри интерпретатора, но для программиста они ведут они себя точно так же, как и все остальные функции.

                                                                              тут тоже есть примитивные конструкции, которые не совсем соответствуют исходной концепции?
                                                                              да вроде нет, можно пример?

                                                                              Ваша позиция понятна, но всё-таки заметно что Вы ей следуете, исходя из того, что неравнодушны к Smalltalk. Это создаёт некоторую предвзятость.

                                                                              Концепция, в которую вовлечено два компонента (объект и сообщение) скорее всего проще, чем та, в которой присутствует большее количество.
                                                                              Вот это не факт. Простота применения ЯП на практике с количеством компонентов в концепции слабо коррелирует.
                                                                              Есть, например, концепция с нулём компонент — «всё есть ничто» и даже соответствующий ЯП. А вот решить на нём практическую задачу совсем не просто :-D

                                                                              по моим ощущениям ООП не менее мощная, чем ФП, так как в объектах можно смоделировать любую концепцию ФП
                                                                              OMFG, зачем? Эти парадигмы совершенно ортогональны. Моя позиция в том, что они должны применяться комплементарно на разных уровнях абстракции. ООП можно применять и в Erlang/Elixir и в диалектах Lisp, но там, где оно реально имеет смысл и пользу. А протаскивание идей ООП через все уровни абстракции вплоть до самых примитивных типов ведёт к излишнему и неоправданному усложнению системы.
                                                                              Собственно изначальная статья посвящена тому, что «Здравствуй ФП» не обозначает «Прощай ООП», оно означает «Здравствуй нормальное ООП, теперь ты будешь работать для меня, а не наоборот»


                                                                              1. chaetal
                                                                                24.08.2016 13:35

                                                                                А как отсутствие неожиданного поведения связано с отсутствием багов?
                                                                                Бага — неожиданное (для разработчика) поведение системы. Нет?

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

                                                                                Но вот списки и функции — они «униформность» ведь не нарушают? Я так понимаю, для вас несколько «параллельных» терминов/понятий в рамках одной концепции — это ОК?

                                                                                Ваша позиция понятна, но всё-таки заметно что Вы ей следуете, исходя из того, что неравнодушны к Smalltalk.
                                                                                «Неравнодушие» к Smalltalk-у определяется тем, что это самая лучшая из известных мне систем, реализующих концепцию и хоть в какой-то степени годных к практическому использованию. Не наоборот.
                                                                                Концепция, в которую вовлечено два компонента (объект и сообщение) скорее всего проще, чем та, в которой присутствует большее количество.

                                                                                Вот это не факт.
                                                                                Да это не факт — поэтому я и написал «скорее всего». Но совсем по другой причине: система, состоящая из N подсистем, может оказаться сложнее системы, состоящей из N+M, если связи между подсистемами первой окажутся сложнее, чем связи во второй. А концепция «с нулем компонент» (с одной все таки?) — действительно проще. Другое дело — возможности, которые она дает. Поэтому я писал и про «мощность».
                                                                                Моя позиция в том, что они должны применяться комплементарно на разных уровнях абстракции.
                                                                                Это я уже давно понял. Но наши позиции как раз тоже не противоречат друг другу. ООП не предполагает как таковой отказ от всего другого. Просто все другое можно реализовать как объекты. Подозреваю, кстати, что ФП — аналогично. А вопрос — в простоте исходных положений. Вам это не интересно, а я считаю, что именно оттуда «растут ноги» у избыточной сложности.


                                                                                1. Source
                                                                                  24.08.2016 14:09
                                                                                  +1

                                                                                  Бага — неожиданное (для разработчика) поведение системы. Нет?
                                                                                  Необязательно, большинство багов встречаются в бизнес-логике или в логике самого программиста (алгоритмов, которые он реализует). В общем, только часть багов связана с неожиданным поведением языка и его стандартной библиотеки.

                                                                                  Но вот списки и функции — они «униформность» ведь не нарушают? Я так понимаю, для вас несколько «параллельных» терминов/понятий в рамках одной концепции — это ОК?
                                                                                  Это лишь для большей понятности. По факту, любой список — это вызов функции, т.е. это не разные понятия, а одно и то же разными словами. Даже «списки-литералы» записываются как вызов функции list:
                                                                                  (list 1 2 3)


                                                                                  А вопрос — в простоте исходных положений. Вам это не интересно, а я считаю, что именно оттуда «растут ноги» у избыточной сложности.

                                                                                  Это всё очень субъективно… Краткость исходных положений не означает простоту. На мой взгляд «всё есть объект» — это очень сложное исходное положение, как в реализации, так и в следовании ему и главное — не отражающее реальное положение дел ни концептуально, ни технически. Т.е. если пытаться следовать этому тезису абсолютно, то вся система будет построена вокруг этой идеи, а не с её помощью.


                                                                                  1. chaetal
                                                                                    24.08.2016 15:36

                                                                                    По факту, любой список — это вызов функции
                                                                                    (1 2 3) — какая функция будет вызвана?


                                                                                    1. Source
                                                                                      24.08.2016 16:07

                                                                                      такая запись вызовет ошибку

                                                                                      application: not a procedure;
                                                                                      expected a procedure that can be applied to arguments
                                                                                      given: 1


                                                                                      1. chaetal
                                                                                        24.08.2016 16:58

                                                                                        Но (1 2 3) — это список в синтаксисе Scheme? Или меня этот сайт обманывает?


                                                                                        1. Source
                                                                                          24.08.2016 17:11

                                                                                          Возможно, я конкретно про Racket реализацию говорю.
                                                                                          Там есть синтаксический сахар, позволяющий записать

                                                                                          '(1 2 3)
                                                                                          
                                                                                          но это эквивалент
                                                                                          (list 1 2 3)
                                                                                          

                                                                                          Просто список, не являющийся вызовом функции, записать нельзя.


                                                                                          1. chaetal
                                                                                            24.08.2016 17:20

                                                                                            Но тогда функция — это же не список?


                                                                                            1. Source
                                                                                              24.08.2016 18:02

                                                                                              В данном случае, функция — это чисто умозрительное понятие, в языке его нет, но при этом:

                                                                                              • Определение функции — это список.
                                                                                              • Вызов функции — это список.


                                                                                              1. chaetal
                                                                                                24.08.2016 18:55

                                                                                                Нет же: (list 1 2 3) — это список? А определение функции — это (define (…) …). Списка же здесь нет? Выглядит похоже, но по факту — совсем разные вещи?


                                                                                                1. Source
                                                                                                  24.08.2016 19:06

                                                                                                  Нет, (list 1 2 3) — это вызов функции list.
                                                                                                  Определение функции — это вызов функции define.
                                                                                                  А вот любой вызов функции — это уже список )))
                                                                                                  Тут по факту всё действительно униформно, т.к. для большинства интерпретаторов/компиляторов (вне зависимости от ЯП) программа — это AST, а тут мы упрощаем работу парсеру, по сути сразу записывая всё в виде AST.
                                                                                                  Также очевидно, что по мощности этот подход мощнее любого другого варианта высокоуровневого языка, т.к. в других концепциях мы можем получить только подмножество возможных AST, разрешенное языком, а тут полное множество.


                                                                                                  1. chaetal
                                                                                                    24.08.2016 19:14

                                                                                                    :) Ну, как так?!? Я спросил:

                                                                                                    (1 2 3) — это список в синтаксисе Scheme?
                                                                                                    Ответ:
                                                                                                    Просто список, не являющийся вызовом функции, записать нельзя.
                                                                                                    То есть, это таки список, но записать его нельзя? При этом
                                                                                                    Определение функции — это список.
                                                                                                    Вызов функции — это список.
                                                                                                    То есть, список записать нельзя, а частные случаи списков — можно?

                                                                                                    Я понимаю, что если не задумываться сильно и не придираться, то это все можно принять. Примерно так же как и «в Smallltalk-е все делается через сообщения, кроме…»


                                                                                                    1. Source
                                                                                                      24.08.2016 19:32

                                                                                                      Тут как и со всеми униформными концепциями возникает путаница в понятиях. Обычно под списком понимают структуру данных, а тут это способ записи программы, в котором первым элементом списка всегда идёт имя функции.
                                                                                                      Поэтому если нужен список, как структура данных, а не как «управляющая конструкция», то вызываем функцию list, ну или какой-нибудь генератор списков. Это и есть униформность, мать её xD


                                                                                  1. chaetal
                                                                                    24.08.2016 15:57

                                                                                    Это всё очень субъективно
                                                                                    Я как раз пытаюсь рассуждать (хоть и на довольно профанско-бытовом уровне) о сложности объективно…
                                                                                    На мой взгляд «всё есть объект» — это очень сложное исходное положение, как в реализации, так и в следовании ему
                                                                                    Как это дело реализовывать и ему следовать — вопрос отдельный. Само утверждение «все сущности в системе являются A» делает систему простой по сравнению с системой, где часть сущностей является А, другая — B, а еще бывают C и D и т.д. Безотносительно к сути A. Работать с группой людей или с группой кошек не сложнее, чем работать с группой, где вперемежку идут люди, обезьяны, тигры, носороги и ядовитые змеи (сам не пойму, почему родилась такая аналогия). Или взять для примера конвейер… Нет?


                                                                                    1. lair
                                                                                      24.08.2016 16:16

                                                                                      На самом деле, нет. Работать с группой людей проще, чем работать с группой "животных" (где среди животных есть люди и носороги). И работать с группой людей и группой носорогов по отдельности проще, чем работать с группой людей и носорогов.


                                                                                      1. chaetal
                                                                                        24.08.2016 17:11

                                                                                        Хорошо, поиграемся словами чуть-чуть — хоть вы и коверкаете исходный смысл моих слов.

                                                                                        Вы хотите сказать, у вас все типы одинаковы? Или же они все разные, с разным набором операций и т.д.? Если так, то по факту у вас те же тигры, обезъяны, змеи и носороги — вперемежку. А еще — отдельно — люди. Но отдельно — условно. Потому что в какой-то момент вам все равно придется вспоминать, что люди — тоже животные и складывать их в ту же кучу. Но это внутри. А снаружи все эти животные выглядят как люди. Так получается?


                                                                                        1. lair
                                                                                          24.08.2016 17:14

                                                                                          Вы хотите сказать, у вас все типы одинаковы?

                                                                                          Нет, не хочу.


                                                                                          Если так, то по факту у вас те же тигры, обезъяны, змеи и носороги — вперемежку.

                                                                                          Это почему вдруг?


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

                                                                                          Ключевой вопрос: а зачем?


                                                                                          1. chaetal
                                                                                            24.08.2016 17:24

                                                                                            Это почему вдруг?
                                                                                            Потому что это разные типы.
                                                                                            Ключевой вопрос: а зачем?
                                                                                            В какой-то момент вам же может захотеться внутри какого-нибудь актора-объекта-человека (где у нас только животные вроде как?) поработать с коллекцией других акторов-объектов-людей?


                                                                                            1. lair
                                                                                              24.08.2016 17:26

                                                                                              Потому что это разные типы.

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


                                                                                              В какой-то момент вам же может захотеться внутри какого-нибудь актора-объекта-человека (где у нас только животные вроде как?) поработать с коллекцией других акторов-объектов-людей?

                                                                                              Извините, я запутался в вашем предложении. Почему внутри "человека" только "животные"? Я вообще не понимаю, что такое "внутри" в этом контексте.


                                                                                              1. chaetal
                                                                                                24.08.2016 17:34

                                                                                                И как из этого вытекает, что они вперемешку? Они разные, я и могу их отдельно держать и обрабатывать.
                                                                                                У вас отдельно функции, которые работают только с целыми числами, отдельно — только с плавающей запятой и совсем отдельно — со строками? :)
                                                                                                Извините, я запутался в вашем предложении.
                                                                                                Ну, это вы переиначили изначальный смысл метафоры. Я попытался развить уже вашу.


                                                                                                1. lair
                                                                                                  24.08.2016 17:37

                                                                                                  У вас отдельно функции, которые работают только с целыми числами, отдельно — только с плавающей запятой и совсем отдельно — со строками?

                                                                                                  У меня могут быть такие функции.


                                                                                                  Ну, это вы переиначили изначальный смысл метафоры. Я попытался развить уже вашу.

                                                                                                  В моей метафоре нет понятия "внутри".


                                                                                                  1. chaetal
                                                                                                    24.08.2016 17:46

                                                                                                    Извините, я запутался в вашем предложении.
                                                                                                    Вопрос, могут ли быть другие. Если да — где же пресловутая униформность?
                                                                                                    В моей метафоре нет понятия «внутри».
                                                                                                    Это понятие есть в контексте применения данной метафоры.


                                                                                                    1. lair
                                                                                                      24.08.2016 17:54

                                                                                                      Вопрос, могут ли быть другие. Если да — где же пресловутая униформность?

                                                                                                      Другие кто? Другие функции? Да, могут. Униформность, например, там, где все целые числа ведут себя одинаково.


                                                                                                      (еще она там, где для любого сложения достаточно написать +, и результат всегда будет относиться к той же группе, что и оба операнда)


                                                                                                      Это понятие есть в контексте применения данной метафоры.

                                                                                                      Я не очень понимаю, где вы взяли этот контекст.


                                                                                    1. Source
                                                                                      24.08.2016 16:18
                                                                                      +1

                                                                                      Само утверждение «все сущности в системе являются A» делает систему простой
                                                                                      Нет. Простой она станет, если все сущности действительно являются А. Но по факту мы имеем систему «Давайте будем считать, что все сущности являются А».


                                                                                      1. chaetal
                                                                                        24.08.2016 17:14

                                                                                        Хорошо. По факту ни одна сущность не является A. Подставьте на место A слово «объект», «процедура», «функция», «список»… — что угодно из программирования. Это все абстракции, которыми сущности по факту не являются.


                                                                                        1. Source
                                                                                          24.08.2016 17:56

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


                                                                                          1. chaetal
                                                                                            24.08.2016 18:05

                                                                                            Разные понятия никуда не пропадут. Просто между ними будет что-то общее — и это позволит с ними работать одинаково (в меру этой общности).


                                                                                            1. lair
                                                                                              24.08.2016 18:16

                                                                                              … вот только это "общее" для разных задач может быть разным.


                                                                                              1. chaetal
                                                                                                24.08.2016 18:56

                                                                                                Для разных задач и есть разное общее. Для самой общей задачи (среды разработки/выполнения) это общее кроется в понятии Object. Для задач, связанных с вычислениями — в Magnitude, ну и т.д.


                                                                                            1. Source
                                                                                              24.08.2016 18:21

                                                                                              Ну а если между двумя понятиями нет ничего общего, то что?
                                                                                              Всё равно подгоним их под общность?


                                                                                              1. chaetal
                                                                                                24.08.2016 19:01

                                                                                                Давайте пример с пояснением, почему нет ничего общего.

                                                                                                Почему оно есть — см. выше: программист должен иметь возможность взаимодействовать (использовать) с любой компонентой в системе (напрямую или опосредованно). Необходимость этого самого взаимодействия — и есть то самое общее.


                                                                                                1. lair
                                                                                                  24.08.2016 19:15
                                                                                                  +1

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


                                                                                                  Ответ же на этот вопрос ("должно ли...") в свою очередь, упирается в то, эффективна ли такая унификация с точки зрения разработки (и с точки зрения реализации средств разработки, и с точки зрения нагрузки на программиста, ими пользующегося).


                                                                                                  (Грубо говоря, человек должен воспринимать и свет, и химический состав (вкус). Но что общего между светом и химическим составом — кроме того, что мы решили, что их надо воспринимать? Можем ли мы построить униформную модель обработки света и химического состава только опираясь на то, что человек воспринимает и то, и другое? Будет ли эта униформная модель нам полезна?)


                                                                                                  1. chaetal
                                                                                                    25.08.2016 08:56

                                                                                                    Я только что дал свой вариант того, почему должно.


                                                                                                    1. lair
                                                                                                      25.08.2016 11:33
                                                                                                      +1

                                                                                                      Я же специально написал: "должно" определяется по эффективности унификации. Я не вижу объяснения, почему вы считаете, что унификация "все есть Х" эффективна.


                                                                                                      1. chaetal
                                                                                                        25.08.2016 11:40

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

                                                                                                        В целом, я чувствую, что дискуссия постепенно теряет смысл — то ли мы добрались до неких базовых (мировоззренческих) вещей, где «на вкус и цвет», то ли просто потеряли все нити :) …Если будет время, я просмотрю затронутые темы и еще раз постараюсь их осмыслить.


                                                                                                        1. lair
                                                                                                          25.08.2016 11:41
                                                                                                          +1

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

                                                                                                          … вы считаете, что создать один механизм, который будет реализовывать все те же варианты внутри себя, по каким-то причинам эффективнее?


                                                                                                          Само взаимодействие-то не униформно, мы это уже выяснили.


                                                                                                1. Source
                                                                                                  24.08.2016 19:21
                                                                                                  +1

                                                                                                  Давайте пример с пояснением, почему нет ничего общего.
                                                                                                  Да у вас с lair уже была дискуссия на тему может ли сообщение быть объектом, не хочется повторяться… Но по сути у них как раз нет ничего общего. Также как у любых данных нет ничего общего с объектами, так же как у функций нет ничего общего с объектами.
                                                                                                  Всё это приводит к созданию довольно монструозных объектных обёрток над простыми сущностями. Все мы видели эти вырожденные объекты для представления лямбда-функции, DTO и т.д.
                                                                                                  Вот и получается, что система в которой есть объекты, данные и
                                                                                                  функции выглядит гораздо изящнее и реалистичнее, чем система, в которой есть только объекты.

                                                                                                  Необходимость этого самого взаимодействия — и есть то самое общее.
                                                                                                  С чего вдруг это должно быть единое взаимодействие? Даже в физике пока его не нашли, аж целых 4 разных до сих пор :-)


                                                            1. lair
                                                              21.08.2016 13:09
                                                              +1

                                                              Обращаясь к объекту, вы каждый раз стараетесь вспомнить/понять, изменит объект свое состояние или нет? Если так, то зачем?

                                                              Да, именно так. Затем, чтобы знать — соседние ссылки на тот же объект будут изменены благодаря этому сообщению, или нет.


                                                              Пример из реальной жизни:


                                                              mappings = GetMappingsForObject();
                                                              _mappings = mappings;
                                                              _filteredMappings = Filter(mappings);
                                                              
                                                              //...
                                                              
                                                              IEnumerable<string> Filter(IEnumerable<Mapping> mappings)
                                                              {
                                                                foreach (var mapping in mappings)
                                                                {
                                                                  mapping.AdjustType();
                                                                  if (IsBasic(mapping.Type))
                                                                    yield mapping.Name;
                                                                }
                                                              }

                                                              Вот метод AdjustType — он меняет состояние Mapping, потому что так проще расчитывать, какие типы какие… и внезапно теперь в _mappings состояние тоже поменялось, хотя из кода это вообще не очевидно. Мы это отлавливали несколько часов (и потом еще чинили ощутимое время).


                                                              1. chaetal
                                                                21.08.2016 13:18

                                                                Мы это отлавливали несколько часов (и потом еще чинили ощутимое время).
                                                                Сочувствую и понимаю — самому таким приходится заниматься время от времени. И…?

                                                                …Вы хотите исключить момент поиска ошибок и отладки из программирования за счет полного отказа от состояния? Сомневаюсь, что даже в ФП это возможно. А если и возможно, то имеет массу других «побочных эффектов» (в самом широком смысле слова). Нет?


                                                                1. lair
                                                                  21.08.2016 13:22
                                                                  +2

                                                                  Сочувствую и понимаю — самому таким приходится заниматься время от времени. И…?

                                                                  И то, что сделав изменяемость состояния униформной, мы можем обезопасить себя от таких ошибок.


                                                                  Сомневаюсь, что даже в ФП это возможно.

                                                                  Добро пожаловать в Erlang.


                                                                  А если и возможно, то имеет массу других «побочных эффектов» (в самом широком смысле слова). Нет?

                                                                  Как раз "побочные эффекты" от этого уменьшаются, простите за игру слов. Но да, потребление памяти растет, производительность может падать, типовые алгоритмы перестают быть применимыми — все так. Типичная плата за униформность.


                                                                  1. chaetal
                                                                    21.08.2016 13:26

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


                                                                    1. lair
                                                                      21.08.2016 13:30
                                                                      +1

                                                                      Поясните, пожалуйста.

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


                                                                      Типичная — да. Обязательная — не факт.

                                                                      Да обязательная, обязательная. Не существует zero-cost abstractions, мир не униформен. Чем больше вы хотите охватить своей абстракцией, тем тоньше она будет растянута, тем сильнее она будет течь.


                                                                      1. chaetal
                                                                        21.08.2016 13:44

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


                                                                        1. lair
                                                                          21.08.2016 13:48
                                                                          +1

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


                                                                          Это радикально повышает мои накладные расходы (как во время разработки, так и во время выполнения)


                                                                          1. chaetal
                                                                            21.08.2016 14:07
                                                                            -1

                                                                            Развивайте инструменты, которыми пользуетесь :)


                                                                            1. lair
                                                                              21.08.2016 14:08

                                                                              Это в лучшем случае уменьшит мои накладные расходы, но не сведет их к нулю.


                                                                              1. chaetal
                                                                                21.08.2016 14:10

                                                                                Напрашивается вопрос «откуда вы знаете», но не хочу его задавать. Давайте на этом остановимся.


                                                                                1. lair
                                                                                  21.08.2016 14:10

                                                                                  Из отсутствия zero-cost abstractions я это знаю.


                                                                                  1. chaetal
                                                                                    21.08.2016 14:12

                                                                                    Значит, в вашей модели вселенной выхода нет.


                                                                                    1. lair
                                                                                      21.08.2016 14:12

                                                                                      О нет, в моей модели вселенной выходов больше одного.


                                                                                    1. lair
                                                                                      21.08.2016 14:21
                                                                                      +1

                                                                                      … в частности, простой выход для этой конкретной проблемы состоит в том, чтобы сказать: есть объекты, и есть значения (важно, не примитивные типы, а именно значения), внутреннее состояние объектов изменяемо, внутреннее состояние значений неизменно. Дальше я могу рассуждать — и описывать контракты — в этих двух терминах, резко снизив количество раз, когда мне надо задуматься, как я могу работать с конкретной сущностью.


                                                                              1. chaetal
                                                                                21.08.2016 14:12

                                                                                Значит, в вашей модели вселенной выхода нет.


                                                            1. lair
                                                              21.08.2016 13:15

                                                              Я вообще склоняюсь к тому, чтобы не упоминать про состояние (внутреннюю память объекта) в «универсальной» части определения ООП.

                                                              Я смотрю, вы в своем определении все дальше уходите от Кэевского понимания.


                                                              1. chaetal
                                                                21.08.2016 13:38

                                                                Это на ваше усмотрение. Оно формально не совпадает с тем, как сформулировано в EHoSt, но (на мой взгляд) по сути ему соответствует. Впрочем, я хоть некоторых аспектов своего понимания и касался в разных местах и в разное время, пока не уверен, что оно в достаточной степени сформировано. И не думаю, что здесь подходящее место для подробного обсуждения моих личных взглядов на проблему ООП. Может быть, когда-нибудь соберусь их изложить (если посчитаю, что могу достаточно внятно это сделать) — тогда обсудим.


                                        1. Source
                                          18.08.2016 17:02
                                          +1

                                          Вы меня извините, но чем больше я с Вами общаюсь, тем сильнее ощущение, что Вы преимущественно теоретик.
                                          У меня нет опыта работы с Smalltalk, но если взять допустим C#, то концепция «всё есть объект» течёт там как дырявое решето на каждом шагу. И ничего путного Вы не напишете, если будете слепо её придерживаться.


                                          1. chaetal
                                            20.08.2016 11:26

                                            Вы меня извините, но чем больше я с Вами общаюсь, тем сильнее ощущение, что Вы преимущественно теоретик
                                            Вы считаете это оскорблением? :) Что значит «преимущественно теоретик»? Если, к примеру, человек 40 часов в неделю занимается решением практических задач, но недоволен тем, как приходится это делать и в свободное время пытается понять почему и найти решения — он «преимущественно теоретик»? :)
                                            если взять допустим C#, то концепция «всё есть объект» течёт там как дырявое решето на каждом шагу. И ничего путного Вы не напишете, если будете слепо её придерживаться.
                                            Так ее и не удается слепо придерживаться! И даже не слепо. :)
                                            На самом деле: если на «борьбу за чистоту» приходиться тратить слишком много усилий — оно не имеет смысла. Вы, видимо, не представляете себе, что может быть иначе… и обобщаете.


                                            1. Source
                                              20.08.2016 14:44

                                              Дело не в распределении часов, а в том, что Вы делаете вид, что теоретической красоты достаточно, а то, что на практике это не работает, — это досадная мелочь, не достойная внимания )))

                                              если на «борьбу за чистоту» приходиться тратить слишком много усилий — оно не имеет смысла.
                                              Именно!

                                              Вы, видимо, не представляете себе, что может быть иначе… и обобщаете.
                                              Ну, Вы добились, что я скачал Pharo и прочитал tutorial от ProfStef xD


                                              1. chaetal
                                                20.08.2016 19:12

                                                Дело не в распределении часов, а в том, что Вы делаете вид, что теоретической красоты достаточно, а то, что на практике это не работает, — это досадная мелочь, не достойная внимания )))
                                                Я-то как раз хочу чтобы «теоретическая красота» работала на практике. Меня не очень устраивают оба варианта: и не работающая красота, и работающая (обычно очень условно) некрасота.
                                                Вы добились, что я скачал Pharo и прочитал tutorial от ProfStef xD

                                                Это победа! :)


                                                1. Source
                                                  21.08.2016 13:31

                                                  Я просто не люблю обсуждать то, что в глаза не видел )))
                                                  Возможности IDE впечатляют, хоть сам редактор кода слабоват, зато System Browser, Spotter, Finder (by examples), Debugger реализованы весьма интересно. Думаю, оттуда и дальше будут черпать вдохновение для инструментов разработки под другие языки.
                                                  Что касается, стандартной библиотеки, то она выглядит как ActiveSupport на стероидах — десятки тысяч методов, которые в 99.999% случаев вам не понадобятся… и, насколько я понял, без возможности подключить только нужные, потому что они все сразу в базовых классах реализованы, а не добавлены через композицию.


                                                  1. chaetal
                                                    21.08.2016 13:54

                                                    сам редактор кода слабоват
                                                    Думаю, это следствие того, что довольно редко встречаются методы длиннее нескольких строк. Да и несколько строк — это уже запашок для Smalltalk …по крайней мере, для меня.
                                                    десятки тысяч методов, которые в 99.999% случаев вам не понадобятся… и, насколько я понял, без возможности подключить только нужные, потому что они все сразу в базовых классах реализованы, а не добавлены через композицию
                                                    Может, нам и не понадобятся. Может, нужны для работы самой системы. А даже если и нет — они чем-то сильно мешают? У меня с этим особых проблем не было, лежат себя спокойно и лежат. Бывает, их приходится пролистывать, когда ищешь нужный метод, но это редко — нужные методы редко подбираются путем просмотра всего протокола класса…
                                                    Хотя, на самом деле, считаю, средства управления кодом, безусловно надо развивать дальше… 
                                                    Ну, и многие методы, разумеется, «подгружаются» в классы из пакетов. Состав базового образа Pharo, насколько я понимаю, до сих пор в стадии формирования — система-то относительно молодая (хотя и базируется на «бородатом» Squeak-е)… С другой стороны, я не уверен, что этот процесс когда либо закончится или даже должен закончиться.


                                                    1. Source
                                                      21.08.2016 14:20

                                                      Думаю, это следствие того, что довольно редко встречаются методы длиннее нескольких строк.
                                                      Ну, это в принципе даже плюс. Судя по редактору, типичный метод должен уместиться в 11 строк, включая комментарии.

                                                      А даже если и нет — они чем-то сильно мешают?
                                                      На самом деле спасают только продвинутые средства навигации по всему этому добру. Хотя я не уверен, что даже они позволяют всегда быстро найти то, что нужно. В общем, на мой субъективный взгляд они явно переборщили с набором методов.

                                                      Ну, и многие методы, разумеется, «подгружаются» в классы из пакетов.
                                                      А можно пример? Реально интересно посмотреть.


                                                      1. chaetal
                                                        23.08.2016 08:09
                                                        +1

                                                        Пример расширения класса из пакета?

                                                        Можно открыть Monticello Browser -> выбрать пакет -> Browse: то, что лежит в *Extensions — расширяет уже существующие классы.

                                                        Можно открыть System Browser -> выбрать класс -> в окне протоколов светло-серые начинающиеся с символа * категории — добавленные из других пакетов методы.

                                                        Реализация механизма примитивненькая, куценькая и не очень удобная; унаследована от Squeak, а там, судя по всему, было сделано по принципу The Simplest Thing That Could Possibly Work.


                                                        1. Source
                                                          23.08.2016 13:26

                                                          Спасибо, разобрался. Чтобы по-нормальному расширить базовый класс, надо создать свой пакет, потом перейти к определению класса, добавить протокол *ИмяСвоегоПакета и туда уже нужные методы.
                                                          А в пакете они появятся автомагически сразу после Accept :-)


                                                          1. mwambanatanga
                                                            22.12.2016 05:30

                                                            На Линуксе запускается?


                                                1. Source
                                                  21.08.2016 14:07

                                                  Я-то как раз хочу чтобы «теоретическая красота» работала на практике.
                                                  Тогда Вам реально в Elixir.
                                                  Я намедни ещё на тему модели акторов читал и наткнулся на прекрасное описание Erlang… в нём очень хорошо сформулировано то, что я Вам пытался донести.
                                                  Что касается Elixir, то он добавил в Erlang ещё и метапрограммирование по образцу Lisp. И практически весь его синтаксис построен на макросах времени компиляции.
                                                  Вот, например, реализация синтаксиса для записи диапазонов: kernel.ex#L2597..L2638


                                                  1. chaetal
                                                    21.08.2016 14:08

                                                    Спасибо, обязательно ознакомлюсь!


      1. nwalker
        16.08.2016 17:30
        +1

        Не нужно лепить баззворды без необходимости, вот в чем дело.

        Вообще, «ООП» это очень расплывчато определенное понятие, которое после многих лет странных трактовок лучше перестать употреблять.
        Что такое «инкапсуляция» и «полиморфизм» по отдельности, как работает наследование в C++ или Java или .NET или Python — понятно. Особенности JS или Smalltalk тоже можно изучить. Зачем нужны паттерны проектирования в определенных языках — тоже более менее понятно. То есть, все практически-значимые вопросы не вызывают у меня вопросов.
        Вот только это все почти не имеет отношения к собственно ООП. Что такое ООП в целом — мне непонятно, и, честно говоря, не очень хочется это «понимать». Есть практические реализации ООП как его поняли авторы конкретных языков, это важно понимать. А сферическое ООП в вакууме, о котором тут куча камментов, как минимум ненужно, а то и вредно.


        1. Source
          16.08.2016 18:41

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


          1. lair
            16.08.2016 18:47

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


  1. iCpu
    17.08.2016 06:23
    -4

    Я понял, что мне не нравилось в этой статье. Это не ООП. Это такое же, допустим, заблуждение, как и статья «функциональное программирование на С++». Поясняю:
    ООП, как известно, зиждится на трёх китах: инкапсуляция, наследование, полиморфизм. Вы реализовали только первое из свойств. Наследования нет. Как нет и возможности отделить мухи от котлет, отделить классы с совпадающими методами от классов, реализующих один и тот же интерфейс. Что, вроде как, зовётся полиморфизмом. Нет, вы, конечно, можете подпихнуть pid любого модуля, но, вот незадача, у вас нет встроенного метода узнать, реализует ли он нужный интерфейс или просто имеет пару схожих методов.

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


    1. chaetal
      17.08.2016 08:16

      :) Может быть, вы сформулируете, что такое инкапсуляция и что такое полиморфизм? И как быть с объектно-ориентированным языками без классов — что там с наследованием? Или же вы отрицаете их существование?


      1. iCpu
        17.08.2016 08:46

        Инкапсуляция — объединение данных и методов в класс. Вне зависимости от локальной терминологии — это помещение всех методов-сообщений внутрь класса и сокрытие его внутреннего состояния.
        Наследование — создание нового класса путём дополнения существующего класса новыми свойствами без изменения наследуемого класса.
        Полиморфизм — возможность обращаться к методам класса без явного знания о его конкретном типе. При этом обращение происходит по базовому классу и программист имеет гарантии, что нужный метод будет реализован именно с той сигнатурой, что и в базовом классе.

        И как быть с объектно-ориентированным языками без классов — что там с наследованием?
        Это которые прототипно-ориентированные? Которые Луа и иже с ними?
        А чем они отличаются от аспектно-ориентированных? Посмотрите внимательнее, и окажется, что практически ничем, обыкновенный public class Class extends HashMap<String,Object>, в которых Object может быть кем угодно, от char до function, и получается на лету. А АОП хорошо реализуется через ООП, являясь надстройкой. Так что никак с ними не нужно быть.

        А то, что реализовано в статье, по терминологии Гради Буча называется программированием с помощью абстрактных типов данных.


        1. chaetal
          17.08.2016 08:49

          Это которые прототипно-ориентированные? Которые Луа и иже с ними?
          Это, в первую очередь, Self. К АОП не имеет отношения. Давайте для начала разберемся с ООП без классов, а то эти самые классы у вас на каждом шагу. А потом вернемся к остальным определениям. Не против?


          1. iCpu
            17.08.2016 09:13

            Интересно, чем концептуально, кроме синтаксиса, отличаются Self от, например, JavaScript?
            И чем не укладывается Self в, грубо,

            class Class extends HashMap<String,Object> {
            Class prototype;
            Class setPrototype (Class toCopy) { this = toCopy; prototype = toCopy;}
            }

            Может быть я чего-то не знаю о Self? Всё-таки я его не изучал. Но JavaScript проваливается в это определение чуть ли не по шейку. А он, насколько мне известно, самый что ни на есть прототипно-ориентированный.
            Не против?
            Против.
            То, что есть иные подходы к реализации ООП не отменяет того, что в статье нет реализации ООП.


            1. chaetal
              17.08.2016 09:50

              И чем не укладывается Self в, грубо, <…>
              Как минимум, двумя вещами:
              • Механизмом создания объектов
              • Механизмом связывания сообщения с методом

              Но вопрос-то был в другом: язык без классов может являться объектно-ориентированным или нет?

              Против.
              То, что есть иные подходы к реализации ООП не отменяет того, что в статье нет реализации ООП.
              Ваше определение полностью базируется на понятии класса. (Кстати, вы не определили, что это такое.) Либо мы утверждаем, что без классов ООП не бывает (что, очевидно, не так… но, возможно, не всем очевидно; да и почему бы тогда не назвать это класс-ориентированным программированием? слово «объект» там вообще не фигурирует), либо ваши определения требуют коррекции. Во втором случае мы можем вернуться к вопросу о ООП в данной статье только после соответствующей коррекции.


              1. iCpu
                17.08.2016 10:15
                -4

                Как минимум, двумя вещами:

                1) Объекты либо клонируются с указанием предка, либо создаются с нуля. Интерфейс подобного поведения я указал. Разве чего-то не хватает?
                2) Сигналы-слоты так же запросто реализуются.
                Да, синтаксис будет отличаться, в силу ограничений языка, всё-таки нельзя безболезненно скрестить разные типизации. Это не такие критические вещи, на которые стоило бы обращать внимание в данном контексте.
                Но вопрос-то был в другом: язык без классов может являться объектно-ориентированным или нет?
                А разве в self нет классов? Я вижу как минимум один — объект. Есть ещё базовые типы, которые тоже классы, но, так как концепция не позволяет, мы их так называть не будем, да?
                (Кстати, вы не определили, что это такое.)
                Ну так погуглите. Я вам не учебник по ООП. И гуглите тщательнее, а то в школу обратно попадёте.
                Либо мы утверждаем, что без классов ООП не бывает
                Без либо.


                1. chaetal
                  17.08.2016 11:21

                  И гуглите тщательнее, а то в школу обратно попадёте.
                  Ооо! Ясно, разговор не получится.


            1. lair
              17.08.2016 09:53

              И какие же гарантии того, что "нужный метод реализован именно с той сигнатурой", есть в JavaScript?


              1. iCpu
                17.08.2016 10:16
                -3

                Никаких, потому что это не ООП, а программирование сбрасыванием барахла в коробки.


                1. lair
                  17.08.2016 11:22

                  Ага, то есть в JavaScript — и, по расширению, во всех динамических языках — ООП нет?


                  1. iCpu
                    17.08.2016 11:55
                    -2

                    Для вас это новость? Не буду говорить за абсолютно все динамические языки, но JavaScript — точно не ООП. Не после того, как он впитал в себя ПОП, АОП и ФП. Почитайте про этот самый JavaScript хотя бы на той же википедии.


                    1. lair
                      17.08.2016 11:59

                      Не буду говорить за абсолютно все динамические языки

                      А что в них может отличаться в этом контексте?


                      JavaScript — точно не ООП. Не после того, как он впитал в себя ПОП, АОП и ФП.

                      Эээ, то есть мультипарадигменные языки не поддерживают каждую из парадигм в отдельности? Это как-то странно.


                      (и если ПОП — это прототипно-ориентированное программирование, то оно является частным случаем объектно-ориентированного)


                      1. iCpu
                        17.08.2016 12:35
                        -3

                        > А что в них может отличаться в этом контексте?
                        Понятия не имею, потому и не говорю.
                        > то есть мультипарадигменные языки не поддерживают каждую из парадигм в отдельности? Это как-то странно
                        Вы же сами меня спросили:
                        > И какие же гарантии того, что «нужный метод реализован именно с той сигнатурой», есть в JavaScript?
                        А теперь потрудитесь объяснить, как так получается, что в ООП у программиста нет гарантированного способа узнать, что у экземпляра определённого класса реализован определённый интерфейс, то есть нужный метод реализован именно с той сигнатурой? Это и не АОП, и не ООП, это уже цирк какой-то. Сбрасывание барахла в коробки. Это был бы ООП, если бы такой класс вызывал бы ошибку на этапе компиляции\интерпритации, но не факт, что вы эту ошибку получите даже в рантайме. Даже вызвав метод с ошибочным интерфейсом.


                        1. lair
                          17.08.2016 12:43
                          +1

                          А теперь потрудитесь объяснить, как так получается, что в ООП у программиста нет гарантированного способа узнать, что у экземпляра определённого класса реализован определённый интерфейс, то есть нужный метод реализован именно с той сигнатурой?

                          А должен быть (гарантированный способ)?


                          Это был бы ООП, если бы такой класс вызывал бы ошибку на этапе компиляции\интерпритации, но не факт, что вы эту ошибку получите даже в рантайме. Даже вызвав метод с ошибочным интерфейсом.

                          Хм. Давайте-ка начнем с простого вопроса: Smalltalk — ООП?


                          1. iCpu
                            17.08.2016 13:29

                            > А должен быть (гарантированный способ)?
                            А разве не это называется классом? Ах, да, мы же отказались от классов, да… А почему мы тогда говорим об объектах? Да, объект — чёрный ящик, но это чёрный ящик с ручками, которые, даже если и прикрутили у меня на виду, всё равно не взялись из воздуха, а лежали рядом с инструкцией на икеевском. Ящик, а не коробка ручек, из которой мы в любой момент можем выкинуть что угодно, не потеряв при этом приемственности. Тогда давайте говорить о контейнерно-ориентированных языках, потому что мы реально забрасываем всё в контейнеры, и копируем контейнеры. И всё.
                            > Давайте-ка начнем с простого
                            Давайте перейдём сразу к сути: вы хотите спросить, почему я называю ООП тот язык, у которого на лету может поменяться как реализация класса, так и интерфейс?
                            Ровно потому, что я могу гарантировать какой-либо интерфейс через механизм наследования. Потому что я определяю интерфейс и реализую его в наследниках, и если я накосячил на одном из уровней, я сразу узнаю, что мой наследник является абстрактным классом, к примеру. Этого более, чем достаточно, чтоы говорить об ООП. Но в JavaScript, по вашим же словам, я такой возможности не имею.


                            1. lair
                              17.08.2016 13:32
                              +1

                              Давайте перейдём сразу к сути: вы хотите спросить, почему я называю ООП тот язык, у которого на лету может поменяться как реализация класса, так и интерфейс?

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


                              1. iCpu
                                17.08.2016 13:39

                                Потому что это динамический язык, а не статический. И в нём до последнего откладывается подобная проверка, потому что
                                >> на лету может поменяться как реализация класса, так и интерфейс
                                Важно не это. Важно то, что я не могу создать наследника класса, в котором не будут реализованы все сообщения прототипа с нужным интерфейсом.


                                1. lair
                                  17.08.2016 13:40
                                  +1

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

                                  … и что? Где гарантия, что в переменной, которой вы посылаете сообщение, лежит объект именно этого класса?


                                  1. iCpu
                                    17.08.2016 19:37
                                    -2

                                    Какие гарантии между классами в динамических языках? Хорошо иметь гарантию внутри своего класса.

                                    В целом я понял, почему практически все динамические языки являются прототипно-ориентированными. Потому что слишком дорого поддерживать классы в динамике. И почему они ООП, все типы являются наследниками типа Object: от целых до классов. И почему у меня не поднимается язык назвать их объектно-ориентированными — кроме «найти содержимое по имени поля», «клонировать другой объект» и стандартных операторов у этих классов нет никаких методов.То есть гарантируемый интерфейс дико скуп, а всё наносное — это, извините, обещания, верить которым — дело лично каждого. Лично у меня фраза «а у нас приличным гражданам принято верить на слово» не вызывает никакого доверия.


                                    1. lair
                                      17.08.2016 21:06
                                      +1

                                      Хорошо иметь гарантию внутри своего класса.

                                      … которых у вас тоже с гулькин нос. Кто-нибудь гарантирует, что все реализации метода возвращают объект, отвечающий на одни и те же сообщения? Кто-нибудь гарантирует, что все реализации метода требуют одинаковых сообщений от входных параметров?


                                      В целом я понял, почему практически все динамические языки являются прототипно-ориентированными.

                                      М? Ruby? PHP? Python?


                                      И почему у меня не поднимается язык назвать их объектно-ориентированными

                                      Ну то есть Smalltalk вы все-таки не называете объектно-ориентированным?


    1. lair
      17.08.2016 09:51
      +1

      Поясняю: ООП, как известно, зиждится на трёх китах: инкапсуляция, наследование, полиморфизм.

      Кому "известно"?


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

      … и это никак не связано с полиморфмизмом, а всего лишь говорит об отсутствии — в этом месте — строгой типизации. Утиный полиморфизм — прекрасная вещь.


      1. iCpu
        17.08.2016 10:23
        -2

        lair, всем, изучавшим ООП, а если вы не в их числе, почитайте любую книжку по ООП.

        … и это никак не связано с полиморфмизмом, а всего лишь говорит об отсутствии — в этом месте — строгой типизации. Утиный полиморфизм — прекрасная вещь.

        Я бы согласился, если бы было наследование. Или если бы был способ узнать, реализован ли нужный интерфейс или нет ДО вызова нужного метода.


        1. lair
          17.08.2016 11:29
          +4

          всем, изучавшим ООП

          Ну, я вот изучал ООП. Автор поста, насколько я понимаю, тоже. chaetal — тоже. Но внезапно, всем троим это не известно.


          почитайте любую книжку по ООП.

          Если завтра выйдет еще одна книжка по ООП, в которой будет сказано, что ООП зиждется на насилии, прелюбодеянии и гордыне — будем ей верить?


          А если серьезно, то есть разные книжки по ООП. Скажем, в Баддсовской "An Introduction To Object Oriented Programming", определение другое. И вообще их много. Даже вики приводит другое определение:


          Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which may contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.

          Я бы согласился, если бы было наследование.

          Наследование для полиморфизма не обязательно.


          Или если бы был способ узнать, реализован ли нужный интерфейс или нет ДО вызова нужного метода.

          То есть, стоит добавить операцию School.isSchool(pid), как немедленно появляется полиморфизм?


          1. iCpu
            17.08.2016 12:15
            -3

            Ну, я вот изучал ООП.
            Видимо по книге, в которой
            сказано, что ООП зиждется на насилии, прелюбодеянии и гордыне
            Почитайте стандарты SIMULA и Smalltalk, основоположников ООП. Там, внезапно, есть и наследование, и полиморфизм, и инкапсуляция.
            А если серьезно, то есть разные книжки по ООП. Скажем, в Баддсовской «An Introduction To Object Oriented Programming», определение другое. И вообще их много.
            Если мы будем брать определения ООП по книжкам для новичков, мы никогда ни к чему не прийдём. Давайте основываться на каких-нибудь обязующих текстах, на стандартах к языкам, к примеру.
            Наследование для полиморфизма не обязательно.
            Для полиморфизма необходимо, как минимум, определить интерфейс взаимодействия. После этого класс должен обязаться его реализовать. Что это, если не наследование?
            То есть, стоит добавить операцию School.isSchool(pid), как немедленно появляется полиморфизм?
            Нет, так как у вас нет способа узнать, чей это метод. Нужно тогда, как минимум, хранить имена всех базовых классов, их методы и параметры, и при каждом вызове искать в таблице, есть у нас такой метод или нет.


            1. lair
              17.08.2016 12:34
              +3

              Почитайте стандарты SIMULA и Smalltalk, основоположников ООП. Там, внезапно, есть и наследование, и полиморфизм, и инкапсуляция.

              (а) пожалуйста, конкретную ссылку
              (б) почему вы считаете, что эти стандарты — определяющие в ООП, а другие определения нерелевантны?


              Если мы будем брать определения ООП по книжкам для новичков, мы никогда ни к чему не прийдём.

              Ага, то есть не все книжки равны?


              Для полиморфизма необходимо, как минимум, определить интерфейс взаимодействия

              Это определение обязано быть в коде? Нет.


              После этого класс должен обязаться его реализовать.

              Это зачем еще? Может и классов не быть же.


              Что это, если не наследование?

              Внезапно, это реализация интерфейса. Которая не обязана быть наследованием.


              Нет, так как у вас нет способа узнать, чей это метод.

              Какой именно метод и что значит "чей"?


              Нужно тогда, как минимум, хранить имена всех базовых классов, их методы и параметры, и при каждом вызове искать в таблице, есть у нас такой метод или нет.

              Извините, но выше вы писали "нужен способ узнать, реализован ли нужный интерфейс". Почему School.isSchool(pid) не удовлетворяет этой фразе?


              1. iCpu
                17.08.2016 13:08
                -3

                > пожалуйста, конкретную ссылку
                Сами найдёте. Не великий труд, всё на вики есть.
                > почему вы считаете, что эти стандарты — определяющие в ООП, а другие определения нерелевантны?
                Давайте котлеты отдельно, а мух — отдельно. Если у нас новые стандарты определяют что-то другое, то давайте этому новому новое, извините за тавтологию, имя. Если у вас есть ООП, а потом появляется ПОП, который может быть реализован через ООП, но, в целом, не обязательно удовлетворяет условиям ООП, так, быть может, не называть его частным случаем ООП? Если у вас ООП, в котором нет наследования, да и, в общем, полиморфизма, так значит, это не ООП, а, скажем, структурное программирование?
                Так уж сложилось, что Симула появилась задолго до всех прочих концепций. Право первого. И, если заложенные на тот момент концепции отличаюся от современного понимания ООП, и вы против изменения привычного вам мира, доназовите старые концепции, введите их в общепринятый лексикон и наслаждайтесь идилией.
                > Ага, то есть не все книжки равны?
                Вы разве не знали? Конечно не равны. То, что можно Зевсу, нельзя быку. То, что можно Аллаху, нельзя Гитлеру. За первую книжку можно засудить человека, а за вторую — сесть в тюрьму, хотя в обеех есть пикантные формулировки.
                Конкретно в вашем примере некорректно сравнивать научно-популярную книжку, в которой всё объясняется на пальцах, и строгий инжинерный\научный язык. Ферштейн?
                > Это определение обязано быть в коде? Нет.
                Да. Или для вас внешний xml — это уже не код, а задний проход?
                > Это зачем еще? Может и классов не быть же.
                Ну так и ООП может не быть. В чём проблема-то?
                > Внезапно, это реализация интерфейса. Которая не обязана быть наследованием.
                Не обязана, конечно. Если вы пропускаете пункт про обязательство его реализовать. А обязательство — это не пустой звук, это, опять же, некоторый унифицированный способ узнать, что ваше творение полностью реализует указанный интерфейс. И, если такой способ есть, ваша реализация становится классом, вне зависимости от вашего желания. Потому что именно и только класс даёт гарантию реализации интерфейса (Если мы вводим полноценное наследование, уместно слово «частичной и полной», в противном случае только «полной»).
                > Извините, но выше вы писали «нужен способ узнать, реализован ли нужный интерфейс». Почему School.isSchool(pid) не удовлетворяет этой фразе?
                А как узнать, реализован ли метод «isSchool»? А как узнать, что это метод «School.isSchool(pid)», а не «Building.isSchool(pid, floors[])? А как узнать, что это „Human.lead(pid, to)“, а не „AlchemistryGenerator.lead(pid, to)“?


                1. lair
                  17.08.2016 13:25
                  +1

                  Если у вас есть ООП, а потом появляется ПОП, который может быть реализован через ООП,

                  Вообще-то, наоборот. ООП может быть реализовано через ПОП.


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

                  Вот только если мы говорим о "праве первого", то (утверждается, что) термин ООП придумал Алан Кэй, и его определениие звучит так: "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things". Впрочем, и в первом его определении наследования нет (хотя вот классы есть).


                  Вы разве не знали? Конечно не равны.

                  Тогда нельзя взять "любую" книжку про ООП, можно брать только конкретную. А дальше возникает вопрос, кто определяет, какая книжка про ООП равнее других...


                  Да. Или для вас внешний xml — это уже не код, а задний проход?

                  При чем тут внешний xml? Интерфейс (точнее — контракт) может быть определен и просто на словах. Он перестал быть контрактом от этого?


                  А обязательство — это не пустой звук, это, опять же, некоторый унифицированный способ узнать, что ваше творение полностью реализует указанный интерфейс.

                  … и где же в определении ООП есть требование такого унифицированного способа?


                  Потому что именно и только класс даёт гарантию реализации интерфейса

                  Оу, вы правда не слышали про анонимные реализации?


                  А как узнать, реализован ли метод «isSchool»?

                  Внезапно, в Elixir есть типизация, которая вам об этом скажет.


                  1. iCpu
                    17.08.2016 14:04
                    -1

                    > то (утверждается, что) термин ООП придумал Алан Кэй,
                    Есть иное мнение.
                    http://c2.com/cgi/wiki?AlanKaysDefinitionOfObjectOriented
                    Кроме того, я не настаивал на том, что именно его определение должно быть определяющим. Во многом, потому, что оно слишком короткое и общее, чтобы стать таковым, под него можно много чего подогнать. Я лишь указывал, что если у нас один термин означает слишком много, нужно добавить терминов. Или использовать формулировки из стандартов, в которых такие моменты будут хорошо прописаны.
                    > Вообще-то, наоборот. ООП может быть реализовано через ПОП.
                    Интересно, как вы введёте классы?
                    > Тогда нельзя взять «любую» книжку про ООП, можно брать только конкретную.
                    Давайте не впадать в оурэлевщину.
                    > При чем тут внешний xml? Интерфейс (точнее — контракт) может быть определен и просто на словах. Он перестал быть контрактом от этого?
                    Проверка выполнения обязательств.
                    > … и где же в определении ООП есть требование такого унифицированного способа?
                    Класс.
                    > Оу, вы правда не слышали про анонимные реализации?
                    Анонимные реализации чего? Класса? То, что вы не дали ему имя, не отнимает у него звания класса. Вы просто делегировали право определить его имя дальше в недра среды исполнения.
                    >Внезапно, в Elixir есть типизация, которая вам об этом скажет.
                    O RLY?


                    1. lair
                      17.08.2016 14:10

                      Есть иное мнение.

                      Есть. Но тогда у вас вообще нет единого мнения об определении ООП.


                      Или использовать формулировки из стандартов, в которых такие моменты будут хорошо прописаны.

                      А кто сказал, что в стандарте правильно сделано? Вы ошибочных стандартов не видели?


                      Интересно, как вы введёте классы?

                      Никак. Классы не обязательны для ООП.


                      Проверка выполнения обязательств.

                      Контракт обязательно машинно-верифицируем?


                      Класс

                      В определении ООП его нет.


                      Анонимные реализации чего?

                      Интерфейса.


                      O RLY?

                      Да.


                      1. iCpu
                        17.08.2016 14:35
                        -1

                        > Есть. Но тогда у вас вообще нет единого мнения об определении ООП.
                        Видимо, так оно и есть.
                        > А кто сказал, что в стандарте правильно сделано? Вы ошибочных стандартов не видели?
                        А кто сказал, что Алан Кэй, будучи уже в преклонном возрасте, не забыл (или не передумал) того, что он сказал ранее? Иначе истолкавал свои старые высказывания?
                        > Никак. Классы не обязательны для ООП.
                        Если мы рассматриваем только ПОП подмножество. Меня же ниже уже ткнули носом в незнание терминов, и что ООП — более общее, нежели КОП, так что, расскажите пожалуйста, как вы реализуете КОП через ПОП, как вы сделаете классы?
                        > Контракт обязательно машинно-верифицируем?
                        Вы программист или лавочник?
                        > Интерфейса
                        А разве интерфейс — это не из КОП? Разве интерфейс — это не частный случай класса, имеющий только виртуальные методы без реализации?
                        > Внезапно, в Elixir есть типизация, которая вам об этом скажет.
                        Она мне скажет что? Что она мне скажет на „Human.lead(pid, to)“ vs „AlchemistryGenerator.lead(pid, to)“? человек.веди против генератор.свинец?


                        1. chaetal
                          17.08.2016 14:46
                          +1

                          Но тогда у вас вообще нет единого мнения об определении ООП.
                          Видимо, так оно и есть.
                          Ooo! Так, вам обратно в школу?!?


                        1. lair
                          17.08.2016 16:32

                          Видимо, так оно и есть.

                          Тогда ваше утверждение "ООП, как известно, зиждится на трёх китах: инкапсуляция, наследование, полиморфизм" — неверно. О чем с начала и говорили.


                          более общее, нежели КОП, так что, расскажите пожалуйста, как вы реализуете КОП через ПОП, как вы сделаете классы?

                          Эээ, и снова, если ПОП — это один из способов реализации ООП (и, следовательно, можно реализовать ООП через ПОП), а КОП — это другой способ реализации ООП (и, следовательно, ООП можно реализовать через КОП), то почему внезапно КОП должно быть можно реализовать через ПОП?


                          Вы программист или лавочник?

                          Я программист, и я в своей жизни видел дофига неверифицируемых (машинно) контрактов.


                          А разве интерфейс — это не из КОП?

                          Нет, это более общее понятие.


                          Разве интерфейс — это не частный случай класса, имеющий только виртуальные методы без реализации?

                          Тоже нет. Точнее, в рамках определенных контекстов это так, но в рамках программирования в целом — не так.


                          Что она мне скажет на „Human.lead(pid, to)“ vs „AlchemistryGenerator.lead(pid, to)“? человек.веди против генератор.свинец?

                          Зависит от типа to. Если они одинаковые, то ничего (потому что типизации по pid нет).


                          1. iCpu
                            17.08.2016 20:24
                            -1

                            > Тогда ваше утверждение «ООП, как известно, зиждится на трёх китах: инкапсуляция, наследование, полиморфизм» — неверно. О чем с начала и говорили.
                            Или оно верно, но заумные формулировки заумных людей размыли эти понятия, так что наблюдателю извне сразу и не понятно, где находится каждый из китов. Где находятся они в JavaScript я вам уже ответил выше. Про АОП, думаю, нет смысла писать, там всё достаточно очевидно.

                            Почему я так привязался к интерфейсам? Потому, что интерфейс — единственное, что отделяет объекты от структур. Если у объекта нет интерфейса, то он не объект, а набор данных. И если интерфейс неизвестен — это тоже не объект, потому как мы с ним не можем взаимодействовать, даже создать. (Под «интерфейс неизвестен» я имею в виду не положительный\отрицательный ответ на попытку вызвать метод, а отсутствие возможности вызвать этот метод, т.е., к примеру, полностью приватные классы С++)

                            > Эээ, и снова, если ПОП — это один из способов реализации ООП (и, следовательно, можно реализовать ООП через ПОП), а КОП — это другой способ реализации ООП (и, следовательно, ООП можно реализовать через КОП), то почему внезапно КОП должно быть можно реализовать через ПОП?
                            Сойдёмся на том, что ПОП — подмножество КОП и пойдём дальше.

                            > Нет, это более общее понятие.
                            Разве интерфейс — это не набор обязательств объекта, то есть тех методов, без которых объект не может существовать? Если нет, то смысл говорить об интерфейсе как о вещи, которая «может быть, а может и не быть, а может быть, но не вся и вообще я тебе завтра отвечу»? Если да, то чем отличаются интерфейс и абстрактный класс?

                            > Точнее, в рамках определенных контекстов это так, но в рамках программирования в целом — не так.
                            В рамках ООП естественно, Prolog мы не трогаем.

                            > Зависит от типа to. Если они одинаковые, то ничего (потому что типизации по pid нет).
                            И где, собственно, тогда интерфейс? И что, собственно, тогда интерфейс?


                            1. lair
                              17.08.2016 21:14

                              Или оно верно

                              На основании чего оно верно?


                              Потому, что интерфейс — единственное, что отделяет объекты от структур.

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


                              Сойдёмся на том, что ПОП — подмножество КОП и пойдём дальше.

                              Это утверждение неверно. В JS нет классов.


                              Разве интерфейс — это не набор обязательств объекта, то есть тех методов, без которых объект не может существовать?

                              Действительно, интерфейс (точнее, повторюсь, контракт) — это набор тех операций, которые объект позволяет над собой совершать.


                              Если да, то чем отличаются интерфейс и абстрактный класс?

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


                              И где, собственно, тогда интерфейс? И что, собственно, тогда интерфейс?

                              В данном случае интерфейс — это набор методов, выставленных модулем School, Human или AlchemistryGenerator.


                              1. iCpu
                                18.08.2016 00:08
                                -1

                                > На основании чего оно верно?
                                Ну же, я вам уже 2 раза написал. На основании того, что объектов не может быть без интерфейсов, а интерфейсы влекут за собой классы, наследование и полиморфизм.
                                Классы — связка интерфейса, данных и реализации.
                                Полиморфизм следует из требования единообразно обращаться к объектам хотя бы при их создании (конструкторов может быть бесконечно много, но то же соглашение об имени конструктора и вызове его по оператору new, к примеру — самый базовый интерфейс).
                                Наследование вытекает из того, что класс, реализовавший интерфейс, не эквивалентен интерфейсу и не является исключительной реализацией.
                                Как бы вы не крутились, ни один ООП не обойдёт этих простых правил, а всё остальное — сахар.

                                > Это утверждение неверно. В JS нет классов.
                                Перечитайте https://habrahabr.ru/post/307720/#comment_9756054
                                Если в JavaScript нет классов, то что такое базовые типы и тип class? Как они могут так просто занимать общее пространство и быть взаимозаменяемы в коде, если у них нет общего предка, дающего им общий базовый интерфейс?

                                > Это зависит от того, в каком языке вы находитесь. Скажем, в C# структуры — тоже объекты (и тоже имеют поведение).
                                В C# всё классы. Или вас сбило то, что класс называется struct? Shame on you! Вы сами написали, что структура имеет поведение. Позвольте вам напомнить, что единственное отличие структуры от класса — наличие поведения, то есть методов. Впредь, пожалуйста, не лажайтесь так грубо.

                                > Действительно, интерфейс (точнее, повторюсь, контракт) — это набор тех операций, которые объект позволяет над собой совершать.
                                > Тем, что набор операций не обязательно реализовывать в виде класса.
                                Какая разница, где и как они записаны, если они допустимы только в контексте объекта и обязаны быть реализованы для существования объекта?


                                1. lair
                                  18.08.2016 00:14

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

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


                                  А во-вторых, для реализации интерфейса (даже если это отдельная языковая сущность) наследование не нужно.


                                  Если в JavaScript нет классов, то что такое базовые типы и тип class?

                                  Базовые типы — это базовые типы. А что за тип class — я не знаю, я его не видел никогда в JavaScript.


                                  В C# всё классы.

                                  А вот это — неправда. В C# есть классы и есть структуры.


                                  Позвольте вам напомнить, что единственное отличие структуры от класса — наличие поведения, то есть методов.

                                  Это, повторюсь, зависит от языка, в котором вы находитесь. В C# это не так.


                                  Какая разница, где и как они записаны, если они допустимы только в контексте объекта и обязаны быть реализованы для существования объекта?

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


                                  1. iCpu
                                    18.08.2016 00:55
                                    -1

                                    > Во-первых, не объекта не может быть без интерфейса, а у любого объекта обязательно будет интерфейс. В смысле — создадите объект, появится и интерфейс. Более того, можно не иметь объекта, но иметь интерфейс.
                                    Как вы создадите объект, не имеющий интерфейса создания?
                                    > А во-вторых, для реализации интерфейса (даже если это отдельная языковая сущность) наследование не нужно.
                                    Есть маленькая тонкость, вы исходите из своего толкования термина «интерфейс» на основе ПОП программирования. Но в таком случае вы упускаете одну проблему, объект не проверяем на соответствие интерфейсу. Вы хотите сказать, что это ОК, но, извините, это не так. Как всё может быть в порядке, если сам объект не в курсе своего интерфейса? В таком случае функция — это не метод, а данные. А методом будет операция «попытаться выполнить поле как функцию над следующими параметрами» — оператор круглых скобок.

                                    > А вот это — неправда. В C# есть классы и есть структуры.
                                    > Это, повторюсь, зависит от языка, в котором вы находитесь. В C# это не так.
                                    https://msdn.microsoft.com/ru-ru/library/saxz13w4.aspx
                                    >> Все структуры наследуют непосредственно от System.ValueType, который наследует от System.Object. <<
                                    Ой!

                                    > Базовые типы — это базовые типы. А что за тип class — я не знаю, я его не видел никогда в JavaScript.
                                    Я — не я, базовые типы — не классы, даже если они себя ведут, как классы! Что это тогда, если не классы?
                                    https://learn.javascript.ru/es-class


                                    1. lair
                                      18.08.2016 01:02

                                      Как вы создадите объект, не имеющий интерфейса создания?

                                      Через фабрику. Но если вы обратите внимание, я говорю, что у любого объекта есть интерфейс, так что это бессмысленный вопрос.


                                      Есть маленькая тонкость, вы исходите из своего толкования термина «интерфейс» на основе ПОП программирования.

                                      Нет, с чего вы это взяли?


                                      Как всё может быть в порядке, если сам объект не в курсе своего интерфейса?

                                      Объект как раз прекрасно в курсе.


                                      Ой!

                                      Не "ой". "Наследует от System.Object" не означает "является классом".


                                      Я — не я, базовые типы — не классы, даже если они себя ведут, как классы! Что это тогда, если не классы?

                                      В каком смысле "ведут себя как классы"? Может, это классы ведут себя как типы (которыми они, кстати, и являются)?


                                      https://learn.javascript.ru/es-class

                                      Фразу "Современные возможности ES-2015" видите? В EcmaScript ключевое слово class есть (хотя, впрочем, это все равно только синтаксический сахар над прототипами), а в JavaScript — нет.


                                      1. iCpu
                                        18.08.2016 01:20
                                        -1

                                        > Через фабрику. Но если вы обратите внимание, я говорю, что у любого объекта есть интерфейс, так что это бессмысленный вопрос.
                                        Но, по вашим словам, сначала создаётся объект, а потом он получает интерфейс, то есть изначально его, интерфейса, нет. Как создаётся объект без интерфейса?

                                        >Нет, с чего вы это взяли?
                                        >>В смысле — создадите объект, появится и интерфейс.

                                        > Объект как раз прекрасно в курсе.
                                        >> И какие же гарантии того, что «нужный метод реализован именно с той сигнатурой», есть в JavaScript?

                                        > Не «ой». «Наследует от System.Object» не означает «является классом».
                                        https://msdn.microsoft.com/ru-ru/library/system.object(v=vs.110).aspx
                                        >> public class Object <<
                                        Ой-ой! Наследование = «является».

                                        > Фразу «Современные возможности ES-2015» видите? В EcmaScript ключевое слово class есть (хотя, впрочем, это все равно только синтаксический сахар над прототипами), а в JavaScript — нет.
                                        Принимается.


                                        1. lair
                                          18.08.2016 01:24

                                          Но, по вашим словам, сначала создаётся объект, а потом он получает интерфейс, то есть изначально его, интерфейса, нет.

                                          Нет. Объект всегда обладает интерфейсом (в значении "набором операций").


                                          Как создаётся объект без интерфейса?

                                          Никак.


                                          Нет, с чего вы это взяли?
                                          В смысле — создадите объект, появится и интерфейс.

                                          ПОП тут ни при чем.


                                          Объект как раз прекрасно в курсе.
                                          И какие же гарантии того, что «нужный метод реализован именно с той сигнатурой», есть в JavaScript?

                                          Не вижу связи между этими двумя фразами.


                                          Ой-ой! Наследование = «является».

                                          Да, любая структура в C# является System.Object, но при этом не является классом. Вот такая вот фигня.


                                          (На самом деле, это потому, что System.Object — не вполне настоящий класс, а отношение между ним и System.ValueType — не вполне наследование. Такая вот протекшая абстракция.)


                                          1. iCpu
                                            18.08.2016 07:18
                                            -2

                                            > Нет. Объект всегда обладает интерфейсом (в значении «набором операций»).
                                            Отлично. Тогда, получается, минимальный интерфейс — набор соглашений о способах создания и удаления объекта — есть всегда и присущ всем объектам. Тогда все объекты принадлежат классу создаваемых объектов.
                                            Тогда, получается, и Self, и JavaScript имеют, как минимум, создаваемые классы, просто они находятся на нижнем уровне. Соглашения высшего же уровня, прототипы, — попытка исправить то, что классов в смысле гарантии соблюдения интерфейсов на высшем уровне нет, а без таких гарантий более-менее серьёзная раработка вообще не возможна.

                                            > Не вижу связи между этими двумя фразами.
                                            Ну как же. Вы же меня спросили в начале, как в JavaScript объект может проверить, есть ли у него нужный метод с нужной сигнатурой (с намёком — никак). А теперь вы же утверждаете, что способ есть, как есть и некое высшее знание. Я ничего не пропустил?

                                            > Да, любая структура в C# является System.Object, но при этом не является классом. Вот такая вот фигня.
                                            Я — не я, классы — не классы.
                                            Код
                                            public struct CoOrds
                                            {
                                            public int x, y;
                                            public CoOrds(int p1, int p2)
                                            {
                                            x = p1;
                                            y = p2;
                                            } }

                                            Stack(Object)stack = new Stack(Object)();
                                            stack.Push(new integer(5));
                                            stack.Push(new string(«lolwat?»);
                                            stack.Push(Coord(5,5));
                                            string str = stack.Last().toString();
                                            валиден? Если да, то как Object может не быть классом? А как struct может не быть классом, если он наследуется от класса и имеет методы? Ах, они указаны как final, и operator= выполняет копирование, а не получение ссылки? И? И ничего. Структуры — это классы, потому, что то, на чём они основаны — тоже классы, то, что реализуют — классы, и то, что получается в итоге — классы.


                                            1. lair
                                              18.08.2016 12:01

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

                                              Нет. Интерфейс всегда рассматривается с точки зрения пользователя. И если у пользователя нет способа создать объект — например, это синглтон, или объект всегда получается из другого объекта — то у этого объекта нет интерфейса создания. Аналогично и для интерфейса удаления (которого, скажем, в C# по умолчанию у объектов нет).


                                              Тогда все объекты принадлежат классу создаваемых объектов.

                                              Только в том значении слова "класс", которое "категория объектов, объединенных признаком". Но, как мы помним, в class-based OOP под словом "класс" понимается другое, поэтому — в терминах class-based OOP — объекты не принадлежат к этому классу (если он вообще есть). Они реализуют этот интерфейс — если реализуют, конечно.


                                              а без таких гарантий более-менее серьёзная раработка вообще не возможна.

                                              То есть на динамических языках (включая Smalltalk) серьезная разработка невозможна?


                                              А теперь вы же утверждаете, что способ есть, как есть и некое высшее знание. Я ничего не пропустил?

                                              Вы путаете гарантию реализации и способ проверить, есть ли метод. Одно в JS есть (по крайней мере, на уровне имени метода), другого — нет.


                                              Если да, то как Object может не быть классом?

                                              Легко.


                                              А как struct может не быть классом, если он наследуется от класса и имеет методы?

                                              Аналогично, легко.


                                              Структуры — это классы, потому, что то, на чём они основаны — тоже классы, то, что реализуют — классы, и то, что получается в итоге — классы.

                                              Не в C#. В C# очень конкретная терминология, в которой struct и class имеют разную семантику, и, что важно, разное поведение.


                                              В частности, это очень хорошо видно на следующем коде:


                                              CoOrds locker = new CoOrds(1, 2);
                                              
                                              lock(locker) //не будет работать, точнее, всегда будет входить внутрь лока
                                              {
                                              }


                                              1. iCpu
                                                18.08.2016 12:27
                                                -1

                                                > Нет. Интерфейс всегда рассматривается с точки зрения пользователя. И если у пользователя нет способа создать объект — например, это синглтон, или объект всегда получается из другого объекта — то у этого объекта нет интерфейса создания. Аналогично и для интерфейса удаления (которого, скажем, в C# по умолчанию у объектов нет).
                                                Ваши логические пассы верны для КОП, в котором базовый интерфейс поддаётся значительному изменению, но в ПОП это не так. Нет у javascript private, а, значит, и способов сокрыть базовый интерфейс.
                                                Да и в КОП это не вполне корректно, класс знает о стандартном интерфейсе, и, чтобы его избежать, нужно явно прописывать подавляемые соглашения. Для пользователя чёрного ящика, конечно, нет способа самостоятельно получить такой, но интерфейс взаимодействия не исчезает.


                                                1. lair
                                                  18.08.2016 12:34

                                                  Ваши логические пассы верны для КОП, в котором базовый интерфейс поддаётся значительному изменению

                                                  Значит, они верны хотя бы для части ООП. Этого достаточно.


                                                  в ПОП это не так. Нет у javascript private, а, значит, и способов сокрыть базовый интерфейс.

                                                  В JavaScript — нет, а вот в других языках может и быть. Почему вы так смело говорите за всю (суб-)парадигму?


                                                  Да и в КОП это не вполне корректно, класс знает о стандартном интерфейсе, и, чтобы его избежать, нужно явно прописывать подавляемые соглашения [...] интерфейс взаимодействия не исчезает.

                                                  Исчезает. private-операция (например, private-конструктор) не являются частью интерфейса.


                                                  А главное, это все никак не меняет того факта, что для наличия интерфейса не нужно наследование (а интерфейс, на самом деле, не является определяющей частью ООП).


                                                  1. iCpu
                                                    18.08.2016 13:01
                                                    -2

                                                    > Значит, они верны хотя бы для части ООП. Этого достаточно.
                                                    Нет, не достаточно. Они верны для той части ООП, в которой программист может определять интерфейсы и классы. В той части, где он не может определять классы, действуют https://habrahabr.ru/post/307720/#comment_9756778
                                                    То есть классы никуда не деваются. Девается ваш контроль над ними.

                                                    > В JavaScript — нет, а вот в других языках может и быть. Почему вы так смело говорите за всю (суб-)парадигму?
                                                    Весь интерфейс классов ПОП — создание, клонирование и доступ к полям. Я, конечно, могу представить, что подобные запреты могут вводиться, но не вижу способа сделать это элегантно и полезно. Хотя, правда ваша.
                                                    Хотя в таком случае, случае запрещения, получится другой базовый интерфейс и, соответственно, другой класс. И будет уже не совсем ПОП.

                                                    > А главное, это все никак не меняет того факта, что для наличия интерфейса не нужно наследование (а интерфейс, на самом деле, не является определяющей частью ООП).
                                                    https://habrahabr.ru/post/307720/#comment_9756092
                                                    Интерфейс — набор методов — всё, что отделяет объект от структуры. Извините, но без интерфейсов получится СОП, или просто классический процедурный яп.


                                                    1. lair
                                                      18.08.2016 13:09

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

                                                      Программист может определять интерфейс в любой части ООП. Иногда его контроль ограничен, но он всегда есть.


                                                      То есть классы никуда не деваются

                                                      Не во всяком ОО-языке есть классы.


                                                      Девается ваш контроль над ними.

                                                      Для меня это эквивалентно "классов нет".


                                                      Весь интерфейс классов ПОП — создание, клонирование и доступ к полям.

                                                      В ПОП — по крайней мере, в подавляющем количестве реализаций — классов нет.


                                                      Интерфейс — набор методов — всё, что отделяет объект от структуры.

                                                      У структуры тоже есть интерфейс — это набор предоставляемых ей данных. И у модуля есть интерфейс. И у функции есть интерфейс. У всего в программировании есть интерфейс.


                                                      (повторюсь, "интерфейс" в значении "набор предоставляемого поведения")


                                                      1. iCpu
                                                        18.08.2016 13:49

                                                        > Программист может определять интерфейс в любой части ООП. Иногда его контроль ограничен, но он всегда есть.
                                                        > Не во всяком ОО-языке есть классы.
                                                        > В ПОП — по крайней мере, в подавляющем количестве реализаций — классов нет.
                                                        В общем, нет, вы не правы, и я уже показал это на примере JavaScript.

                                                        > «интерфейс» в значении «набор предоставляемого поведения»
                                                        Разве это определение интерфейса из ООП?
                                                        In object-oriented languages, the term interface is often used to define an abstract type that contains no data or code, but defines behaviors as method signatures. A class having code and data for all the methods corresponding to that interface is said to implement that interface. Furthermore, a class can implement multiple interfaces, and hence can be of different types at the same time.


                                                        1. lair
                                                          18.08.2016 13:57

                                                          В общем, нет, вы не правы, и я уже показал это на примере JavaScript.
                                                          … в котором, как мы выяснили, классов нет. И обратного вы не показали.

                                                          Разве это определение интерфейса из ООП?

                                                          В ООП нет определения интерфейса.


                                                          In object-oriented languages, the term interface is often used to define

                                                          Есть фундаментальная разница между often used и определением.


                                              1. iCpu
                                                18.08.2016 12:43
                                                -1

                                                > в class-based OOP под словом «класс» понимается другое
                                                Что же?

                                                > То есть на динамических языках (включая Smalltalk) серьезная разработка невозможна?
                                                Не смешивайте котлеты и мух и не перевирайте мои слова. Я даже про javascript написал, что там есть надстройка в виде прототипов, которая позволяет иметь некие гарантии. Естественно, они есть много ещё где. Насколько они эффективны — вопрос не ко мне.

                                                > Не в C#. В C# очень конкретная терминология, в которой struct и class имеют разную семантику, и, что важно, разное поведение.
                                                Нельзя подгонять результаты под желаемый ответ. Я прекрасно понимаю, чем отличаются структуры от классов в контексте шарпа, но не в контексте ООП. С точки зрения ООП у них общий интерфейс и общий базовый класс. Который является классом, и не перестанет им быть, даже если вы очень сильно постараетесь доказать обратное. С точки зрения пользователя, их обоих можно понизить до Object и жонглировать ими. Так в чём, с точки зрения ООП, у них разница, кроме вашей хотелки?


                                                1. lair
                                                  18.08.2016 12:48

                                                  Что же?

                                                  "In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods)"


                                                  Я даже про javascript написал, что там есть надстройка в виде прототипов, которая позволяет иметь некие гарантии

                                                  Какие же?


                                                  Так в чём, с точки зрения ООП, у них разница, кроме вашей хотелки?

                                                  С точки зрения ООП понятия "структура" не существует, поэтому этот вопрос бессмысленен.


                                                  И да, я изначально говорил, что мое разделение структур и классов языко-специфично.


                                                  1. iCpu
                                                    18.08.2016 13:34
                                                    -1

                                                    И?
                                                    https://en.wikipedia.org/wiki/Class_(computer_programming)#The_concept_of_class_interface

                                                    > Какие же?
                                                    А ви-таки почему интересуетесь?

                                                    > С точки зрения ООП понятия «структура» не существует, поэтому этот вопрос бессмысленен.
                                                    С точки зрения ООП у нас есть класс с названием «class» и есть класс с названием «struct». В чём, с точки зрения ООП, а не вашего взгляда на мир, у них отличия?

                                                    > И да, я изначально говорил, что мое разделение структур и классов языко-специфично.
                                                    Я и заметил, что у вас полифония мнений.


                                                    1. lair
                                                      18.08.2016 13:38

                                                      А ви-таки почему интересуетесь?

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


                                                      С точки зрения ООП у нас есть класс с названием «class» и есть класс с названием «struct». В чём, с точки зрения ООП, а не вашего взгляда на мир, у них отличия?

                                                      Если мы говорим о class-based OOP, то ни в чем: и то, и другое — класс.


                                                      1. iCpu
                                                        18.08.2016 13:54

                                                        > Потому что вы говорите, что гарантии обязательны для разработки крупных систем (изначально вы вообще, если я не ошибаюсь, говорили, что ООП без гарантий не существует).
                                                        И то, и другое верно. Интерфейсы — это гарантии, обязательства классов. Они максимальны в статических КОП и минимальны в динамических ПОП (на уровне наследования базовых типов, пустого класса и функторов от одной базы и, как следствие, единое поведение в контейнере).

                                                        > Если мы говорим о class-based OOP, то ни в чем: и то, и другое — класс.
                                                        Мы говорим про ООП в общем, что это меняет?


                                                        1. lair
                                                          18.08.2016 13:58
                                                          +1

                                                          Интерфейсы — это гарантии, обязательства классов.

                                                          … так какие гарантии предоставляет JavaScript?


                                                          Мы говорим про ООП в общем, что это меняет?

                                                          Это меняет то, что в "ООП в общем" не может быть "класса с названием", потому что "ООП в общем" не оперирует понятием класса. В нем может быть объект с поведением.


                                    1. sl_bug
                                      18.08.2016 01:33

                                      > Как вы создадите объект, не имеющий интерфейса создания?

                                      Ruby: x = 2. создал.


                                      1. iCpu
                                        18.08.2016 06:34
                                        -1

                                        С++ тоже так умеет.
                                        class Integer {
                                        Integer(int t = 0);
                                        };
                                        int main () {
                                        Integer Int = 10;
                                        }
                                        Просто особое соглашение, интерфейс, всего-то…
                                        Повторю вопрос, как вы можете создать объект, если объект не имеет способов себя создать?


                1. Source
                  17.08.2016 13:56

                  Сами найдёте. Не великий труд, всё на вики есть.
                  Раз уж Вы сослались на вики, то откройте страничку Programming paradigm и увидьте, что модель акторов — это такая же реализации ООП, как и Class-based и Prototype-based:

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


                  1. iCpu
                    17.08.2016 14:24

                    Окей, я понял, что пока я спал, АОП из некоего подмножества КОП стала самостоятельным подмножеством ООП. хотя не понятно, на каких основаниях: всё же классы никуда не делись, остались и Агент и Объект.


            1. Virviil
              17.08.2016 19:18
              +1

              Если говорить на уровне "серьёзных книг", то после 1994 года, когда вышла "Design patterns" от GoF, реализовывать полиморфизм через наследование, а не через композицию — дурной тон.
              Да и впринципе, посмотрите на современные реализации полиморфизма — сперва была мода duck typing во всяких там динамических языках, теперь — полная реализация интерфейса как к примеру в Rust.
              Полиморфизм есть — наследования нету. Так что что-то у вас не сходится.


              1. iCpu
                17.08.2016 19:58
                -1

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


                1. lair
                  17.08.2016 21:20
                  +1

                  В конце концов, полиморфизм без наследования интерфейсов не возможен

                  Правда?


                  void Do(dynamic target)
                  {
                    target.Do();
                  }
                  
                  DoSomething(new Action());
                  DoSomething(new Command());
                  DoSomething(new Piano());

                  Или вот:


                  let inline add(value1 : ^T when ^T : (static member (+) : ^T * ^T -> ^T), value2: ^T) =
                     value1 + value2
                  
                  add 9 13
                  add 7.0 4.0
                  add "abc" "def"


                  1. iCpu
                    17.08.2016 23:36
                    -1

                    А разве вы не наложили ограничения на эти ваши объекты? Вы не обязали их в первом случае иметь метод Do, а во втором operator+, то есть реализовывать единообразный интерфейс? Вы не дали этим ограничениям имён, но разве это что-то значит? Они наследуют анонимные базовые интерфейсы, без реализации которых выполнение не возможно. Нет? А что вы сделали иначе?


                    1. lair
                      17.08.2016 23:39

                      Я наложил ограничения, да. Но это не интерфейс (в значении "интерфейс как сущность языка"), и нет никакого наследования.


                      Более того, в первом случае даже и ограничения нет никакого: если объект не будет иметь такого метода, код скомпилируется — просто в рантайме будет ошибка.


                      1. iCpu
                        18.08.2016 00:29
                        -1

                        Поведение в первом случае зависит от языка. У меня его название не подсвечивается, и я не стыжусь признаться, что не знаю языков из обоих примеров. Потому и не могу сказать определённо.
                        Хотя, во втором явно накладывается ограничение на тип Т на реализацию оператора сложение. Причём ранг полиморфизма чуть выше первого, так что, формально, нельзя сказать, что класс наследует интерфейс, скорее, для классов, не имеющих интерфейса с оператором сложения не создаётся метода add. Иначе говоря, такой шаблон автоматически унаследует все подходящие классы каждый от своего анонимного интерфейса.

                        А первый случай — немного слегка почти не ООП, потому что когда в плюсах что-то делают через (void*), это считается дурным тоном, а для адептов чистого ООП — вообще причина для ритуального сожжения. А в чём, извините, разница, кроме того, что плюсы вызывают метод не по имени, а по адресу?


                        1. lair
                          18.08.2016 00:33

                          Иначе говоря, такой шаблон автоматически унаследует все подходящие классы каждый от своего анонимного интерфейса.

                          А ничего, что "подходящие классы" — они из системной библиотеки, и модификации не подлежат?


                          Слишком много сущностей (анонимный интерфейс, автоматическое наследование) там, где можно обойтись ограничением на статический метод. Кстати, в некоторых (как минимум) языках статические методы не входят в иерархию реализации (не определяются в интерфейсе и не переопределяются).


                          А первый случай — немного слегка почти не ООП, потому что когда в плюсах что-то делают через (void*), это считается дурным тоном. А в чём, извините, разница, кроме того, что плюсы вызывают метод не по имени, а по адресу?

                          Ну то есть Smalltalk все-таки не ООП?


                          1. iCpu
                            18.08.2016 01:04
                            -4

                            > А ничего, что «подходящие классы» — они из системной библиотеки, и модификации не подлежат?
                            А ничего, что вы создали не метод, а функцию в функциональном языке? Ничего? Тогда движемся дальше.

                            > Ну то есть Smalltalk все-таки не ООП?
                            Если это его синтаксис и если это нормальный способ вызова своих методов, а не отсылки сообщений потенциально неизвестному классу, то по конкретно этому критерию — да. Но мне что-то подсказывает, что это не smalltalk, а java. Не знаю, то ли дело в том, что синтаксис не подходит. то ли дело в том, что в smalltack нельзя не знать собственных сообщений, то ли в жирной лыбе на вашем лице.


                            1. lair
                              18.08.2016 01:11
                              -1

                              А ничего, что вы создали не метод, а функцию в функциональном языке? Ничего? Тогда движемся дальше.

                              Она (функция) от этого перестала быть полиморфной?


                              Если это его синтаксис и если это нормальный способ вызова своих методов, а не отсылки сообщений потенциально неизвестному классу, то по конкретно этому критерию — да.

                              О нет, в Smalltalk все еще веселее.


                              doSomething: target
                                  target do
                              
                              Action new doSomething
                              Command new doSomething
                              Piano new doSomething

                              Но мне что-то подсказывает, что это не smalltalk, а java.

                              Неправильно подсказывает.


                              в smalltack нельзя не знать собственных сообщений

                              А при чем тут собственные сообщения, когда речь идет о сообщениях, поддерживаемых параметром target, который снаружи передается?


                              1. iCpu
                                18.08.2016 01:26

                                > Она (функция) от этого перестала быть полиморфной?
                                Она стала объектно-ориентированной?
                                > А при чем тут собственные сообщения, когда речь идет о сообщениях, поддерживаемых параметром target, который снаружи передается?
                                При том, что в smalltack есть respondsTo: doSomething


                                1. lair
                                  18.08.2016 01:33

                                  Она стала объектно-ориентированной?

                                  Нет. Но речь шла о полиморфизме, а не об ООП.


                                  При том, что в smalltack есть respondsTo: doSomething

                                  … и что? Такие вещи во многих динамических языках есть. Да и в статических тоже, прямо скажем.


                                  (BTW, если я не ошибаюсь, respondsTo может обмануть)


                                  1. sl_bug
                                    18.08.2016 01:42

                                    в руби точно можно обмануть (либо накосячить). думаю в smalltalk так же


                                  1. iCpu
                                    18.08.2016 06:28
                                    -2

                                    > Нет. Но речь шла о полиморфизме, а не об ООП.
                                    Батенька, вам к лицу ваш ник. Мы уже два дня пишем про ООП, и тут, БАХ!, внезапно не про ООП, а так, о природе, о кошечках, так получается? Это не серьёзно.

                                    >… и что? Такие вещи во многих динамических языках есть. Да и в статических тоже, прямо скажем. (BTW, если я не ошибаюсь, respondsTo может обмануть)
                                    И-и-и-и? Кого угодно можно обмануть, если начать использовать грязные трюки. У вас претензия к Smalltalk за то, что он такой сякой, позволяет отправлять сообщения, не удосужевшись узнать, умеют ли его принять? Или к тому, что отдельные реализации плохо с этим справляются?


                                    1. lair
                                      18.08.2016 11:46

                                      Батенька, вам к лицу ваш ник. Мы уже два дня пишем про ООП, и тут, БАХ!, внезапно не про ООП, а так, о природе, о кошечках, так получается? Это не серьёзно.

                                      Внезапно, во фразе "В конце концов, полиморфизм без наследования интерфейсов не возможен." нет ни слова про ограничение на ООП. Впрочем, для ООП это тоже не верно. Один пример выше, второй легко правится под ООП следующим образом:


                                      type ListWithTotal<'T when 'T : (static member (+) : 'T * 'T -> 'T)> =
                                      class end

                                      У вас претензия к Smalltalk за то, что он такой сякой, позволяет отправлять сообщения, не удосужевшись узнать, умеют ли его принять?

                                      У меня вообще вообще нет претензий к Smalltalk, я просто пытаюсь понять, вы таки считаете его ООП-языком, или нет.


                                      1. iCpu
                                        18.08.2016 12:08

                                        > Внезапно, во фразе «В конце концов, полиморфизм без наследования интерфейсов не возможен.» нет ни слова про ограничение на ООП.
                                        Хорошо, с этих пор я буду писать «вне ООП» каждый раз, как буду писать не об ООП.

                                        > Впрочем, для ООП это тоже не верно. Один пример выше, второй легко правится под ООП следующим образом
                                        Первый пример, в общем, — не ООП, а пережиток процедурного программирования. Только конкретная реализация конкретного языка позволит сказать, возможно ли эту ситуация обернуть в ООП (как если бы это были макросы, проверяющие подставляемые типы) или нет (если дёргается метод без проверок).
                                        А шаблоны, мой милый собеседник, повторяюсь ещё раз, служат для генирации интерфейсов и\или реализации. То есть параметризуя шаблон вы получите новый интерфейс со своим именем и методами, своими или общими — в зависимости от параметризации самих методов.

                                        > У меня вообще вообще нет претензий к Smalltalk, я просто пытаюсь понять, вы таки считаете его ООП-языком, или нет.
                                        Ничего не изменилось.


                                        1. lair
                                          18.08.2016 12:14

                                          первый пример, в общем, — не ООП, а пережиток процедурного программирования

                                          Это почему?


                                          А шаблоны, мой милый собеседник, повторяюсь ещё раз, служат для генирации интерфейсов и\или реализации.

                                          Только это не шаблоны.


                                          Ничего не изменилось.

                                          Так Smalltalk — ООП-язык или нет?


                                          1. iCpu
                                            18.08.2016 13:22

                                            > Это почему?
                                            А чем target.do() отличается от
                                            typedef void (*pDo)(myStruct *target);
                                            pDo do = (*pDo)(void*)(target.func);
                                            do(target);
                                            Требованием вызвать метод по имени? Но это не вопрос ООП, нигде не стоит обязательства хранить имя метода, и конкретные реализации могут заменить строки хешами или указателями. А больше ничем.

                                            > Только это не шаблоны
                                            А что?

                                            > Так Smalltalk — ООП-язык или нет?
                                            Да.


                                            1. lair
                                              18.08.2016 13:35

                                              А чем target.do() отличается от typedef void (*pDo)(myStruct *target);

                                              Отсутствием типа. Вообще.


                                              А что?

                                              Обобщенный класс.


                                              Так Smalltalk — ООП-язык или нет?
                                              Да.

                                              О, прекрасно. Давайте запомним это утверждение.


                                              Сразу вопрос: почему первый мой пример (который один в один реализуется на Smalltalk) — не ООП?


                                              1. iCpu
                                                18.08.2016 14:01

                                                > Отсутствием типа. Вообще.
                                                А что такое .Do() тогда? И что такое dynamic?

                                                > Обобщенный класс.
                                                То есть, шаблон.

                                                > Сразу вопрос: почему первый мой пример (который один в один реализуется на Smalltalk) — не ООП?
                                                >>Первый пример, в общем, — не ООП, а пережиток процедурного программирования. Только конкретная реализация конкретного языка позволит сказать, возможно ли эту ситуация обернуть в ООП (как если бы это были макросы, проверяющие подставляемые типы) или нет (если дёргается метод без проверок).
                                                Подозреваю, что проверок нет, а значит, интерпретатор будет дёргать любой одноимённый слот\метод\ассептор. Конкретно это фича — не из ООП. И?


                                                1. lair
                                                  18.08.2016 14:08

                                                  А что такое .Do() тогда?

                                                  Метод.


                                                  И что такое dynamic?

                                                  Ключевое слово, включающее DLR.


                                                  То есть, шаблон.

                                                  Нет. Не все обобщенные классы — шаблоны.


                                                  Подозреваю, что проверок нет, а значит, интерпретатор будет дёргать любой одноимённый слот\метод\ассептор. Конкретно это фича — не из ООП. И?

                                                  И то, что так работает весь Smalltalk. При любом вызове будет дергаться "одноименный метод" (и это, заметим, воспевается Кэем как фундаментальное качество ООП). Если эта фича не из ООП, то что в Smalltalk из ООП?


                                1. sl_bug
                                  18.08.2016 01:58
                                  -2

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


                                  1. iCpu
                                    18.08.2016 06:20
                                    -1

                                    А что толку это оставлять, если вы не понимаете, о чём говорит Вилл, да и он сам, похоже, не осознаёт, в чём настоящая проблема?
                                    Вы послушайте, сами внимательно с четвёртого пункта. В нём он говорит, что в больших сложных системах не всегда удаётся произвести правильную декомпозицию, потому возникает сильная связность между классами и драконовские, порой, рекурсивные графы наследования, что плохо от слова пушнина. Это проблема ООП?
                                    Это проблема дизайна. Решится ли она с помощью ФП? Нет, точно такая же проблема будет и в функциональных языках, она лишь немного сместится, когда нельзя будет, например, просто обернуть операцию в одну функцию, так как она зависит от слишком многих состояний слишком многих модулей, при этом копирование состояний будет не возможно в силу ограниченности объёма памяти и мутабельности части из них, а любое разбиение этой операции приведёт к размазыванию реализации, ухудшению удобочитаемости и усложнению поддержки. И это поведение не зависит, функционально ли мы подходим, объектно, структурно, агентно или ещё как-то. Если задача — пушнина, то и на выходе будет шуба из норок.