LINUX.ORG.RU

Немного новостей из мира Rust

 


1

4

Последние новости из мира Rust вкратце:

  1. Вышла новая стабильная версия Rust 1.74.0.
  2. Сформирована новая команда по работе над официальной спецификацией языка Rust и представлено их видение.
  3. Ferrocene (набор инструментов компилятора Rust для критически важных сред и систем безопасности) прошёл сертификацию и теперь официально соответствует требованиям ISO 26262 и IEC 61508 и полностью пригоден для использования в средах, критически важных для безопасности.
  4. Доступно видео с конференции EuroRust 2023.
  5. Microsoft вкладывает 10 миллионов долларов, чтобы сделать Rust языком 1-го класса в своих инженерных системах.

Перемещено maxcom из talks

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

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

Хех. Простой вопрос: rectangle is-a square или square is-a rectangle. Ну а потом строим иерархию классов на этом.

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

Если вернуться к основной теме форума, то ядро линукса как-то живёт без явного наследования. Идиоты, наверно, 30 лет «долбаться под хвост».

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

Вот честно, считал, что одного раза достаточно.

ООП – это инструмент. Инструмент может подходить под задачу (GUI яркий пример), может не подходить.

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

Кроме того, есть ли в Rust наследование traits? Типа generic_io_device с наследниками serial_io_device и block_io_device.

Если я правильно врубился в раст, вы имплементируете поведение для трейта, а не наследуете, но для конкретных структур это работает как если бы это было наследование


trait Device {
    fn write(&self) {
        println!("Write to device")
    }
}

struct MyDevice;

impl Device for MyDevice {}

trait BlockDevice {}

impl<T> Device for T where T: BlockDevice {
    fn write(&self) {
        println!("Write to block device")
    }
}

struct MyBlockDevice;

impl BlockDevice for MyBlockDevice {
    
}

fn main() {
    let d1 = MyBlockDevice;
    let d2 = MyDevice;
    let devices: Vec<&dyn Device> = vec![&d1, &d2];
    for d in devices {
        d.write()
    }
}
FishHook
()
Последнее исправление: FishHook (всего исправлений: 1)
Ответ на: комментарий от red75prim

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

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

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

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

«обычное ооп»

Было бы лучше, если б вы его переименовали во что-то, больше соответствующие сути «обычного ооп». А то люди ожидают увидеть систему, основанную на обменивающихся сообщениями объектах, а получают какую-то странную композицию модулей и управление областей видимости. Расстраиваются, начинают спорить о словах, вот это вот всё …

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

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

а не потому, что ооп это плохо.

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

Считаете, что в вашем случае без него будет хреново, считайте, в чём проблема?

ХЗ, г.hrundel почему-то возбудился.

Не надо так нервно реагировать на упоминание систем не использующих ООП.

Более того, я и сам в рамках C++ далеко не всегда ООП применяю.

Я здесь попытался просто сказать, почему на мой взгляд, в Rust ООП не совсем нормальный и полноценный.

При этом неоднократно говорил, что если Rust-оманов имеющийся устраивает, то это хорошо.

Но мне почему-то стараются доказать, что ООП говно вааще. Ну вот без всяких оговорок.

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

ядра и проч. системная требуха пишутся на си исходя из простоты и доступности компилятора

Исходя из требований простоты компилятора тридцатилетней давности. Современный парк машин способен потратить слегка больше тактов на резолвинг абстракций нежели тот спектрум на котором студент Торвальдс упражнялся в программировании

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

ядра и проч. системная требуха пишутся на си исходя из простоты и доступности компилятора

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

red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 1)
Ответ на: комментарий от red75prim

Сейчас для этого больше используют кросскомпиляцию.

если у вас есть кросскомпилятор, то вы откомпилировав компилятор, опа!- получаете портированный компилятор!

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

потому и кросскомпиляция

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

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

Такое как раз лучше ложится на алгебраические типы данных и функциональщину, а не на ООП. В расте с этим как раз получше чем в C++, но похуже (рекурсивность) чем в OCaml или Haskell.

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

Такое как раз лучше ложится на алгебраические типы данных

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

товары->продукты_питания->мясо/птица->куриные_окорочка

