LINUX.ORG.RU

Зачем нужны динамические языки?


0

0

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

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

В ruby (особенно в гомогенных проектах!) особо собирать ничего не надо. По сему не представляю как можно сравнивать make и rake в таком контексте :]

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

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

>Учи матчасть ... select table tbl (id integer, name varchar(5))

И что? Почему это разные классы с т.з. исходников сервера (выше говорилось про необходимость перекомпилить оный при alter table)?

>без перезапуска не обойтись. Именно то, о чём я и говорил

Ээ нет!! Ты говорил, что "Никто не поймет, если нужно будет перезапускать". А вот же, перекомпилируют статический язык, перегружают целиком или модулями, и друг друга понимают :)

>В это время возможна работа С ОСТАЛЬНЫМИ ТАБЛИЦАМИ

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

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

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

> Ээ нет!! Ты говорил, что "Никто не поймет, если нужно будет перезапускать". А вот же, перекомпилируют статический язык, перегружают целиком или модулями, и друг друга понимают :)

Во-первых, это просто один из миллиона других оконных менеджеров. Может быть, он вообще плохой. Откуда мне знать? Во-вторых, я не говорил, что динамизм нужен _всегда_. Я говорил, что он просто нужен, отвечая на вопрос темы. А вопрос был о том, нужен ли динамизм хоть когда-то. С моей точки зрения, я привёл достаточно хороший пример, когда он нужен.
Мы перебрали при этом не все возможные варианты использования динамизма в SQL и не все возможные варианты его реализации. Например, я почти уверен, что многие варианты alter table в реальных серверах можно делать одновременно с работающими на этой таблице запросами.

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

Ладно, на следующей неделе я на форумы не хожу, разве только доделаю одну тему на comp.lang.lisp.

Всего хорошего!

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

>> невозможно определить те строчки, в которых лежит sql-запрос. А уж если она генерируется на лету, то тем паче.
> Делать можно и по-другому - например, генерировать классы из описания схемы.


На запросы-то это всё равно не повлияет. Или ещё до кучи всё запросы в проверяемом виде писать?
Хочу посмотреть на такую либу!

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

> Итого, это не "невозможно" а "несовместимо с используемым API БД".

Ну разумеется, если сделать api бд, неотрывным от базы, то проблем не будет. Только это сферическое апи в вакууме.

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

>если сделать api бд, неотрывным от базы

А я думал, это нельзя понять неправильно. Проблема не в "неотрывности от базы", а в возможности анализа "запросов" во время компиляции. Достаточно отделить описания запросов в отдельный тип/синтаксис/whatever и статическая проверка уже может обнаруживать несовместимости, проблемы с правами, и т.п.

Т.ч. конкретные примеры с sql бд и 10м правилом не являются убедительными. Что, впрочем, не означает, что "динамика не нужна" -- просто "не обязательна в этом применении".

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

>Во-вторых, я не говорил, что динамизм нужен _всегда_. Я говорил, что он просто нужен

А я не говорил, что не нужен. Я говорил, что в приведенных примерах его "предпочтительность" не так уж очевидна. Может это просто примеры "плохие"?

>Если упереться рогом и снизить качество решения, затруднив при этом эксплуатацию

Вот же ж. Показано, что "затруднения эксплуатации" вызваны не "статичностью средств", а "непродуманностью особенностей". Можно сделать "полную перегрузку" с меньшими последствиями, чем "сброс кеша" (наблюдал), причём первое намного проще реализуется (YMMV). Кроме того, "остановка/апдейт/запуск" даёт только "несколько" _гарантированных_ отказов. IMO это намного лучше постоянного потока случайных отказов от "неблокирующего" режима. Не говоря уже об "неизвестном" состоянии в случае больших апдейтов в распреденённых системах c таймаутами. Начальство любит предсказуемость:)

DonkeyHot ★★★★★
()

ох сколько нафлудили-то. почитаем, почитаем...

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

> Достаточно отделить описания запросов в отдельный тип/синтаксис/whatever и статическая проверка уже может обнаруживать несовместимости, проблемы с правами, и т.п.

