LINUX.ORG.RU

В чём профит от Eiffel...

 ,


2

4

...и, в частности, от design by contract? Чем эта фича принципиально отличается от ассертов в других языках?

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

Мой интерес вызван тем, что Бертран Мейер - автор языка Eiffel - возглавляет (возглавлял?) кафедру программной инженерии и верификации программ в СПбНИУ ИТМО (http://sel.ifmo.ru/), и используют они в основном Eiffel.

★★★★★

Последнее исправление: hateyoufeel (всего исправлений: 3)
Ответ на: комментарий от Miguel

А много написано на Eiffel?

Без понятия. Слышал, что сам EiffelStudio + EiffelVision — это несколько миллионов строк на Eiffel-е. Плюс несколько раз по столько в разных проектах, вроде системы управления метро для какого-то европейского города.

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

О том, что null pointer - это плохо, говорили ещё в 70х.

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

И как широко языки без null pointer используются сейчас?

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

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

Что такое «мейнстримовый язык» ?

И как широко языки без null pointer используются сейчас?

Я и мои коллеги используем Haskell и Erlang. Помимо этого, довольно таки широко распространён OCaml. В Scala null references считаются крайне плохим стилем. В Rust есть ADT.

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

Что такое «мейнстримовый язык» ?

Вы прикалываетесь?

Я и мои коллеги используем Haskell и Erlang. Помимо этого, довольно таки широко распространён OCaml. В Scala null references считаются крайне плохим стилем. В Rust есть ADT.

Из того, что вы перечислили, более-менее распространены Erlang и Scala. Rust только пару дней назад вышел в версии 1.0.

Haskell и OCaml как были экзотикой на общем фоне, так и остаются.

Хотя, если вы зарабатываете на Haskell и Erlang, вы смотрите на мир с другой стороны.

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

Вы прикалываетесь?

Нет, я серьёзно. К тому же, как верно подметил анонимус, аргумент к популярности - это не доказательство.

Rust только пару дней назад вышел в версии 1.0.

Да, поэтому мы его пока не применяем, но он выглядит как неплохая замена C++ во многих случаях.

Haskell и OCaml как были экзотикой на общем фоне, так и остаются.

Экзотика - это Malbolge.

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

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

Квантовая механика где-то рядом.

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

Нет, я серьёзно.

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

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

Собственно, пример с Eiffel показателен. Eiffel нифига не мейнстрим. Поэтому найти для него какую-нибудь библиотеку, скажем, для работы с аргументами командной строки или с SOAP — это нужно будет постараться.

Тогда как для каких-нибудь Java, C#, Python, Ruby или даже C или C++ это на порядок проще.

Экзотика - это Malbolge.

Если не секрет, в какой области работаете?

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

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

PHP.

Собственно, пример с Eiffel показателен. Eiffel нифига не мейнстрим. Поэтому найти для него какую-нибудь библиотеку, скажем, для работы с аргументами командной строки или с SOAP — это нужно будет постараться.

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

Если не секрет, в какой области работаете?

В области программирования, конечно же.

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

сам EiffelStudio + EiffelVision

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

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

что без null нельзя реализовать некоторые фундаментальные структуры данных

Можно реализовать ограниченной версией null, без строгой необходимости в универсальной, то есть с помощью значений 1 -> T в категории типов языка, для каждого типа T отдельно (ADT соответствуют диаграммы 0, 1, 2, ... : 1 -> N, схемы None : 1 -> Optional<T>, ..., Empty : 1 -> List<T>, ... и т.п.), без свойственного динамической типизации примешивания значений (если уж тут статика). null же требует ссылок и подтипирования с универсальными схемами Null < &T, Null !< T, null : &Null (also, Nothing < &T, Nothing < T) и привет null : Option[T] вместе с None : Option[T] (это всё Scala).

И, кстати, где null у ссылок в C++? Понятно, что нет...

Вот указатель это уже другое дело — индекс плюс (иногда забытый) размер, индекс может быть нулём, нет проблем.

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

И, кстати, где null у ссылок в C++? Понятно, что нет...

Понятно, что и списков, где ссылки на соседние узлы делаются через С++ references, тоже нет.

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

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

Да легко. В Ассемблере тоже хотели Optional для тех же списков, но тратить лишнее слово на тег - недопустимая роскошь же. Поэтому выдумали костыль с особенным специальным значением для указателей (потому что туда его можно пристроить и никто не заметит пропажи одного из значений). В Си он перешёл, потому что был понятен ассемблерщикам. В мейнстримные языки - потому что был понятен сишникам. Исключительно вопрос популярности и скорости обучения, а не приобретаемых преимуществ.

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

Блин, откуда на LOR-е такое количество анонимных долбодятлов? Или это ресурс специально для таких?

«Tony Hoare introduced Null references in ALGOL W back in 1965 “simply because it was so easy to implement”, says Mr. Hoare.»

1965-й год, до начала работ над языком C еще четыре года.

eao197 ★★★★★
()

Контракты и код должны писать два разных человека, в разных отделах, с разными начальниками. Тогда есть смысл.

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

Что же так мешает программисту написать контракт и код что нужно заводить второго программиста с начальником?

Безусловно, больше глаз лучше, но не надо доводить это до абсурда.

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

Что же так мешает программисту написать контракт и код

Внутренний естественный конфликт в голове. Любой здоровый человек в таких случаях начинает «срезать углы».

не надо доводить это до абсурда.

Это не абсурд. Очень часто делают так, например, что охрана предприятия не подчиняется директору, или ОТК подчиняется другому министерству, чем само производство. И это правильно.

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

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

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

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

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

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

Вообще контракты обычно применяются именно в «mission critical».

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

Вообще контракты обычно применяются именно в «mission critical».

Мне кажется, вы путаете DbC в Eiffel со проверками на соответствие спецификаций в Spark.

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

Но разве подобное уже применяется где-то в ПО «гражданского» профиля?

«Подобное» — это вы про DbC?

Если про DbC, то в том же Eiffel DbC применяется повсюду. EiffelVision написан с контрактами, а это библиотека самая обычная, никакого отношения к mission-critical не имеющая.

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

Вообще контракты обычно применяются именно в «mission critical».

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

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

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

почему контракты причислены исключительно к инструментарию серьёзных дядек

Да как-то так сложилось... А вы применяете это в каких-то «мирных» целях? Пока не случалось такое видеть.

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

Но разве подобное уже применяется где-то в ПО «гражданского» профиля?

«Гражданский» - это какой? В статье говорится о применении Ada в civilian aircrafts.

Вообще контракты обычно применяются именно в «mission critical».

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

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

В этом плане, ясно. Странная формулировка.

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

А вы применяете это в каких-то «мирных» целях?

Да, если считать контрактами assert-ы. Я люблю делать валидацию входных данных в случае если там сложные типы или взаимоисключающие аргументы. Покрытие далеко не 100%, только там где «чувствую что надо».

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

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

Ну вот для ссылок не нужен глобальный null, и для списков тоже.

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

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

Для этого нужно сделать класс-обертку над ссылкой. Это не так сложно, в принципе, но бессмысленно. Гораздо лучше было бы использовать какой-нибудь boost::variant в связке с Mach7, если уж требуется своя megatypesafe реализация спиисков.

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

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

C++ я упомянул как язык где с ссылками не связано стандартной «нулевой ссылки» (ни для конкретного типа, ни глобально). Это вообще нормально (http://www.cis.upenn.edu/~bcpierce/tapl/). Указатель это *(T) = Ref(Option(T)) с частичным operator*, конкретный DList* в структуре и возможность использовать nullptr или вовсе Ptr<T> с конструкторами Ptr<T>(T&) и Ptr<T>() это не то же самое, что null где-нибудь в Java или Scala, последние форсят подтип Null со значением null ко всем определяемым типам, даже когда их не просят.

Но речь не о том, а об ADT. Двусвязный список это List(T) = 1 + T * List(T)^2 (конструкторы Empty и Cons (поля value, prev, next)) как ADT, так что с автоматическим управлением памятью можно ожидать (*ML, Haskell, Scala) прямой реализации без всяких null, указателей и т.п., по крайней мере с лицевой стороны. В Rust можно ожидать прямой реализации с Box. В C++ можно обойтись хоть просто указателями, хоть наследованием и ссылками на интерфейсы или в духе тех же ADT с boost::make_recursive_variant — ни указателей, ни ссылок, ни nullptr.

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

Для этого нужно сделать класс-обертку над ссылкой.

Сделайте и покажите.

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

Но речь не о том, а об ADT.

Речь уже давно о сферических конях в вакууме.

ТС сказал, что void safety в Eiffel — это костыль, и что в случае с ADT необходимости в Void в языке нет. На что было указано, что без аналога Void/null в императивных языках нельзя работать с определенными структурами данных. И что None в Optional(T) играет ту же роль, что и Void/null. В чем легко убедиться на такой простой структуре данных, как двухсвязный список.

Вы можете написать еще 100500 раз умные слова вроде: «Указатель это *(T) = Ref(Option(T)) с частичным operator*, конкретный DList* в структуре и возможность использовать nullptr или вовсе Ptr<T> с конструкторами Ptr<T>(T&) и Ptr<T>() это не то же самое, что null где-нибудь в Java или Scala, последние форсят подтип Null со значением null ко всем определяемым типам, даже когда их не просят.» Но они все равно не закроют суть: вам нужно будет иметь две разных сущности Ptr<T>(T&) и Ptr<T>(). И вторая из них, Ptr<T>(), будет ничем иным, как прямым аналогом Void/null.

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

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

Но это же бгед :) Так и число 42, утрируя, это такая же «сущность» для типа int — нужно наличие, нужен способ отличать все остальные числа от него, чтобы определить это число 42. None это законное значение типа Optional, как 42 — int, Empty — List, и 0 — NNO. Не важно императивно или нет, математически так, теоретико-множественно. И диаграмма списков в категории типов того же вида, что и диаграмма NNO (с полиморфизмом это будет функтор, но не суть), и пустой список это такого же рода стрелка (значение, 0-арный конструктор в нормальной форме), что и число 0 для NNO или 42 для int. Указатели, отсутствующие ссылки и всё прочее это уже артефакты реализации — я упомянул *ML, Haskell, Scala, Rust и boost (императивные?), в которых можно без такой реализации обойтись, потому что есть ADT.

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

Глобальный (!) null таким вещам не упёрся, они явно не аналог такой колесницы:

val x: Option[Int] = null

Scala, как туда попал null — потому что Null < любого ссылочного типа, в т.ч. Option.

var x /* : Top */ = 1
x = "2"
x = null

JS — потому что {любое значение, в т.ч. 1, «2» и null} < Top.

Есть тут что-то общее :) Неограниченные схемы подтипирования это свойство динамических систем типов, их отсутствие или ограниченность (классическое ООП) даёт «герметичность» и статические проверки, иначе проверок нет (о чём выше писали).

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