описать аглебраическими типами… тогда как классами с наследованием это описывается один в один.

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

Потому что погромистам нельзя давать всё, что они хотят, надо давать то, что им нужно. Поэтому циничный примитивный Голанг так хорошо скармливается — оказывается, кодерам большего-то и не надо. Даже ООП не надо. А вы говорите, без ООП никуда. Конечно, ага 😁.

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

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

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

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от bread

Опять ты себя выдаешь: после перепоя плохо из-за перепоя, а не из-за чего-то еще дополнительно. Приятный код, читать одно удовольствие. Вот когда увидишь какие-нибудь ... -> Result<☹️😦😧😮😯😲> страшные в сигнатуре, поначалу не по себе 🤯.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от khrundel

Я привёл цитату 1987 года, в которой суть принципа Лисковой произнесена.

В том-то и дело, что нет.

В приведенной вами выше цитате:

«What is wanted here is something like the following substitution property: If for each object o_1 of type S there is an object o_2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o_1 is substituted for o_2, then S is a subtype of T.»

говорится, что нам хотелось бы иметь что-то вроде «substitution property», но что это за «property» и как оно может быть выражено (и может ли быть выражено вообще) не говорится. Т.е. это из категории «если бы у нас были такие приборы» ну или «за все хорошее против всего плохого».

Причем цитата не полная, в оригинале она выглядит так:

«What is wanted here is something like the following substitution property [6]: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T. (See also [2, 17] for other work in this area.)»

Т.е. говоря о «substitution property» идет отсылка к работе «Leavens, G. Subtyping and Generic Invocation: Semantics and Language Design. Ph.D: Th., Massachusetts Institute of Technology, Department of Electrical Engineering and Computer Science, forthcoming»

К сожалению, именно под таким названием эта работа не гуглится. Но зато есть работа того же Гари Ливенса LEAVENS G. 1989. Verifying object-oriented programs that use subtypes. Technical Report 439 (Feb.), MIT Laboratory for Computer Science. Ph.D. thesis., которая, полагаю, и является той самой работой, на которую и ссылалась Лисков (и эта диссертация Ливенса в 1987-ом еще была в режиме подготовки и под другим названием).

И как раз в работе Ливенса прямо в начале можно прочитать следующее:

Object-oriented programming languages, such as Smalltalk-80 [GR83], provide programmers with powerful tools. One of these tools is a generic invocation (or message passing) mechanism, which allows code to manipulate instances of different types. To reason about programs that use generic invocation, programmers often classify types by how instances of that type behave. If each instance of type S behaves like an instance of type T, then S is called a subtype of T. Programmers hope that if their code works correctly when it operates on instances of some type T, then their code will also work correctly on instances of subtypes of T. However, since they lack the formal tools to guide their classification of types and their reasoning, their reasoning lacks certainty.

Как раз вот этот «If each instance of type S behaves like an instance of type T» очень сильно напоминает «all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2».

А с учетом того, что Лисков ссылается на Ливенса еще вопрос, кто первым «substitution property» сформулировал.

Тогда как в работе от 1994-го года уже определены «формализованные» требования и сформулировано два определения для subtyping-а: одно на базе т.к. constraints, второе на базе extension maps. Причем эти определения оказали не полностью эквивалентны друг другу и одно определение допускает наличие подтипов с одними свойствами, а второе – с другими.

Так что ценность работы 1994-го года как раз в том, что там приведены критерии, которые позволяют сделать оценку, действительно ли тип A является подтипом B или нет.

Что любопытно, так это то, что в работе 1994-го года Лисков даже не упоминает свою статью от 1987-го, хотя есть упоминание ее более ранних статей от 1981-го и 1985-го. А вот ссылка на диссертацию (и другие работы Ливенса) как раз есть.

Вы пишете «точной формулировки нет». Что это?

Это то, что точной формулировки нет.

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

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

Это довольно странная версия, однако учитывая что именно принцип Лисковой и доказал полную несостоятельность ООП

А вот с этого места поподробнее, пожалуйста.

