LINUX.ORG.RU

Ядро на ООП

 ,


2

4

А как вам идея написать ядро ОС, по сложности и возможностям сопоставимой с Linux, с применением ООП (например, на C++) Каждый драйвер, сервис и др. сделать классом (ну группой классов).

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

Минус - необходимость поддержки ООП в ядре влечёт за собой некоторый overhead (вот насколько он будет заметен - тоже интересный вопрос).

Высказывайтесь.

★★★★★
Ответ на: комментарий от jtootf

Вообще-то мы ушли далековато от темы основной дискуссии. Лучше бы это в отдельный топик. Ну ладно. Постараемся закончить так сказать.

Erlang - практически чистый ОО-язык

Золотые слова! Да, ты прав эрланг практический язык. Добавлю от себя: это ФП-язык-практик. Самый он. АТС, годами работающие на эрланге практически без перезагрузки, но с обновлениями. Почти все есть функция. Иммутабельные объекты. Паттерн-матчинг включая функции. Хвостовая. Анонимные функции есть, но слабоватые. Отсутствие циклов (хотя не уверен здесь, относится ли это к ФП - наверное должно относится).

«ОО-язык» и близко не лежало. Есть некоторые, присущие теоретическому ООП элементы, но не более этого. Например классическое толкование: отправка и прием сообщений. Наследования нет. Полиморфизм обеспечивается за счет динамической типизации в итоге. Виртуальных методов нет. Классов нет. Конструкций типов нет. Инкапсуляция: нету. Только на уровне параметрических модулей. Ограничение доступа: на уровне модулей и отсутствие глобальных переменных. this нету: вместо этого Send|Receive (классическое поведение наверное из smalltalk) или genserver. С помощью этих нехитрых конструкций можно реализовать ООП. Что и сделано в языке Elixir.

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

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

это не декларативное описание зависимости результата от аргументов

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

Классический пример:

-module(m).          % module attribute
-export([fact/1]).   % module attribute

fact(N) when N>0 ->  % beginning of function declaration
    N * fact(N-1);   %  |
fact(0) ->           %  |
    1.               % end of function declaration


Те-же balls, только вид сбоку.

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

Наследования нет

ООП не подразумевает наследования

Виртуальных методов нет

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

Классов нет

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

Инкапсуляция: нету

есть, конечно же. интерфейс от реализации в gen_server отделён настолько, насколько это вообще возможно

this нету

есть id текущего процесса, выполняющий ту же роль. послать сообщение себе можно? можно

С помощью этих нехитрых конструкций можно реализовать ООП

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

это очень удобно

но не функционально

ты прав эрланг практический язык

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

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

но не функционально

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

Позиция разработчиков эрланга по поводу ООП:
http://harmful.cat-v.org/software/OO_programming/why_oo_sucks

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

Что такое функциональность в практическом смысле?

в контексте треда - соответствие функциональной парадигме

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

Просто надо очень не любить С. :)

В смысле? Чтобы такое раскопать, надо очень не любить C, я правильно понял? :)

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

Абсолютно правильно.

Попробую объяснить. Если мне нравится С, и я могу считать, что это один из моих любимых языков, я буду просто писать на нём код, стремиться к совершенству этого кода и искать наилучшие образцы кода на С, чтобы учиться и перенимать опыт.

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

Вот приблизительно так. :)

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

не переживай так.

Я переживаю только по серьёзным поводам. И то, всё реже и реже. А уж по поводу своих или чьих-то комментов на ЛОРе — не дождёшься. :)

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

Интересно, а вообще существуют не-ОО-языки?

да, конечно

А можно пример? Или обоснование того, что, к примеру, Си - это не ООП-язык?

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

Си - это не ООП-язык

нет механизма динамической диспетчеризации на уровне семантики языка; взаимодействие модулей посредством общей памяти, а не обмена сообщениями

jtootf ★★★★★
()

ядерный framework в xnu(MacOSx) на OOP, ну или очень близкий к OOP

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