Так и число 42, утрируя, это такая же «сущность» для типа int — нужно наличие, нужен способ отличать все остальные числа от него, чтобы определить это число 42.

Доказательство по аналогии суть демагогия.

Речь не про int-ы и теорию множеств. Речь про ссылки/указатели. Для которых важны всего несколько значений — актуальная ссылка на какой-то объект и отсутствие таковой.

И вы либо вводите в язык понятие Void/nullptr для обозначения ссылки без значения. Либо вынуждены достигать такого же через специальные случаи в виде None для Option[T].

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

optional/nullable типы помогают в этом случае.

template<typename T>
struct ref {
    ref(std::nullptr_t) = delete;
    explicit ref(T *ptr)
        : p(ptr)
    {
        if (!p) {
            throw std::runtime_error("bla-bla-bla");
        }
    }
    T * operator -> () const
    {
        return p;
    }
    T & operator * () const
    {
        return *p;
    }

private:
    T * p;
};

template<typename T>
struct node {
    T data;
    optional<ref<node>> next;
};

На самом деле мне жаль, что в языке нет этого разделения на указатели(которые всегда указывают на что-то) и optional/nullable, которые применимы к любым типам, не только указателям. Делать велосипеды в реальном проекте не хочется.

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

Речь про ссылки/указатели. Для которых важны всего несколько значений — актуальная ссылка на какой-то объект и отсутствие таковой.