Ну пусть хоть и так. Хочу видеть такую либу!

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

>Хочу видеть такую либу!

То немногое, о чём даже я слышал: oracle proc/c++ выделяет запросы "синтаксически" (exec sql declare blabla cursor for select ...). haskelldb, sqlalchemy для "представления" таблиц и операций с ними в программе используют "выделенные" типы/классы/функции.

Т.ч. они есть, и "db.execute(strA+strB+strC)" не вершина прогресса, а "наименьший общий" тип API. Да, мне тоже нравятся "универсальные" инструменты. Но они далеко не по любому критерию наилучшие.

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

> То немногое, о чём даже я слышал: oracle proc/c++ выделяет запросы "синтаксически" (exec sql declare blabla cursor for select ...). haskelldb, sqlalchemy для "представления" таблиц и операций с ними в программе используют "выделенные" типы/классы/функции.

Ок, буду знать, что такие существуют. Судя по слову "слышал", о реальном опыте работы с ними у тебя спросить не получится.

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

>буду знать, что такие существуют

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

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

>сли кто-то в Ruby хочет добавить метод sum ко ВСЕМ контейнерам (колекциям), то он пишет

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

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

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

Школьнику вроде тебя это не понять, но в Реальной Жизни есть функции принимающие более одного параметра. А если их писали полные идиоты, то более шести. Статическая проверка типов устраняет целый ряд ошибок связанных с тем, что программист перепутал параметры местами. Я конечно понимаю, что школота вроде тебя любит орать "я писал решатель квадратных уравненийй! в передаче параметров нельзя ошибиться. А кто ошибается - гнать в шею", но реальная жизнь имеет малого общего с юношеским максимализмом. Ошибки типа "параметры перепутаны местами" есть. И только полный идиот будет отрицать что статическая проверка типов их не отловит.

anonymouze
()
Ответ на: комментарий от val-amart

> именованные параметры?

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

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

> И только полный идиот будет отрицать что статическая проверка типов их не отловит.

foo(int, int);

Как отловит?

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

> Школьнику вроде тебя это не понять, но в Реальной Жизни есть функции принимающие более одного параметра.

Ай, Моська! знать она сильна, Что лает на Слона!

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

>Ошибки типа "параметры перепутаны местами" есть. И только полный идиот будет отрицать что статическая проверка типов их не отловит.

С хаскелем не знаком, но в С++ вся эта статическая фагготрия помогает как мертвому припарка. В STL ошибки вида "использование невалидного итератора" отлавливаются только в дебажном режиме и в рантайме. То что после первого же push_back все сохраненные в переменных итераторы из любой секвенции кроме std::list<> становятся невалидными не может отловить ни компилятор ни зачастую визуальный контроль кода.

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

> То что после первого же push_back все сохраненные в переменных итераторы из любой секвенции кроме std::list<> становятся невалидными не может отловить ни компилятор ни зачастую визуальный контроль кода.

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

Работы на 50 строк. Но думаю, тебе будет лень -- и так можно жить.

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

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

val-amart ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

>> Зачем хеши конвертировать? Там ничего не должно измениться.

> Ты явно не понял моего вопроса. Был хэш {... person=>'Vasya Pupkin' ...}, стал хэш {... name=>'Vasya', fname=>'Pupkin' ...}, так что конвертация нужна.

Да там нечего было понимать. Напомню, что это был за вопрос

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

Я тебе ответил - проверки не вставляются. Никакой автоматической конвертации объектов по инициативе интерпретатора языка не происходит. Если же ты сам хочешь пробежаться по всем объектам определенного класса и что-то с ними сделать то пиши 

ObjectSpace.each_object(MyClass){|o| puts o} 

или

ObjectSpace.each_object(User)do |o|
   o.instance_eval do
     @first_name,@family_name = @full_name.split(/\s+/, 2)
   end
end 

_И такие вещи можно делать, не меняя класса, так как instance-переменные вообще не относятся к определению класса в языках Ruby и Python._

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

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

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