нет механизма динамической диспетчеризации на уровне семантики языка

whaat? Указатели на функции.

взаимодействие модулей посредством общей памяти, а не обмена сообщениями

Мде. И кто мешает обмениваться сообщениями?

Если термин «ООП-язык» что-то и значит, то это «язык, явным образом поддерживащий ООП-стиль программирования». И если эрланговский обмен сообщениями для тебя является поддержкой ООП, у тебя какое-то свое понятие об ООП. Наверное, ты и QNX считаешь объектно-ориентированной ОС.

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

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

А что скажешь по поводу Io? Декорт позиционирует его, как «чистый объектно-ориентированный язык». И у него там всё основано на обмене сообщениями.

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

А что скажешь по поводу Io?

Как по мне, он акторный, но, если кто-то назовет его объектно-ориентированным, я спорить не стану.

А вообще - еще один унылый динамический недоязычок, очевидно же.

И у него там всё основано на обмене сообщениями.

На обмене сообщениями основано столько систем, что сам факт основанности на этом не значит ровно ничего. Любой сетевой протокол - это обмен сообщениями. Occam и CSP, систолические архитектуры - обмен сообщениями.

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

Как по мне, он акторный, но, если кто-то назовет его объектно-ориентированным, я спорить не стану.

The AlanKay definition of OO is largely that given by CarlHewitt for the ActorsModel which is a model of computation, not a programming paradigm. AlanKay has acknowledged explicitly this derivation.
Versions of Smalltalk before Smalltalk-80 were still largely based on the (asynchronous, unidirectional) ActorsModel of computation, but with Smalltalk-80, the developers of SmalltalkLanguage switched entirely to the (synchronous, bidirectional) procedural model, while misleadingly retaining the ActorsModel terminology (such as «messages» for what essentially are procedure calls rather than one-way notifications).

http://c2.com/cgi/wiki?AlanKaysDefinitionOfObjectOriented

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

Как по мне, он акторный

Именно.

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

Так сам автор и называет. Утверждает, что основная концепция Io «всё есть объект». И это его главный аргумент.

А вообще - еще один унылый динамический недоязычок, очевидно же.

Когда я попытался на Io сваять один небольшой проектик, очень быстро разочаровался. Решил вернуться к костылям C++&Qt, на которых быстрее получается до финиша добраться, чем на «чистом ООП». С тех пор какое-то скептическое отношение к объявляемым «чистыми» ЯП появилось. Вне зависимости от их основной концепции.

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

ты и QNX считаешь объектно-ориентированной ОС

я QNX считаю очень хорошей ОС :)

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

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

Ок, ты будешь первым, кто об этом узнает.

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

Да, и требованиям соответствует Я не понимаю тех, кто пишет на языках, требующих виртуальную машину/интерпретатор, где проседает быстродействие и сьедаются ресурсы

ms-dos128
()
Ответ на: комментарий от ms-dos128

Я не понимаю тех, кто пишет на языках, требующих виртуальную машину/интерпретатор, где проседает быстродействие и сьедаются ресурсы

Я ни слова про это не говорил. Но есть ряд очень приятных плюшек которые, мягко говоря, сям бы не помешали. Хотя бы нормальная работа со строками, нормальная поддержка переменного кол-ва аргументов, параметры по-умолчанию, декораторы, эксепшены итп. Есть, правда, риск получить вторые кресты.

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

Все это есть в С++, но сделано криво. И работа со строкой как с объектом кажется мне не совсем удобной. Хотя бы потому что в С это массив символов с \0 в конце, а в С++ специально выделяется хип и вообще невесть что происходит

ms-dos128
()
Ответ на: комментарий от ms-dos128

Я не понимаю тех, кто пишет на языках, требующих виртуальную машину/интерпретатор, где проседает быстродействие и сьедаются ресурсы

Это потому, что у тебя ограниченное понимание «ресурсов».

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

Все это есть в С++, но сделано криво