Ибо если в работе 1987-го года «наледование» еще хотя бы как-то упоминается и, натянув сову на глобус можно попробовать найти там критику ООП в пользу иерархии типов (но, при этом, Лисков прямо пишет: «An inheritance mechanism can be used to implement a subtype hierarchy. There would be a class to implement the supertype and another class to implement each subtype. The class implementing a subtype would declare the supertype’s class as its superclass.», т.е. указывает, что ООП-ное наследование может использоваться для выражения иерархии типов), то вот в статье 1994-го года вообще ООП упоминается (если не ошибаюсь) только один раз в разделе «abstract».

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

Удачи!

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 2)
Ответ на: комментарий от alysnix

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

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

Давайте пропустим этот бред. Да, с третьего раза вы напишете правильный пример, у вас будет, например, не default_indent, а additional_indent, который будет добавляться к заданному извне. Этот пример будет сомнительным, в том плане что нарушит внешние инварианты, либо get_indent будет возвращать несоответствующий рендерингу отступ, либо get_indent будет возвращать не то число, которое было передано set_indent, но пусть нам плевать и нас не беспокоит поломавшийся внешний код, который ищет tree_view с помощью dynamic_cast и предполагает, что всё знает о найденом типе. В этом случае вы получите пример, в котором плюсы действительно изменят поведение несколькими строчками, а аналог на расте потребует «наследования» через паттерн декоратор, т.е. композицию с последующим перенаправлением всех требуемых виджетом методов внедрённому tree_view, а это очень много кода.

Важно другое: в данном примере вы не добились чего-то добавив пару строк, вы серьёзно ухудшили программу, многое поломав, написав лишние десятки строк и не добавив ничего. Единственная ценность такого кода - демонстрация крутизны наследования. Давайте представим, что мы делаем что-то полезное. Например добавляем indent к классу tree_view, который его сам по себе не поддерживает. И мы по какой-то причине не можем обернуть его в другой виджет, просто добавляющий indent. Можно ли такое в плюсах с наследованием? Да, если все нужные методы виртуальны. Вы добавите сдвиг в функции рисования. Вы добавите что-то к результату базового вычисления размера. Во всех обработчиках событий мыши добавите сдвиг координат. И это будет работать. Ваш коллега растовик с его декоратором сделает то же самое, но кода у него будет в 2 раза больше. Однако должен заметить, что половина кода от декоратора - это уже не «2 строки» и выгода не столь уж очевидна. Но самый цимес начнётся, когда в вашем проекте обновится библиотека гуи. Добавится, например, баблинг событий мыши. У растовика сломается сборка, а у вас просто начнутся глюки от того что половина обработки мыши базовым классом не совпадает по координатам с другой, которую вы не переопределили.

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

Создатели явно хотели сделать ещё хуже, чем в с++

Не то что хотели, а просто так само получается, когда пытаются всё это великолепие втиснуть в шкурку сишки. Всё, что чуть сложнее жавы, в ней отвратно выглядит. Но в расте совсем уже фимоз с этими fn и закорючками. Словно какие-то крокодилы всплыли из 70-х и дизайнили раст на PDP-11.

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

Словно какие-то крокодилы всплыли из 70-х и дизайнили раст на PDP-11.

Первоначальный разработчик Rust-а, вроде как любитель OCaml-а был. И даже первые версии компилятора Rust-а на OCaml-е писались.

Не зря же в свое время шутка ходила, что Rust – это внебрачный ребенок OCaml и Си :)

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

Существует класс agent_t,

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