Во многих случаях вам не нужен null. Вернее он является некорректным значением для ссылки. И никаких альтернатив у вас в системе типов нет. Разве что костыль делать, как я выше показал.

anonymous
()
Ответ на: комментарий от anonymous
template<typename T>
using nullable_ptr = optional<ref<T>>;

Это если нужно.

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

Алгебраическим типам — теорию множеств.

Появление сырых указателей и nullptr в таком контексте это как если бы мы начали рассуждать о машинном представлении (кодировании) структуры данных («специальный случай») — разумеется, слово (или два) на месте ссылки будет пронумеровано тегом в зависимости от того, на какой вариант оно ссылается, оно может содержать все данные значения n-арного конструктора по «ссылке», либо содержать его адрес, в случае значения первого 0-арного конструктора (пустой список, например) оно даже может быть машинным нулём («ссылка без значения», срочно вводить в язык).

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

Разве что костыль делать, как я выше показал.

То, что вы показали, это эмуляция средствами C++ типа Optional[T] из языков с паттерн-матчингом. При этом плохая эмуляция, т.к. проверки переносятся из compile-time в run-time.

При этом вы нифига не избавились от ситуаций, когда нужно явно определить отсутствие значения ссылки. Просто ваш костыль будет это делать теперь не с голым указателем и nullptr, а со специальным значением optional<ref<T>>(). Которое нужно будет явным образом использовать при «обнулении» ссылки и явным образом проверять при обращении по ссылке.