вот и я о том же :). Впрочем, я, наверно, преждевременно стал утверждать что хороших языков нет. Я от силы штук 10-15 (включая скриптовые) видел, а «серьёзно» прогал и того меньше.

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

Позиция разработчиков эрланга по поводу ООП

Joe Armstrong: Smalltalk got a lot of the things right. So if your question is about what I think about object oriented programming, I sort of changed my mind over that. I wrote a an article, a blog thing, years ago - Why object oriented programming is silly. I mainly wanted to provoke people with it. They had a quite interesting response to that and I managed to annoy a lot of people, which was part of the intention actually. I started wondering about what object oriented programming was and I thought Erlang wasn't object oriented, it was a functional programming language.

Then, my thesis supervisor said «But you're wrong, Erlang is extremely object oriented». He said object oriented languages aren't object oriented. I might think, though I'm not quite sure if I believe this or not, but Erlang might be the only object oriented language because the 3 tenets of object oriented programming are that it's based on message passing, that you have isolation between objects and have polymorphism.

Alan Kay himself wrote this famous thing and said «The notion of object oriented programming is completely misunderstood. It's not about objects and classes, it's all about messages». He wrote that and he said that the initial reaction to object oriented programming was to overemphasize the classes and methods and under emphasize the messages and if we talk much more about messages then it would be a lot nicer. The original Smalltalk was always talking about objects and you sent messages to them and they responded by sending messages back.

But you don't really do that and you don't really have isolation which is one of the problems. Dan Ingalls said yesterday (I thought it was very nice) about messaging that once you got messaging, you don't have to care where the message came from. You don't really have to care, the runtime system has to organize the delivery of the message, we don't have to care about how it's processed. It sort of decouples the sender and the receiver in this kind of mutual way. That's why I love messaging.

The 3 things that object oriented programming has it's messaging, which is possibly the most important thing. The next thing is isolation and that's what I talked about earlier, that my program shouldn't crash your program, if the 2 things are isolated, then any mistakes I make in my program will not crash your program. This is certainly not true with Java. You cannot take 2 Java applications, bung them in the JVM and one of them still halts the machine and the other one will halt as well. You can crash somebody else's application, so they are not isolated.

The third thing you want is polymorphism. Polymorphism is especially regarding messaging, that's just there for the programmer's convenience. It's very nice to have for all objects or all processes or whatever you call them, to have a printMe method - «Go print yourself» and then they print themselves. That's because the programmers, if they all got different names, the programmer is never going to remember this, so it's a polymorphism. It just means «OK, all objects have a printMe method. All objects have a what's your size method or introspection method.»

Erlang has got all these things. It's got isolation, it's got polymorphism and it's got pure messaging. From that point of view, we might say it's the only object oriented language and perhaps I was a bit premature in saying that object oriented languages are about. You can try it and see it for yourself.

http://www.infoq.com/interviews/johnson-armstrong-oop

Правда

He said object oriented languages aren't object oriented.

:) Я бы назвал Erlang конкурентным и распеределённым, но не ОО - нужно не путать эти вещи, messaging в конкурентном и распеределённом это одно (моделируется на основе _process_ calculus - CSP, pi/ambient, etc.), а в ООП это просто синоним (омоним по отношению к сообщениям IPC) к «method invocation» (моделируется на основе обычного _лямбда_ исчисления - F-omega-sub + Records + Dispatch Matrix), а «message sending» - просто метафора (какое это сообщение когда это сугубо локальный процесс выбора нужной функции из таблицы). Классическое ООП это, например, Java (в TAPL есть упрощённая модель) с вниманием к подтипам (наследованию) и вызову методов на объектах с динамической диспетчеризацией (по разным типам и подтипам).

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

messaging ... в ООП это просто синоним (омоним по отношению к сообщениям IPC) к «method invocation»

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

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

ООП. Каждая новая версия ядра.. наследует предыдущую!

special-k ★★★★
()
Ответ на: комментарий от quasimoto

Позиция разработчиков эрланга по поводу ООП

ЧТД