Вот, скажем, зачем вам непустые виртуальные методы? Там находится что-то необходимое? Тогда зачем вы позволяете наследнику не вызвать это необходимое? Исполняйте это вне пределов виртуальных функций, а между вызывайте виртуальные пустышки. Там находится наоборот, необязательное? Но как вы можете быть уверены, что наследник, решивший не вызывать метод базового класса соблюдёт необходимые ритуалы? Откуда ему вообще знать, нужно вызвать базовый метод или нужно забить? Как читатель кода поймёт, это лопух-программист тупо забыл вызвать базовый метод или это было осознанное решение и в базовом было что-то ненужное. Это всё нарушает один из базовых принципов ООП - инкапсуляцию. Потомок, написанный другим человеком, в другом проекте, вынужден знать особенности реализации ваших агентов и их ковырять грязной вилкой. Более того, в виду вот этих практических особенностей методы перестают быть методами, вы декомпозируете процесс не по границам осмысленных действий, а по границам возможных переопределений, в итоге метод превращается из doSomethingMeaningful() в stepOneOfBigProcessSeeDocForExplanation(). Это не просто плевок в ООП, это даже не процедурное программирование. И то что вы используете для этого наследование как бы просто от бедности старых плюсов. В 90х было так принято писать из-за отсутствия замыканий, теперь пишут по инерции, в 200х в «потомке» под названием C# это стали заменять тупым присваиванием делегатов, это в общем-то нагляднее, и самому процессу виднее было ли «переопределение», он тупо сравнивает значение проперти с null.

Ну и на тему «нужно ли», ваш говнокод вполне можно написать и на расте. В расте есть дефолтные имплементации в трейтах.

trait AgentConfigurator {
    fn foo(&self, agent: &mut Agent){
        doFooSimpleWay(agent)
    }
}

Метод foo можно не переопределять, тогда он вызовет одну реализацию, а можно переопределить и вставить doFooComplexWay(…), будет в общем даже нагляднее и понятнее.

Желающие отказаться от таких возможностей путем пердолинга с переопределением traits или еще какой-то ручной возней с динамической диспетчеризацией могут попробовать доказать, что это не ООП, а даже если и ООП, то нинужно. Но лучше не тратить ничье время.

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

Хотелось бы попросить такого же поведения и от вас, но вы же известный здесь khrundel, так что это заранее бесполезно.

Я доказываю всё что пишу. Балаболить не привык, в отличие от вас.

В интернетах много чего пишут. Вы тут целые простыни высрали.

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

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

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

Во-первых, перечитайте то, что я писал.

О, я много прочитал попыток вывернуться и не спорить по существу. Чего стоит хотя бы принцип Лисковой: начали с опровержения заявления о 5 годах, видимо сдуру показалось удобной мелочью за которую можно зацепиться и не обсуждать главный тезис, но, блин, небольшая промашка вышла и теперь необходимо делать вид, что есть очень серьёзный вопрос, «почему 94 год».

Во-первых, не стало.

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

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

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

Во-вторых, оно там и не прототипное.

Спасибо, я знаю. Непонятно только зачем вертеть жопой и вспоминать прототипное наследование, типа чтоб просто слов накидать? Так есть в Расте наследование или где? Все поклонники ООП замерли в ожидании вашего вердикта.

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

Вы всерьёз думаете что в вашем случае это сложно?

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

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

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

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

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

Да, с третьего раза вы напишете правильный пример, у вас будет, например, не default_indent, а additional_indent, который будет добавляться к заданному извне. Этот пример будет сомнительным, в том плане что нарушит внешние инварианты, либо get_indent будет возвращать несоответствующий рендерингу отступ, либо get_indent будет возвращать не то число, которое было передано set_indent, но пусть нам плевать и нас не беспокоит поломавшийся внешний код,

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от khrundel

Важно другое: в данном примере вы не добились чего-то добавив пару строк, вы серьёзно ухудшили программу, многое поломав, написав лишние десятки строк и не добавив ничего. Единственная ценность такого кода - демонстрация крутизны наследования. Давайте представим, что мы делаем что-то полезное. Например добавляем indent к классу tree_view, который его сам по себе не поддерживает. И мы по какой-то причине не можем обернуть его в другой виджет, просто добавляющий indent. Можно ли такое в плюсах с наследованием? Да, если все нужные методы виртуальны. Вы добавите сдвиг в функции рисования. Вы добавите что-то к результату базового вычисления размера. Во всех обработчиках событий мыши добавите сдвиг координат. И это будет работать. Ваш коллега растовик с его декоратором сделает то же самое, но кода у него будет в 2 раза больше. Однако должен заметить, что половина кода от декоратора - это уже не «2 строки» и выгода не столь уж очевидна. Но самый цимес начнётся, когда в вашем проекте обновится библиотека гуи. Добавится, например, баблинг событий мыши. У растовика сломается сборка, а у вас просто начнутся глюки от того что половина обработки мыши базовым классом не совпадает по координатам с другой, которую вы не переопределили.