>> То что после первого же push_back все сохраненные в переменных итераторы из любой секвенции кроме std::list<> становятся невалидными не может отловить ни компилятор ни зачастую визуальный контроль кода.

>Выведи из вектора пару субклассов, у одного из них будет push_back но не будет итераторов, у другого -- только итераторы без push_back,

Предполагается конечно же приватное наследование и враппинг всего функционала вектора? Это не 50 строк. К тому же, не факт что это будет работать - там много тонкостей: даже авторы GNU STL с трудом склеивают все семантические контексты возникающие при совместном использовании разных частей С++ stdlib.

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

>> И только полный идиот будет отрицать что статическая проверка типов их не отловит.

> foo(int, int);

> Как отловит?

А что, Си++ - это верх статической типизации?

type Something is new integer;

type Something_Else is new integer;

procedure foo(a1: Something; a2: Something_Else) returns integer;

;)

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

>>Если кто-то в Ruby хочет добавить метод sum ко ВСЕМ контейнерам (колекциям), то он пишет >Это возможно и в статически типизированной Scala с помощью неявных преобразований.

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

"Most dynamic languages are dynamically typed, but not all." (c)

Scala есть в списке динамических языков на английской википедии. Это, безусловно, не объективная истина, но сослаться на что-то более объективное не могу ...

Если приводите контрпример, то используйте для надёжности С или Fortran или С++ (но этот лучше не упоминайте). Остальные языки уже претендуют на звание динамического (http://en.wikipedia.org/wiki/Dynamic_programming_language - указано порядка 70 динамических языков, и 5 нединамических, из которых один (Java) под вопросом - поэтому автору топика все таки следует признать, что что-то такое важное в динамических языка есть, раз их столько напложилось, только нужно разобраться)

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

1) В первую очередь, это изменение пространства имен (добавление/изменение/удаление классов, методов объектов и классов, переменных объектов и классов, локальных/глобальных переменных, ...).

2) Затем персонализированное расширение объектов (точнее тех логических единиц программы, которые в парадигме, соответствующей языку, являются основными - объекты (ООП), определения функций (функциональное программирование), правила вывода (логическое программирование)) (в Ruby это делается с помощью singleton класса (он же virtual class)).

3) Динамическая типизация

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

На С++ можно все. Запостулируем это - макросы, шаблоны, изменение секции кода в рантайме, встроенный в программу компилятор, С++ есть квазитьюрингполный язык (как и многие другие), в конце то концов! На С++ можно всё, но для программистов потенциальной возможности мало.

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

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

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

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

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

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

> Работающий способ изменить психологию программиста

...но работу по их перевоспитанию уже можно начинать.

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

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

Не забываем про 10 правиль Гринспуна :)

> С++ есть квазитьюрингполный язык (как и многие другие)


ЩИТО!?

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

> Я тебе ответил - проверки не вставляются. Никакой автоматической конвертации объектов по инициативе интерпретатора языка не происходит.

Тогда это не называется "лениво менять" объекты, и тебе сразу надо было не пытаться отвечать на вопрос, к твоему руби видимо не относящегомуся (если не сказать -- не надо вести пиар не по теме). Вопрос мой был к mv, он относился именно к фразе

можно в рантайме поменять определение класса, и все готовые объекты -->лениво поменяются<-- под новое определение

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

> А что, Си++ - это верх статической типизации? 
> type Something is new integer;

Гы-гы-гы. Чтобы плюсы перед Адой пасовали? (возможно, но не в таких простых вещах)

Выхлоп: 5512

#include <iostream>


#define CreateNewType(New,Old) class New \
{\
    public:\
	operator Old() {return value;}\
	explicit New (Old v): value(v) {}\
    private:\
	Old value;\
};\


CreateNewType(Int1,int);
CreateNewType(Int2,int);

int f(Int1 x, Int2 y) { return x+y*y; }

int main()
{
    Int1 i1(1);
    Int2 i2(2);
    std::cout << f(i1,i2) << f(Int1(1),Int2(2)) << i1 << i2 << '\n';
    // std::cout << f(i2,i1);	// compile time error
    // i1=i2; 			// compile time error
    return 0;
}

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