Спасибо за ссылку. Раньше видел эту статью. У меня флэша нет в системе - не читается сейчас. Мне нравятся еще изречения Армстронга в его блоге и на https://groups.google.com/forum/?fromgroups=#!forum/erlang-programming

Например: http://goo.gl/XoeVI

Люди спорят о том ООП это или не ООП ФП или не ФП - что по сути дела ничего полезного не несет. А эрланг продолжает работать, радовать и развиваться.

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

Никакой это не синоним, это банальная подмена терминов.

Синхронные inner-thread сообщения идентичны по поведению функциям привязанным к определённым данным. Если добавить подтипы - функциям с динамической диспетчеризацией.

В Simula (1967) были такие функции с динамической диспетчеризацией привязанные к данным класса = виртуальные методы, то есть вещи локальные по отношению к процессу выполнения, тем не менее, их трактовали как синхронные сообщения в рамках одного фактического процесса. Smalltalk, C++, Modula-3, Java, C#, Python, Ruby, Scala - те же самые идеи. Такое ООП про сокрытие состояния, предоставление интерфейсов, наследование с выполнением LSP и вызов методов времени выполнения. Можно сказать, что это всё было «не тем ООП», но тогда понятие «ООП» станет общим местом.

Хочется Алану Кею акцентировать внимание на «сообщениях» - пусть, только от этого в Smalltalk помимо методов не появятся синхронные / асинхронные и inter / remote process сообщения с простым механизмом приёма на уровне синтаксиса языка. Называть Erlang ОО языком в таком случае - тоже подмена терминов. На том уровне архитектуры на котором начинают играть роль конкурентность и распределённость классическое ООП со своими терминами и паттернами чаще остаётся не у дел. А на более простом уровне Erlang и вовсе чисто функциональный (не считая отдельных вещей вроде TLS).

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

Он закончит (он может перед вызовом метода сделать copy для данных), средствами указателей на функции можно покрыть синхронные inner-thread сообщения со стеком вызовов caller -> dispatcher -> callee_method, где dispatcher в самом простом случае это вызов функции по смещению в структуре.

Если делать асинхронные inter-thread методы (spawn per-method), то состояние объекта будет размазано по нитям, что не очень хорошо (хотя можно, если нужно, то с pthread_mutex_*). Для object per-thread с синхронностью или асинхронностью сообщений указатели на функции не очень полезны, скорее уже полезны какие-то обвёртки (вроде TBB) вокруг pthread/mqueue/semaphore. Разве что для интерфейсов остаются полезны.