у вас крышка едет реально и вы не понимаете существо вопроса. повторяю еще раз.

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

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

как будете этот вопрос решать вы со своими трейтами?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от eao197

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

Вы ведь в курсе, что проперти - это не только геттер и сеттер? Ну я на всякий случай спрашиваю.

В цитате эта самая проперти и есть принцип подстановки, и он формулируется вполне понятно «если соблюдаются эти условия то тип 1 потомок типа 2». Никаких «инструментов» тут нет. И по факту никакой проперти тоже, просто сам принцип.

Кстати, формулировка в 94 ещё более укурная, там по математике, прувабл и тому подобное, но в тексте всё равно сообщается о поведении объектов.

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

Это то, что точной формулировки нет.

Это неправда. Уж коль скоро решили строить из себя акадэмика, могли бы по таким мелочам не палиться. Принцип Лисковой формулируется как раз в формулировке 87 года. В 94м он описан:

Subtype Requirement: Let phi (x) be a property provable about objects x of type T. Then phi (y) should be true for objects y of type S where S is a subtype of T.

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

Ибо если в работе 1987-го года «наледование» еще хотя бы как-то упоминается и, натянув сову на глобус можно попробовать найти там критику ООП … то вот в статье 1994-го года вообще ООП упоминается (если не ошибаюсь) только один раз в разделе «abstract».

Браво. В статье о субтайпинге оказывается нет упоминаний ООП.

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

Видите ли.. у нас с вами был небольшой sapienti sat moment. Я дал вам начальную точку, указал направление и предложил проделать путь самому. Вы не смогли. Я указал ближайший ориентир, но и этого оказалось мало. Теперь начался идиотизм с требованием привести как минимум бумагу за подписью Лисковой, а желательно так вообще постановление межправительственной комиссии о том, что ООП - говно.

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

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

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

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

Давайте представим, что мы делаем что-то полезное. Например добавляем indent к классу tree_view, который его сам по себе не поддерживает.

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

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

это какой-то «ооп алкоголиков»… и вовсе не относится к ооп. если вам кто-то переделает семантику просто функции printf(вне всякого ооп), и она станет по иному толковать теги формата - то у вас тоже ничто не сломается. только весь вывод превратится в абракадабру. это что - недостаток традиционного понятия функции или просто у авторов с головой не в порядке?

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

Поэтому собственно вывод, который из всего этого сделала индустрия: запрет на наследование как таковое.

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

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от khrundel

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

лискова(да и хрен с ней, слишком часто она упоминается уже) просто сформулировала, какое отношение классов A и Б можно называть наследованием, сформулировала для этого некий типа «инвариант».

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

чего воду в ступе толочь-то?

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

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

т. вы просто не поняли. ваш код не был эквивалентом моему

Безусловно был. Код определяется тем, что он делает. Разве я виноват, что вы написали бесполезный код?

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

Ваше поле даже компилятор имеет право выкинуть. Слушайте, давайте начистоту, без обид: я понял что вы - дурак. Что вы даже не можете с 2х попыток родить код, который сформулирует мысль, которую вы пытаетесь довести. Подыгрывать вам мне надоело, я предложил вам пример, который бы продемонстрировал вашу не шибко-то глубокую мысль. После чего высказал вам 2 контраргумента:

  • в реальном, действительно полезном подклассе вам не удастся обойтись 2мя строчками, и даже 20, вам скорее всего придётся написать большую долю того кода, который реализовал бы полноценный декоратор.
  • ваш код будет хрупким, может посыпаться просто от обновления библиотеки и вы даже не узнаете о возможности проблемы пока она не выпадет на проде.

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

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

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

Ну и напоследок, чисто чтоб поржать, вот вам псевдокод на Расте:

struct MyFancyTreeView {
  parent_tree_view: TreeView,
  default_indent: i32
}

#[redirect(parent_tree_view, setIndent, getIndent, render, preRender, ... )]
impl TreeViewTrait for MyFancyTreeView
{
  fn resetIndent(&mut self) {
    self.parent_tree_view.setIndent(self.default_indent)
  }
}

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