но при всем этом возникают интересные вопросы:

1. без макроса вроде бы не обойтись, т.к. нет чего-то типа _COUNTER
2. а нужен ли _COUNTER в шаблонах -- он нарушает функциональность, т.е. равенство типов S<T> и S<T> (но второй раз)
3. хотелось бы писать Int i1=1; но это нельзя
4. к п.3: хотелось бы присваивание в инициализации трактовать по-другому

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

>> А что, Си++ - это верх статической типизации?

>> type Something is new integer;

> Гы-гы-гы. Чтобы плюсы перед Адой пасовали? (возможно, но не в таких простых вещах)

Ага, полкило макрокода - и почти как в Аде. Мне лень проверять, но, IIRC, в Аде на новых типах автоматом определены арифметические операции.

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

> Ага, полкило макрокода - и почти как в Аде.

Тебе бы в магазине продавцом работать -- с каких пор 6 строк универсального макроса -- это полкило кода?

> Мне лень проверять, но, IIRC, в Аде на новых типах автоматом определены арифметические операции.

А тут автоматом определена конвертация в int, поэтому можно написать int i=i1+i2*i2 и f (если ты читал внимательно) использует свои аргументы БЕЗ приведения типов.

Т.е. для задачи "недопустить в f неправильные аргументы, но и не заставлять внутри нее писать лишнего" этого достаточно.

Насчет "склонировать полностью тип вместе со всеми операциями" -- это РОВНО приватное наследование (по модулю неприятностей с конструкторами). Почему 1) в плюсах нельзя (неполиморфно?) наследовать от int 2) в плюсах так странно поступили с конструкторами -- я не знаю. Более того, я считаю, что это надо исправить.

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

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

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

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

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

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

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

Ну и по остальным пунктам отвечу.

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

>> Вот так Лисп и обсирают, не понимая, что он из себя представляет... Зачем спорите, если предметом спора не владеете?

> Иди учись. Может быть, тебе объяснят старшие, что подобная техника в ЛИСПе - last resort.


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

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

> Ага, полкило макрокода - и почти как в Аде.

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

Однако, *в отличие от скриптовых языков*, я не считаю достоинством Ады наличие готовых конструкций над типами, если их можно пересоздать на плюсах даже через 0.5 Mloc. Тем более, что там можно самому решать, что делать, если при сложении значение выскочит из диапазона.

Еще в плюсах отсутствуют неполиморфные указатели из Ады. Это может быть очень плохо, а может и ненужно. Я не знаю.

В целом -- вопрос интересный.

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

ну вот, я сделал код на плюсах, параллельных твоему хаскелю

// output: 1 2 3 0 0 0xBLABLABLA

#include <iostream>

struct Before { // this class is defined before MaxBound
    operator int() { return 1; }
};

struct MaxBound {
    operator int () { return 2; } 
    operator Before() { return Before(); }
    template<typename T> operator T* () { return 0; }
    MaxBound() {}
};
static MaxBound MAX_BOUND;

struct After { // this class is defined after MaxBound
    operator int() { return 3; }
    After() {}
    After(MaxBound m) {} // for MaxBound only
};
static After after;

template<> MaxBound::operator After* () { return &after; }

int main()
{
    std::cout << (Before )MAX_BOUND <<' '<< (int    )MAX_BOUND <<' '<< (After  )MAX_BOUND <<' '
	      << (int*   )MAX_BOUND <<' '<< (Before*)MAX_BOUND <<' '<< (After* )MAX_BOUND <<  '\n';
    return 0;
}


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

То, что получилось -- очень хрупко (как впрочем ты и писал). Нельзя функции на типах определять через операторы преобразования.

Более прямой способ -- сделать как в яве Class<T>, но чтобы он был либо целым числом, либо адресом статической переменной.

Теперь насчет http://en.wikibooks.org/wiki/Haskell/Advanced_type_classes

Я могу щас сииильно тормозить, но по-моему у плюсов никогда с этим проблем не было. И это все проблемы хаскеля с его явно лишним выводом типов и/или лишним каррингом, нет? (хотя если пытаться юзать карринг, то может они и в плюсах всплывут?)

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

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

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

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