Можно сколько угодно много говорить умных слов про систему типов, теорию множеств и т.д., но если раньше нужно было писать:

item.next = nullptr;
...
if(item.next)
  item = item.next;
То будет нужно писать:
item.next = optional<ref<T>>();
...
if(item.next)
  item = item.next.get();
Причем, в случае с C++, компилятор не даст вам по рукам, если вы напишете:
item = item.next.get();
забыв предварительно написать if.

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

Так вот в Eiffel это решили кардинальным образом без введения в язык AlgDT и паттерн-матчингом (ФП-фанбои могут идти лесом со своими любимыми ФП-языками, т.к. Eiffel никогда таким не был).

Однако речь не об этом. А о том, что даже в случае с AlgDT и паттерн-матчингом какой-то аналог Void/nullptr для показанных выше случаев вам все равно нужен будет. Потому что все равно нужно будет писать что-то вроде:

item.next = None;
...
match item.next {
  case Some[T] => ...
  case _
}
Что, при всем уважении к ФП/AlgDT/паттерн-матчингу есть те же яйца, только в профиль.

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

Появление сырых указателей и nullptr

В контексте темы Eiffel-я уход от указателей и nullptr в потоки сознания про n-арные конструкторы, которые без кандидатской степени не распарсишь, есть какая-то пустая демагогия.

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

даже в случае с AlgDT и паттерн-матчингом какой-то аналог Void/nullptr для показанных выше случаев вам все равно нужен будет

Только вот аналог nullptr невозможно будет разыменовать.

Так вот в Eiffel это решили кардинальным образом без введения в язык AlgDT и паттерн-матчингом (ФП-фанбои могут идти лесом со своими любимыми ФП-языками, т.к. Eiffel никогда таким не был)

Я тебе страшное скажу: AlgDT есть в обычных императивных языках под названием... tagged unions, ты знал!

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.