В общем в рамках пути, выбранного разработчиками Раста все ваши любимки реализуемы и гораздо лучше чем в «ООП».

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

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

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

Что до предложенного мной примера, он вполне себе может быть реальным. Возьмите виджет типа border он будет действовать примерно как описанный мной, будет хранить дочерний виджет, будет при рендеринге сдвигать начало координат, будет приводить координаты в мышинных евентах в систему координат дочернего виджета и передавать ему. Так что единственное отличие предложенного виджета от обычного бордера с прозрачным цветом границы - это то что IndentedTreeView ещё и реализует интерфейс TreeView. Сложно представить зачем такое могло понадобиться, но, например, если какой-то внешний контракт требует от вас вернуть именно TreeView (интерфейс) и добавляет на форму, а вам нужны отступы.

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

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

таким образом безбашенно критикуя «наследование», вы критикуете просто композицию.

неважно как вы используете функцию f(…) из класса A

вот так, через наследование:

class B: A {
  void ff() {
    A::f();
  }
}

или через композицию

class B {
  A _a;
  void ff() {
    _a.f();
  }
}

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

просто удивительно как люди блуждают в одной сосне.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от khrundel

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

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

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

wandrien ★★
()
Последнее исправление: wandrien (всего исправлений: 2)
Ответ на: комментарий от alysnix

клован, однократное наследование в с++ это просто композиция, где обьект базового класса

Пришло время охренительных открытий. Я вам тайну открою: множественное тоже. Т.е. class A: B, C так же добавит C причём полностью, включая указатель на vtable. Иначе каст с указателя на A в указатель на C не работал бы, а так просто смещение прибавляется и в путь.

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

Что до остальной мысли… Хммм… Интересно, а зачем же тогда всякие умные люди советуют избегать наследования и заменять её композицией? Что это? Некомпетентность? Заговор?

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

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

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

Специальная теория относительности запрещает достижение и превышение скорости света частицами ненулевой массы. Ровно это. Не меньше, но и не больше.

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

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

Пришло время охренительных открытий. Я вам тайну открою: множественное тоже. Т.е. class A: B, C так же добавит C причём полностью, включая указатель на vtable. Иначе каст с указателя на A в указатель на C не работал бы, а так просто смещение прибавляется и в путь.

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

хватит болтать. лучше ответьте почему все пороки просто отношения - «использование»(смотри UML), вы перенесли именно на наследование?

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

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

еще раз для тупых. наследование это технически композиция с ДЕКЛАРИРОВАНИЕМ СОВМЕСТИМОСТИ ДАННОГО ТИПА С ВКЛЮЧАЕМЫМИ ТИПАМИ, обеспечиваемой тем или иным образом.

для совсем тупых - КРИТИКА НАСЛЕДОВАНИЯ ЭТО КРИТИКА КОМПОЗИЦИИ, поскольку совместимость вообще никак в ваших аргументах не затрагивается. если вы только тронете совместимость, полетит вся ваша совместимость в интерфейсах, реализациях и проч пурга.

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

вы бредите.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от khrundel

Ну что ж, слив засчитан.

Как ожидаемо.

Тем не менее, цитаты и ссылки мной приведены. Любой желающий может сам пройтись по ним и составить собственное мнение: доказывают ли работы Барбары Лисков «полную несостоятельность ООП» или же, напротив, формируют более четкие критерии для ответа на вопрос «is-a»

Но вся эта история не может быть полной без упоминания Design By Contract из Eiffel-я, появившегося как раз во второй половине 1980-х. Желающие могут посмотреть вот этот обзорный документик от 1992-го года: Applying “Design by Contract” и сравнить то, что Бертранд Мейер пишет про пред-, пост-условия и инварианты с тем, что описывается в работе Лисков от 1994-го. В частности, можно посмотреть на страницу 9, где говорится о применении пред- и пост-условий при наследовании.

И все это, нужно отметить, в чистом ОО-языке. Подчеркну: в чистом , а не гибридном (вроде C++ или D).

Несостоятельность ООП доказана полностью. Полностью! (это шутка, если что).

eao197 ★★★★★
()