> Я могу щас сииильно тормозить, но по-моему у плюсов никогда с этим проблем не было. И это
> все проблемы хаскеля с его явно лишним выводом типов и/или лишним каррингом, нет? (хотя

> если пытаться юзать карринг, то может они и в плюсах всплывут?)


Проблем с выводом? У С++ другие проблемы - он выводит мало. Карринг нипричем.

При неверном указании типа итератора вершины в каком-нибудь алгоритме boost graph library генерит ошибку компиляции на 1.5 страницы, причем ошибка якобы НЕ в коде пользователя(ну ладно, он показывает откуда производится инстанцирование), а в бустовом хедере(!) (хотя код boost же нормальный, или не очень? если компилятор словил это хер знает где). Больше напоминает препроцессор.

Что за нас может сделать плюсатый компилятор? Типы аргументов/возвращаемого значения шаблонных функций _определяются программистом_ или явно, или вообще не указываются. Concepts частично решают эту задачу, но надо _самим_ лазить по исходнику и указывать, какие операции должен определять на себе полиморфный параметр. Остается только попытаться собрать нечто, получающееся на пути инстанцирования аккуратно обступая код, который в принципе не собирается. Что-то тут не так.

При явном определении получаем жуткие сигнатуры функций (так как typedef юзать в сигнатурах функций нельзя ;]) или заворачиваем всё в traits (тоже выглядит непрозрачно).

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

В примере с max_bound это не так.

> 2. Сообщить, что в шаблоне один тип функционально зависит от других никогда не проблема.

Зависимый тип можно просто _определить_ в терминах шаблонного параметра. Более слабых отношений определить нельзя.

В С++ эту задницу с зависимостями/требованиями к полиморфному параметру _полностью_ сгружают на пользователся, а в haskell - на компилятор; и таки да - ghc надо помогать(fundeps), но не делать за него всё.

Что лучше? :]

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

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

> Карринг нипричем.

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

> диагностика

1. да сейчас диагностику ошибок проще не читать. я читаю только номер строки и дальше думаю сам.

2. concepts это (я ошибаться могу) вещь крайне похожая на type classes, откуда ты высосал ее критику -- мне не ясно, при нормальном использовании -- лазить по исходнику надо ровно как в хаскеле (а если с их помощью можно исправить кривую библиотеку ее *пользователю* -- это плюс, а не минус)

> так как typedef юзать в сигнатурах функций нельзя

почему?

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

> В примере с max_bound это не так.

1. max_bound -- это вообще не функция, а мета-функция. За попытку ее реализовать как функцию надо... ну не буду писать.

2. пусть даже функция -- тогда ее сигнатура T max_bound(T) -- таки функционально зависит (id)

> Зависимый тип можно просто _определить_ в терминах шаблонного параметра. Более слабых отношений определить нельзя.

Можно сделать параметр по умолчанию. Но *интересно*, а какие могут быть более слабые отношения? (желательно пример...)

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

> В С++ эту задницу с зависимостями/требованиями к полиморфному параметру _полностью_ сгружают на пользователся, а в haskell - на компилятор

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

> Что лучше?

вместо пиара лучше расскажи про слабые зависимости.

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

s/(хотя и не все)/(хотя и не все удобно)/

т.к. мета язык (шаблонов) -- полный по тьюрингу

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

http://web.cecs.pdx.edu/~mpj/pubs/fundeps-esop2000.pdf - worth reading (всего 15 страниц)

> > Карринг нипричем.

> я таки подозреваю, что при попытке полноценно юзать карринг из-под плюсов полезут хасклелевские траблы.

Это точно про это? http://en.wikipedia.org/wiki/Currying

Из всего, что обычно надо в C++ - это всякие bind1st и друзья (но бывает и хуже :]).Так как все проверки и вывод типов происходят из точки инстанцирования (где все конкретные типы уже известны) - то не нужно решать никаких уравнений с ограничениями, а значит и проблем особых возникнуть не должно.