То есть, ещё раз, уникальные плюшки ООП это подтипирование и интерфейсы, так что a : A, A <: B => a : B и A <: B, B implements I => A implements I, чтобы это работало требуется динамическая диспетчеризация (например, A <: C, B <: C, список [C] и вызов (map fn (list some-a some-b)). Интерфейсы предполагают сокрытие состояния, а подтипирование - динамическую диспетчеризацию, достаточно этих двух вещей. Всё остальное может быть реализовано параметрическими модулями, параметрическими функциями и прочими дженериками, функциональщиной, конкурентным, распределённым, ещё чем-то.

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

Например

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

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

никаких гарантий

Хотя в хаскеле можно сделать type Process m = (ThreadId, TChan m) и типизировать канал процесса как Process MessageType.

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

Итого, объект = процесс, «сообщение» = сообщение

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

Схема примерно такая:
стартует новый процесс A
создается «стейт» (примерно так-же как в gen_server)
процесс живет
имеем простой объект

Наследование: создаем еще процесс B (можно через A и от его имени)
цепляемся за A (считаем, что A родитель)
Для сообщений: обрабатываем сообщение: по-месту или передаем родителю
Вызов метода: handle_call если метод есть, то выполняем нет - передаем родителю

Можно для простоты реализации использовать gen_server.
Огорчает другое: нет пространств имен. Придется «прятаться» за пидами и выстраивать таблицу соответствий пид - имя (хотя привязка имен к пидам вроде есть штатно нормальная)

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

То есть я правильно понимаю, что аналогом

struct Cell {
    Cell(int value_) : value(value_) {}
    int get() { return value; }
    void set(int new_value) { value = new_value; }
  protected:
    int value;
};

class ReCell : public Cell {
    int backup;
  public:
    ReCell(int value_) : Cell(value_), backup(value_) {}
    void set(int new_value) { backup = value; Cell::set(new_value); }
    void restore() { Cell::set(backup); }
};

будет

-module(cells).
-export([cell/1, reCell/1]).

cell(Value) ->
  put(value, Value),
  cell().

cell() ->
  receive
    {Pid, get} -> Pid ! {ok, get(value)};
    {set, Value} -> put(value, Value)
  end,
  cell().

reCell(Value) ->
  put(backup, Value),
  Cell = spawn(cells, cell, [Value]),
  reCellLoop(Cell).

reCellLoop(Cell) -> 
  receive
    {Pid, get} -> Cell ! {Pid, get};
    {set, Value} -> Cell ! {self(), get}, Cell ! {set, Value};
    {restore} -> Cell ! {set, get(backup)};
    {ok, Value} -> put(backup, Value)
  end,
  reCellLoop(Cell).

?

  1. Во втором случае явно другая парадигма - сложней писать, сложнее отлаживать, есть лишние детали - выделение receive в функцию с рекурсией, передача Pid как обратного порта (цена асинхронности).
  2. Возник лишний метод ok - он нужен только для внутреннего общения предка с потомком, но при этом является «публичным» в reCell.
  3. Динамическая типизация, как следствие - рудиментарный контроль за интерфейсами в compile-time.
  4. Нет явных выражений для подтипов (опять же, статических гарантий никаких).
  5. Правда, что в reCellLoop нет race condition? Cell ! {self(), get}, Cell ! {set, Value} должны выполниться атомично. Ещё, если мы делаем Cell ! {self(), get}, то Cell должен успеть отправить {ok, get(value)} обратно до того как придут другие сообщения.
  6. Я не представляю как второе ложится на память и машинные инструкции.

На хаскеле 1-5 решаются за счёт свободы писать свои монадические комбинаторы поверх IO / STM, статической типизации переменных и сообщений, возможности скрывать имена в модулях, и того что диспетчер receive и (!) это атомичные STM транзакции:

data CellMessage = Get (Process Integer) | Set Integer | SendLocal ReCellProcess
type CellProcess = Process CellMessage

cell :: Integer -> IO CellProcess
cell n = process n $ receive . dispatch where
  dispatch :: TVar Integer -> CellProcess -> CellMessage -> STM ()
  dispatch value _ (Get p) = get value >>= (p !)
  dispatch value _ (Set m) = value =: m
  dispatch value _ (SendLocal p) = get value >>= (p !) . RecvLocal

data ReCellMessage = ReGet (Process Integer) | ReSet Integer | Restore | RecvLocal Integer
type ReCellProcess = Process ReCellMessage

reCell :: Integer -> IO ReCellProcess
reCell n = process n $ \r p -> do { cp <- cell n; receive (dispatch r cp) p } where
  dispatch :: TVar Integer -> CellProcess -> ReCellProcess -> ReCellMessage -> STM ()
  dispatch backup c _ (ReGet p) = c ! Get p
  dispatch backup c self (ReSet m) = c ! SendLocal self >> c ! Set m
  dispatch backup c _ Restore = get backup >>= (c !) . Set 
  dispatch backup c _ (RecvLocal m) = backup =: m
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Хотя в хаскеле можно сделать type Process m = (ThreadId, TChan m) и типизировать канал процесса как Process MessageType.

Так в Limbo и Go каналы тоже типизированные.

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

построить весь ООП-стек на легковесный процессах.

Для начала нужно будет ввести новое определение термина «ООП». Армстронг уже идет по этому пути, ага %)

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

Так в Limbo и Go каналы тоже типизированные.

И это хорошо. А операции на них как monadically composable memory transactions могут работать?)

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