> > диагностика

> 1. да сейчас диагностику ошибок проще не читать. я читаю только номер строки и дальше думаю сам.

А как хорошо было бы увидеть "ваш T не является инстансом итератора<число>" а не портянку из угловых скобок. MSVC в этом смысле не такой жуткий, как g++ :[

> 2. concepts это (я ошибаться могу) вещь крайне похожая на type classes, откуда ты высосал ее критику -- мне не ясно, при нормальном использовании -- лазить по исходнику надо ровно как в хаскеле (а если с их помощью можно исправить кривую библиотеку ее *пользователю* -- это плюс, а не минус)


type classes - это шаблонные типы в теримнах C++ (template <class T> structFoo<T> {..} + операции нам ними).
concepts - это ограничения на T для операций. В haskell это обычно делается ограничением на полиморфные аргументы типа такого: (+) :: (Num a) => a -> a -> a

Когда concepts проверяются? На стадии разбора кода шаблона или в точке инстанцирования?
Почему нельзя дать программисту по рогам за то, что он вписал не все ограничения, которые использовал в коде шаблонной функции? Это же легко проверить до инстанцирования. Пусть гад напишет, что ему нужен не только random_access_iterator, но и кое-какие арифметические операции над значениями, к которым с его помощью можно добраться. А нельзя, потому что замучаешься описывать. В том же stl такие дикие требования к типам хранимых значений и распределителей памяти, что их вообще фиг чем опишешь (и соблюдешь, шутка :]).

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

В pdf выше есть прикольный и очень простой пример определения операции произведения над 2 произвольными типами и однозначного (зависящего от аргументов, но не строго вшитого(!) и не вычисляющегося из них - он пользователем может задаваться) результата умножения.

> > так как typedef юзать в сигнатурах функций нельзя

> почему?

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

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

>> В примере с max_bound это не так.

> 1. max_bound -- это вообще не функция, а мета-функция. За попытку ее реализовать как функцию надо... ну не буду писать.

:]

> 2. пусть даже функция -- тогда ее сигнатура T max_bound(T) -- таки функционально зависит (id)

FD не значит, что зависимость типа выражается в виде формулы, оно ближе к типам отношений в RDB ({1,many}-to-{1,many})
http://en.wikipedia.org/wiki/Functional_dependency
Может, по-русски оно просто звучит по-другому.

> > Зависимый тип можно просто _определить_ в терминах шаблонного параметра. Более слабых отношений определить нельзя.

> Можно сделать параметр по умолчанию. Но *интересно*, а какие могут быть более слабые отношения? (желательно пример...)

В pdf класс Mult и характер ограничений на a b и c.

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

> Учи матчасть. MS SQL: > select table tbl (id integer, name varchar(5))

create table

> declare @id int > select id from tbl into @id

select @id = id from tbl

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

> свои слова подтверждать. И оценить эффективность тех или иных языков.

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

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

Мне неинтересно.

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

> В pdf класс Mult и характер ограничений на a b и c.

Я там отнюдь не все понял. Вот пока какие отзывы:

1. Вместо многотипового max_bound нужно было привести пример empty_collection -- который должен с легкостью приводиться к типу любой коллекции.

В плюсах с этим могут быть проблемы, если написать

auto x=empty_collection;

мне хотелось бы иметь возможность так писать, причем тип х должен быть вполне конкретным Collection<T>. Но тут все вилами по воде. Вполне возможно, что auto x=empty_collection<T>; предпочтительнее.

2. Mult. В плюсах опять же мы можем написать

int mult(int, int) {...}
и одновременно
long mult(int, int) {...}

возможно, что компилятор не даст даже варнинга, пока мы не попробуем где-то реально заюзать, например f(mult(a,b))

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

3. ну и в целом пдф-ка интересная, жаль, ты не разжевал ее в удобопонятном для меня виде :-)



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

>Там алгоритм предлагается искать, а не эффективность языков сравнивать.

У разных классов языков - разные эффективные алгоритмы. Глупо сравнивать Haskell и Си++ на одном алгоритме. В том и прикол таких задач.

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