Re[77]: Динамические языки и переменные
От: Temoto  
Дата: 20.03.10 06:32
Оценка:
ВВ>Это мне напоминает пример из области, как же плохо что в неком языке (что за язык, кстати?) нет base. Вопрос был — покажи, где пользователь может запутаться в this-ах. Ты показал, где пользователь не может обратиться к родительскому скопу из-за отсутствия base.

ВВ>Я твою мысль, конечно, понимаю, но вся твоя критика — деструктивная. Т.е. альтернативной идеи попросту нет. Везде, где мне известно, this передается неявно как аргумент функции. Возможность писать this в функции, которая "не привязана" к объекту естественным образом проистекает из того, что "классов" вообще-то нет и "привязать" функцию к объекту нельзя в принципе.


ВВ>Может быть, "неявный" this это и зло, но брать язык с клонированием объектов и вкорячивать туда статический this мне кажется еще большим злом.


Да, действительно, против вложенных this как-то альтернативы и не видно.

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

ВВ>>>Вот у тебя и получается, что динамика — это вывод типов для бедных.

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

ВВ>Вывожу это из твоих слов. Не больше и не меньше. Ты уже не в первый раз говоришь, что динамика означает, что тип становится известен только в рантайме. Хорошо, все правильно. Но *кому* этот тип становится известен? Среде исполнения? Программист должен знать этот тип, когда пишет код?


Должен. Иначе он пишет код вслепую.

Когда я пишу cout "String length is " + s.length(); наверное подразумевается, что я осознаю, что s это строка, да?

ВВ>Сам попробуй ответить на этот вопрос.


ВВ>Если должен, то получается, что динамика ему никак не помогает. Он все равно работает с конкретными типами, и это просто среда исполнения такая тупая, что может типы вычислить только в рантайме. Интеллектуальная альтернатива — вывод типов.


Динамика отличается от статики *только* тем, что одно и то же имя может в разные моменты иметь значение разных типов. На практике (но не в теории!) это влечёт за собой невероятную сложность статической проверки типов. Поэтому проверка отодвигается до выполнения. Соответственно, да, во всех реализациях — это тупая среда, которая не может, например, положить число в регистр процессора (потому что вдруг там уже строка, а не число) и вместо этого, она выделяет десятки байт под "объект Число".

И да, интеллектуальная альтернатива — вывод типов. Это альтернатива, только *если* типы будут проверены до запуска. (но с динамической типизацией сделать такую проверку в программе сложнее hello world нереально, правда?) А если они не будут проверены, то и смысла в выводе типов нет.

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

Вот есть, например, pylint (для Javascript — jslint) — статический анализатор Python кода. И он да, действительно делает вывод типов. И проверяет. Он не все ошибки находит. Но какие-то находит и это помогает. Представим себе странную ситуацию, что pylint встроен в интерпретатор. Что получится? Получится динамика с выводом и проверкой типов. И если бы pylint давал гарантию, что он выводит все типы и проверяет все выражения, то можно делать страшные оптимизации.

ВВ>А если не должен, то тогда навязывать ему писать на каждом шагу аннотации для типов, бесконечные преобразования и тайп-касты это несколько неправильно. В статическом языке a + b это операция над конкретными типами данных, в динамическом — это абстрактная операция с именами, если хочешь, это мета-код, что в нек-х языках достигается с помощью, к примеру, шаблонов — возможность писать код, абстрагировавшись от типов.


ВВ>Естественно, это имеет свою цену.


Хакей, я понял. Ты путаешь динамику и полиморфизм.

Классический пример. Функция для вычисления наибольшего общего делителя на Python:

def gcd(a, b):
    while a:
        a, b = b % a, a  # % возвращает остаток от деления
    return b


В статическом языке эта функция над конкретными типами данных.
* a — тип, приводимый к Bool и тип, который подходит в качестве второго аргумента к операции `%` (допустим % определена для любых видов чисел: интегральные, рациональные, назовём такой тип INumeric).
И допустим, что для всех чисел определена операция приведения к Bool. В шарпе, кажется, это называется implicit operator (). Следовательно "приводимый к Bool" дополнительных ограничений не вводит.
Тип a — INumeric.
* b — тип, подходящий в качестве первого аргумента к операции `%`.
Тип b — INumeric.

Вот это в статическом языке. Ты называешь это над "конкретными типами"? Я нет.

ВВ>А, так ты обзываешься? Ну ОК. В следующий раз предупреждай хоть.


Но я в шутку, без обид.

ВВ>>>Я на том же шарпе уже лет восемь пишу, естественно, мне первый вариант понятнее.

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

ВВ>Речь о конкретном языке или о чем? Что такое третий язык?


Я приводил примеры трёх языков. В одном "19" + 1 даёт "191", в другом 20, в третьем ошибку типов.

ВВ>В шарпе преобразование типов, которое производит оператор + для строк ни разу проблем у меня не вызвало за весьма долгое время использования данного языка. Ибо типизация статическая, и я всегда знаю, с какими типами я работаю. В каком-то другом языке — может вызовет, может нет. Я не знаю.

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

Нет, я не агитирую делать Java.

Если я для своих типов написал +, то я знаю что этот + делает. Проблемы начинаются, когда кто-то другой написал свою реализацию `+` неявно и для моих типов тоже. В хаскеле такого не получится, раз уж ты за него взялся. А вот в питоне легко, но слава богу, так никто не делает.

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


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

ВВ>А расскажи-ка лучше, что такое в "Своем Языке" и какая у тебя самого на самом деле идея


Ну, в двух словах идея в том, что достаточно многие задачи можно представить в виде обработки потоков (то есть связанных списков). То есть это не general purpose language, и хотя на нём, конечно можно решить любую задачу, но пытаться всё подстроить под его модель будет ошибкой. Программы на этом языке состоят из декларации парсеров [потоков] и вспомогательных функций. Парсеры определяют ожидаемые данные в потоке. Есть примитивы "попытаться распарсить входящий поток S при помощи парсера P" и "прогнать данные через парсер в обратную сторону" (получится то, что можно записать в поток соответствующего типа). Задачи, которые решаются на этом языке проще, чем на других, это: фильтрация (grep) и обработка потоков (sed), сериализация/десерализация, сервера (например, но не только, сететвые) (благодаря неявному IO, фактически, для простых случаев написание сервера сводится к написанию логики).

Цельной реализации (как у тебя) пока нет, только черновики спецификации, парсера и виртуальной машины с M:N поточностью.
Re[78]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 20.03.10 11:43
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Да, действительно, против вложенных this как-то альтернативы и не видно.

T>Я сейчас понял, что, как это ни странно, представления о том, как хороший динамический язык должен помогать программисту [избегать ошибок] у меня меньше, чем о том, как это должен делать хороший статический язык.

Мне тоже начинает так казаться

T>Должен. Иначе он пишет код вслепую.


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

T>Когда я пишу cout "String length is " + s.length(); наверное подразумевается, что я осознаю, что s это строка, да?


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

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


А зачем эта проверка откладывается? Ради чего?

ВВ>>А если не должен, то тогда навязывать ему писать на каждом шагу аннотации для типов, бесконечные преобразования и тайп-касты это несколько неправильно. В статическом языке a + b это операция над конкретными типами данных, в динамическом — это абстрактная операция с именами, если хочешь, это мета-код, что в нек-х языках достигается с помощью, к примеру, шаблонов — возможность писать код, абстрагировавшись от типов.

ВВ>>Естественно, это имеет свою цену.
T>Хакей, я понял. Ты путаешь динамику и полиморфизм.

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

Попробуй развить свою идею со строгой типизацией в динамике и вспомни какой-нибудь хрестоматийный примерчик с утиной типизацией. Он все еще будет работать?

А вообще ты глючишь по-моему. Какая может быть строгая типизация в динамическом языке? Динамика означает, что типы известны только в рантайме и коде они никак не указаны. Что должен делать этот твой "строгий" типизатор? По логике вещей, если тип отличается от *ожидаемого* нужно генерировать исключение. А как среда исполнения поймет какой тип является *ожидаемым*, что на самом деле хотел программист? Мысли его прочитает?
Твой варинт строгих бинарных операций — это не есть строгая типизация, это какая-то строгая жена, которая иногда дает, а иногда дает, причем никогда неясно почему. Т.е. информации о типах в коде нет, но он будет вылетать. Следующий шаг для упрощения жизни — это попробовать ну какой-нибудь констрейнт на функцию повесить.

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

ВВ>>В шарпе преобразование типов, которое производит оператор + для строк ни разу проблем у меня не вызвало за весьма долгое время использования данного языка. Ибо типизация статическая, и я всегда знаю, с какими типами я работаю. В каком-то другом языке — может вызовет, может нет. Я не знаю.

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

А за что агитируешь? Во всех языках есть "опасные" возможности, даже если сами языки рекламируются как безопасные. Например, в C# можно:

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

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

T>Если я для своих типов написал +, то я знаю что этот + делает. Проблемы начинаются, когда кто-то другой написал свою реализацию `+` неявно и для моих типов тоже. В хаскеле такого не получится, раз уж ты за него взялся. А вот в питоне легко, но слава богу, так никто не делает.


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

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

T>В хацкеле полностью строгая типизация. Неявных приведений нет. Сам суди, это промах или нет.

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

T>А дров можно везде наломать. Ты какие-то конкретные дрова хотел обсудить или к чему эта фраза?


Мне казалось, из контекста очевидно, что речь идет о перегрузке операторов, которое в Хаскеле более гибкое и мощное, чем в шарпе. Или я что-то путаю?

T>Ну, в двух словах идея в том, что достаточно многие задачи можно представить в виде обработки потоков (то есть связанных списков). То есть это не general purpose language, и хотя на нём, конечно можно решить любую задачу, но пытаться всё подстроить под его модель будет ошибкой. Программы на этом языке состоят из декларации парсеров [потоков] и вспомогательных функций. Парсеры определяют ожидаемые данные в потоке. Есть примитивы "попытаться распарсить входящий поток S при помощи парсера P" и "прогнать данные через парсер в обратную сторону" (получится то, что можно записать в поток соответствующего типа). Задачи, которые решаются на этом языке проще, чем на других, это: фильтрация (grep) и обработка потоков (sed), сериализация/десерализация, сервера (например, но не только, сететвые) (благодаря неявному IO, фактически, для простых случаев написание сервера сводится к написанию логики).

T>Цельной реализации (как у тебя) пока нет, только черновики спецификации, парсера и виртуальной машины с M:N поточностью.

Не очень понял, речь об асинхронном IO и каком-то механизме, который позволяет описывать парсеры? Что такое парсер?
Re[79]: Динамические языки и переменные
От: Temoto  
Дата: 20.03.10 14:18
Оценка:
T>>Когда я пишу cout "String length is " + s.length(); наверное подразумевается, что я осознаю, что s это строка, да?
ВВ>Ты привел пример, где тип подразумевается. ОК. Код на динамическом языке всегда такой? И если тип *всегда* подразумевается, то почему бы не упростить себе жизнь и избежать странных ошибок в рантайме и попросту его не указывать?

А в приведённом примере тип и не указан. Хотя, на мой вкус, TypeError не странная ошибка.

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

ВВ>А зачем эта проверка откладывается? Ради чего?

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

ВВ>Я не путаю, но тут действительно есть связь.

ВВ>Смысл динамики не в том, что одна переменная может принимать разные значения. Такого эффекта можно добиться и в статическом языка. Смысл в том, что мы, повторюсь, совершаем операции над именами, а не над значениями. И только благодаря этому у нас в динамическом языке есть полиморфизм.

Хакей, опустим спор о терминах.

ВВ>Попробуй развить свою идею со строгой типизацией в динамике и вспомни какой-нибудь хрестоматийный примерчик с утиной типизацией. Он все еще будет работать?


ВВ>А вообще ты глючишь по-моему. Какая может быть строгая типизация в динамическом языке?


Вот такая.

Python:

>>> "foo" / 2
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'int'


PHP:

<? echo "foo" / 2; ?>
0


ВВ>Динамика означает, что типы известны только в рантайме и коде они никак не указаны. Что должен делать этот твой "строгий" типизатор? По логике вещей, если тип отличается от *ожидаемого* нужно генерировать исключение. А как среда исполнения поймет какой тип является *ожидаемым*, что на самом деле хотел программист? Мысли его прочитает?


Толстый троль такой толстый.
Никакого отношения ожидаемый тип к желанию программиста не имеет.

print 10.foo

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

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


В исключении написано почему.

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


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

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

T>>Нет, я не агитирую делать Java.

ВВ>А за что агитируешь? Во всех языках есть "опасные" возможности, даже если сами языки рекламируются как безопасные. Например, в C# можно:


За мир во всём мире.
И за инструменты, которые помогают делать меньше ошибок.

ВВ>Это в языке, который *рекламировался* как безопасный.


Думаю, что взрослый человек должен знать что такое реклама. Но даже если не придираться к слову реклама, то под безопасностью и управляемостью .NET всегда подразумевалось то, что у тебя не будет сегфолтов (на винде это называется access memory violation). И, если я не ошибаюсь, если в шарпе не использовать ключевое слово unsafe, то сегфолтов действительно не будет.

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

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


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

Кажется, разговор об ошибках начался с вложенных this и повсеместного null. Так вот это не то же самое, что "можно в рантайме эмитить любой код". Потому что никто каждый день не пишет unsafe перед каждой функцией и код не эмитит. А вот вложенные this будут. Очень много их будет.

T>>Если я для своих типов написал +, то я знаю что этот + делает. Проблемы начинаются, когда кто-то другой написал свою реализацию `+` неявно и для моих типов тоже. В хаскеле такого не получится, раз уж ты за него взялся. А вот в питоне легко, но слава богу, так никто не делает.


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


Зачем ты усложняешь? Допустим я один работаю над каким-то приложением. И подключил чужую библиотеку.

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

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

В хаскеле нет перегрузки операторов. Например, + работает только с числами.

T>>А дров можно везде наломать. Ты какие-то конкретные дрова хотел обсудить или к чему эта фраза?


ВВ>Мне казалось, из контекста очевидно, что речь идет о перегрузке операторов, которое в Хаскеле более гибкое и мощное, чем в шарпе. Или я что-то путаю?


Да, немножко. Попробуй написать парсер Ela на нём.

Здесь популярно расписано как.
http://jonathan.tang.name/files/scheme_in_48/tutorial/overview.html

T>>Ну, в двух словах идея в том, что достаточно многие задачи можно представить в виде обработки потоков (то есть связанных списков). То есть это не general purpose language, и хотя на нём, конечно можно решить любую задачу, но пытаться всё подстроить под его модель будет ошибкой. Программы на этом языке состоят из декларации парсеров [потоков] и вспомогательных функций. Парсеры определяют ожидаемые данные в потоке. Есть примитивы "попытаться распарсить входящий поток S при помощи парсера P" и "прогнать данные через парсер в обратную сторону" (получится то, что можно записать в поток соответствующего типа). Задачи, которые решаются на этом языке проще, чем на других, это: фильтрация (grep) и обработка потоков (sed), сериализация/десерализация, сервера (например, но не только, сететвые) (благодаря неявному IO, фактически, для простых случаев написание сервера сводится к написанию логики).

T>>Цельной реализации (как у тебя) пока нет, только черновики спецификации, парсера и виртуальной машины с M:N поточностью.

ВВ>Не очень понял, речь об асинхронном IO и каком-то механизме, который позволяет описывать парсеры? Что такое парсер?


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

Парсер это стейт-машина.. хм.. например, регексп это парсер строки. Лучше пример показать.

# модуль http
Eol := "\r\n"
RequestLine := Method URI Version? Eol
Method := "GET" | "POST" | alphanum+
... # и прочая ерунда

main = do # do значит, что все выражения в блоке надо обязательно вычислить и именно в таком порядке.
... # открываем сокет, бла-бла
request-line = HttpRequestLine << socket
print request-line.Method # в этом месте данные будут прочитаны из сокета, рантайм попытается найти там "GET" или не гет и выведет его в stdout. Если не найдёт, будет Parsing Failure™
Re[80]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 20.03.10 16:06
Оценка:
Здравствуйте, Temoto, Вы писали:

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

ВВ>>А зачем эта проверка откладывается? Ради чего?
T>Ну ты в Ela попробуй на этапе компиляции проверь типы, а потом сам расскажешь для чего она откладывается.

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

Все правильно.

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

T>Вот такая.

T>Python:
T>
>>>> "foo" / 2
T>Traceback (most recent call last):
T>  File "<console>", line 1, in <module>
T>TypeError: unsupported operand type(s) for /: 'str' and 'int'
T>


Это не строгая типизация. Строгая и динамическая типизация — это разные вещи. Это пример поведения конкретной проверки в конкретном языке. Вот и все.

Заметь, ты во всех своих примерах почему-то указываешь литералы. С чего бы? А давай такой пример приведем:

var sum = (x,y) -> x + y;

Что делает это функция? Складывает числа? Строки? На мой взгляд она совершает операцию сложения над именами x и y, которая в конкретном случае, в зависимости от значений, может быть и арифметикой, и конкатенацией строк.
В C# вот вообще невозможно написать такие чистые операции, которые абстрагируются над типами. В С++ можно только через шаблоны.

Ты предлагаешь конкретно что?

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

T>Толстый троль такой толстый.

T>Никакого отношения ожидаемый тип к желанию программиста не имеет.
T>print 10.foo

А так?

print obj.foo

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

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

T>В исключении написано почему.

И что? Еще раз — бенефит динамики какой? В том, что исключение будет в рантайме, а не компайл-тайме?

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

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

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

ВВ>>А за что агитируешь? Во всех языках есть "опасные" возможности, даже если сами языки рекламируются как безопасные. Например, в C# можно:

T>За мир во всём мире.
T>И за инструменты, которые помогают делать меньше ошибок.

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

ВВ>>Это в языке, который *рекламировался* как безопасный.

T>Думаю, что взрослый человек должен знать что такое реклама. Но даже если не придираться к слову реклама, то под безопасностью и управляемостью .NET всегда подразумевалось то, что у тебя не будет сегфолтов (на винде это называется access memory violation). И, если я не ошибаюсь, если в шарпе не использовать ключевое слово unsafe, то сегфолтов действительно не будет.

Будет и без unsafe. И даже без эмита. Я же написал — память можно реинтерпретировать без указателей, в декларативной форме. А если можно реинтерпретировать память, то значит ее можно и испортить.

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


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

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

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

В шарпе ортодоксальный ОО код будет иметь кучу неявностей и неочевидностей (как и в любом другом classed based OOP языке) просто в силу того, что так уж работает ООП.

T>>>Если я для своих типов написал +, то я знаю что этот + делает. Проблемы начинаются, когда кто-то другой написал свою реализацию `+` неявно и для моих типов тоже. В хаскеле такого не получится, раз уж ты за него взялся. А вот в питоне легко, но слава богу, так никто не делает.


Я конечно плохо понимаю Хаскель, но мне казалось, что там можно определять свои полиморфные операторы. Вроде как и доки это подтверждают. Ты точно уверен, что нельзя?

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

T>Зачем ты усложняешь? Допустим я один работаю над каким-то приложением. И подключил чужую библиотеку.

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

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

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

T>В хаскеле нет перегрузки операторов. Например, + работает только с числами.


Странно, вон в форумах перегрузки во всю обсуждают:
http://old.nabble.com/Operator-overloading-td12077838.html
Видимо, у них какой-то неправильный Хаскель.

T>>>А дров можно везде наломать. Ты какие-то конкретные дрова хотел обсудить или к чему эта фраза?

ВВ>>Мне казалось, из контекста очевидно, что речь идет о перегрузке операторов, которое в Хаскеле более гибкое и мощное, чем в шарпе. Или я что-то путаю?
T>Да, немножко. Попробуй написать парсер Ela на нём.

На Хаскеле?

T>Парсер это стейт-машина.. хм.. например, регексп это парсер строки. Лучше пример показать.


А можно пример реальной задачи, которую будет очень легко решить на таком языке? И тяжело, скажем, на каком-нибудь типичном императивном.
Re[81]: Динамические языки и переменные
От: Temoto  
Дата: 20.03.10 18:19
Оценка:
ВВ>Ты вот только скажи, исходя из твоей философии, зачем вообще связывать типы именно со значениями? Зачем это нужно? Какие преимущества дает? Ведь недостатки очевидны, как ты тут прекрасно описываешь. Какой смысл делать динамическую типизацию, а затем на каждом шагу дергать программиста за руку и заставлять аннотировать типы?
ВВ>Ты вот от этого-то ответа как-то все время уходишь.

От ответа на какой из этих 3-4 вопросов?
Во-первых, я не объявлял никакой особенной философии, поэтому если ты уточнишь что именно имеешь в виду, под моей философией, это поможет ответить на вопрос. Но ещё я попробую угадать, чтобы, возможно, сэкономить время.
Во-вторых, про типы и значения. Зачем связывать типы со значениями. Думаю, что это близко к вопросу зачем нужны типы. Вот здесь http://rsdn.ru/forum/philosophy/3664785.1.aspx
Автор: Temoto
Дата: 11.01.10
обсудили эту тему вдоль и поперёк.
"Какие преимущества это даёт" по сравнению с чем?
И в-третьих, самое главное, про динамическую типизацию и дёргать за руку. А где, собсно, я предлагал заставлять аннотировать типы? Я не помню.

T>>Вот такая.

T>>Python:
T>>
>>>>> "foo" / 2
T>>Traceback (most recent call last):
T>>  File "<console>", line 1, in <module>
T>>TypeError: unsupported operand type(s) for /: 'str' and 'int'
T>>


ВВ>Это не строгая типизация. Строгая и динамическая типизация — это разные вещи. Это пример поведения конкретной проверки в конкретном языке. Вот и все.


Охренеть.

http://en.wikipedia.org/wiki/Strongly_typed_programming_language
http://ru.wikipedia.org/wiki/Строгая_типизация
Вот, прочитай, пожалуйста, что это такое.

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

ВВ>Заметь, ты во всех своих примерах почему-то указываешь литералы. С чего бы? А давай такой пример приведем:


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

ВВ>var sum = (x,y) -> x + y;


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

ВВ>В C# вот вообще невозможно написать такие чистые операции, которые абстрагируются над типами. В С++ можно только через шаблоны.

ВВ>Ты предлагаешь конкретно что?


ВВ>Рассматривать эту операцию как корректную только если типы обоих значений полностью совпадают? А можно подробнее? Целое и число с плавающей точкой складывать можно? Или тоже ошибки кидать? А то ведь и это у нас неявное привидение, как ни крути.


Рассматривать эту операцию как корректную, если у тебя есть реализация (+) для типов x и y. Если у тебя есть реализация сложения для целого и рационального чисел, то приведение не потребуется. Или ты про внутреннюю реализацию такого сложения, типа какую инструкцию процессору давать?

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

Просто читай код, как будто ты не писал 8 лет на шарпе:

var sum = (x,y) -> x + y;

cout sum("19", 1);


И скажи мне, что ты ожидаешь "191".

T>>Толстый троль такой толстый.

T>>Никакого отношения ожидаемый тип к желанию программиста не имеет.
T>>print 10.foo

ВВ>А так?

ВВ>print obj.foo
ВВ>Что хотел программист? Не нужно выискивать нарочно абсурдные примеры кода, чтобы что-то там доказать.

Это то же самое. Никто не может знать что *хотел* программист. Но он написал obj.foo, значит вроде бы как, он хотел получить значение поля foo. Вот в строго типизированном языке ему скажут "у тебя ошибка, такого поля нет".

Кстати, поясни пожалуйста, что абсурдного в 10.foo?
В Ruby, например, это валидный код:

10.times do puts "spam" end

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

T>>В исключении написано почему.

ВВ>И что? Еще раз — бенефит динамики какой? В том, что исключение будет в рантайме, а не компайл-тайме?


Это меня спрашивает человек, который сознательно делает динамический язык?

Бенефит динамики для программиста? Иллюзия параметрического полиморфизма (то есть в функции можно пихать всё что угодно, а проверки до выполнения нет, авось пронесёт, и часто получается). Возможность на ходу менять смысл программы без специальных диспетчеров (имеется в виду, например, заменить obj.ToString на свою функцию).
Это, наверное, всё строго про динамику.

Ты чего от меня хочешь-то? Зачем тролишь?

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

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

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


Проблема — неправильное употребление типов. Которую в статически типизированном языке нашёл бы компилятор.

Я точно не говорил, что динамическая типизация не даёт ничего, кроме проблем.

ВВ>>>А за что агитируешь? Во всех языках есть "опасные" возможности, даже если сами языки рекламируются как безопасные. Например, в C# можно:

T>>За мир во всём мире.
T>>И за инструменты, которые помогают делать меньше ошибок.

ВВ>"Инструменты, которые помогают делать меньше ошибок" — это мне как раз и напоминает ту самую "реклама", о которой ты тут говоришь.

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

Ты тролишь. И мне это не нравится. Мне хотелось бы, чтоб ты сменил тон на более дружественный. Потому что, на мой взгляд, нет повода быть таким враждебным. А если есть повод, будь добр, объясни в чём дело.

Я уже говорил, что я не агитирую за Java. А ты просто ещё раз повторяешь вопрос про примитивные языки.

Я не буду отвечать в базисе сложно = ошибки, потому что я не считаю, что это неизбежно. Ошибки там, где их не проверяют, а не там, где много составных частей (суть сложно). Поэтому я агитирую за проверку ошибок. В частности, за строгую типизацию. И я не считаю, что "My age is: " + str(age) вместо "My age is: " + age это примитивно или урезаны возможности. Это даже не сложно.

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

ВВ>Э, мы видимо разную рекламу читали. Как раз "меньше ошибок из разряда говнокода" — именно так этот язык и подавался. И многие из его ограничений исторически вводились именно по этим причинам.

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

T>>>>Если я для своих типов написал +, то я знаю что этот + делает. Проблемы начинаются, когда кто-то другой написал свою реализацию `+` неявно и для моих типов тоже. В хаскеле такого не получится, раз уж ты за него взялся. А вот в питоне легко, но слава богу, так никто не делает.


ВВ>Я конечно плохо понимаю Хаскель, но мне казалось, что там можно определять свои полиморфные операторы. Вроде как и доки это подтверждают. Ты точно уверен, что нельзя?


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

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

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

T>>Зачем ты усложняешь? Допустим я один работаю над каким-то приложением. И подключил чужую библиотеку.
ВВ>Я не усложняю. Я описывают типичную ситуацию. Ты же видимо говоришь о языке, изначально расчитанном на то, что на нем будет писать только один человек

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

T>>>>В хацкеле полностью строгая типизация. Неявных приведений нет. Сам суди, это промах или нет.

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

T>>В хаскеле нет перегрузки операторов. Например, + работает только с числами.


ВВ>Странно, вон в форумах перегрузки во всю обсуждают:

ВВ>http://old.nabble.com/Operator-overloading-td12077838.html
ВВ>Видимо, у них какой-то неправильный Хаскель.

Я же говорю, троль. Ещё и ссылками кидаешься. Ты просто не вник, что там написано.
Убрали стандартный оператор ^ из скопа, объявили совсем другую функцию, с совсем другой сигнатурой, которая делает совсем другое. Предыдущей ^ теперь нет. По-моему, это не перегрузка.

Либо опять придираешься к словам. Был ^ который работает только с числами. Стал ^ который работает только со списками. Перегрузки всё равно нет, как ни крути.

T>>Да, немножко. Попробуй написать парсер Ela на нём.

ВВ>На Хаскеле?

Да, это очень подходящий язык для всяких парсеров, трансляторов, шаблонизаторов и прочих вычислений.

T>>Парсер это стейт-машина.. хм.. например, регексп это парсер строки. Лучше пример показать.

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

Да, конечно. Давай реальную задачу. Про тяжело "на каком-нибудь типичном императивном" ничего не обещаю.
Re[82]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 20.03.10 22:52
Оценка:
Здравствуйте, Temoto, Вы писали:

T>От ответа на какой из этих 3-4 вопросов?

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

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

T>Во-вторых, про типы и значения. Зачем связывать типы со значениями. Думаю, что это близко к вопросу зачем нужны типы. Вот здесь http://rsdn.ru/forum/philosophy/3664785.1.aspx
Автор: Temoto
Дата: 11.01.10
обсудили эту тему вдоль и поперёк.

T> "Какие преимущества это даёт" по сравнению с чем?
T>И в-третьих, самое главное, про динамическую типизацию и дёргать за руку. А где, собсно, я предлагал заставлять аннотировать типы? Я не помню.

Ну вот твои "My age is: " + str(age) это как и есть такая аннотация.

T>>>Вот такая.

T>>>Python:
T>>>
>>>>>> "foo" / 2
T>>>Traceback (most recent call last):
T>>>  File "<console>", line 1, in <module>
T>>>TypeError: unsupported operand type(s) for /: 'str' and 'int'
T>>>


ВВ>>Это не строгая типизация. Строгая и динамическая типизация — это разные вещи. Это пример поведения конкретной проверки в конкретном языке. Вот и все.


T>Охренеть.


T>http://en.wikipedia.org/wiki/Strongly_typed_programming_language

T>http://ru.wikipedia.org/wiki/Строгая_типизация
T>Вот, прочитай, пожалуйста, что это такое.
T>Или спроси у людей, чьё мнение тебе авторитетно. Или ещё как-нибудь просветись. Но, пожалуйста, не придумывай своих смыслов выражению "строгая типизация". Я это выражение люблю, мне оно очень дорого.

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

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

Есть статическая типизация, есть динамическая — прямо антонимы. Понятие "строгая" предполагает, что у нас, видимо, много проверок типов. Динамика предполагает, что тип у нас связан не с переменной, а с ее значением, и любые проверки можно производить только в момент "применения" значения. "Строгая" типизация в данном случае, видимо, означает, что мы будет разрешать только операции с одними и теми же типами. Вроде все логично. А если подумать?

В языке "с типами" можно описать такую функцию:

ISummable Foo(ISummable x, ISummable y) {
return x + y;
}

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

В динамическом мы напишем такую функцию:

function Foo(x, y) {
return x + y;
}

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

Причем в динамическом языке нету возможности выделить абстракцию ISummable потому что ее попросту некуда выделять. У нас нет *типов* у переменных как класс.
Ты же предлагаешь следующее под названием "строгая типизация":

function Foo1(x, y) {
return int(x) + int(y);
}

function Foo2(x, y) {
return real(x) + real(y);
}

function Foo3(x, y) {
return string(x) + string(y);
}

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

T>
T>var sum = (x,y) -> x + y;
T>cout sum("19", 1);
T>

T>И скажи мне, что ты ожидаешь "191".

cout sum(int("19"), 1); ?

Я ожидаю то, что язык программирования будет позволять мне делать то, что *я* ожидаю и предоставлять достаточные средства для этого, вот собственно и все. Догадываться о том, хочу ли в действительности складывать строку с числом или нет — неблагодарное занятия.
Был, кстати, такой язык, который любил обо всем догадываться. Назывался Visual Basic.

T>Это то же самое. Никто не может знать что *хотел* программист. Но он написал obj.foo, значит вроде бы как, он хотел получить значение поля foo. Вот в строго типизированном языке ему скажут "у тебя ошибка, такого поля нет".

T>Кстати, поясни пожалуйста, что абсурдного в 10.foo?

10.foo нет ничего абсурдного. Как и в 10.ToString() или чем угодно — обычный код для ОО языка. А вот в качестве примера, когда обсуждается должен ли программист на динамике знать все про типы, это выглядит... неспортивно как-то. Очевидно, что если я пишу x = 10, я знаю, какой у меня тип. Ну и что с того? Это аргументация на уровне детского сада.

ВВ>>И что? Еще раз — бенефит динамики какой? В том, что исключение будет в рантайме, а не компайл-тайме?

T>Это меня спрашивает человек, который сознательно делает динамический язык?

Я тебя спрашивал, считая, что у тебя есть собственное мнение. Но видимо его нет. Тогда извини, вопрос снимается.

T>Бенефит динамики для программиста? Иллюзия параметрического полиморфизма (то есть в функции можно пихать всё что угодно, а проверки до выполнения нет, авось пронесёт, и часто получается). Возможность на ходу менять смысл программы без специальных диспетчеров (имеется в виду, например, заменить obj.ToString на свою функцию).

T>Это, наверное, всё строго про динамику.

Это все про расплывчатое понятие под названием "динамический язык" (без всякой связи с типизацией при этом), которое в современном мире практически ничего не значит. Хотя бы потому что под описанные тобой признаки подходит тот же C#.

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

T>Проблема — неправильное употребление типов. Которую в статически типизированном языке нашёл бы компилятор.
T>Я точно не говорил, что динамическая типизация не даёт ничего, кроме проблем.

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

ВВ>>"Инструменты, которые помогают делать меньше ошибок" — это мне как раз и напоминает ту самую "реклама", о которой ты тут говоришь.

ВВ>>Инструмент, который помогает сделать меньше всего ошибок — это молоток. С одной единственной функцией — забивать гвозди. Чем сложнее инструмент, чем он мощнее — тем больше возможностей сделать ошибку.
ВВ>>И это неизбежно.
ВВ>>Поэтому повторюсь — за что ты агитируешь? За примитивные и урезанные в возможностях языки?
T>Ты тролишь. И мне это не нравится. Мне хотелось бы, чтоб ты сменил тон на более дружественный. Потому что, на мой взгляд, нет повода быть таким враждебным. А если есть повод, будь добр, объясни в чём дело.

"Инструменты, которые помогают делать меньше ошибок" — это отличный повод. Лозунг, после которого не было сказано ни-че-го. Т.е. вообще. Ты не агитируешь за Джава. Да, я понял. Это вся сообщенная тобой информация.

T>Я уже говорил, что я не агитирую за Java. А ты просто ещё раз повторяешь вопрос про примитивные языки.

T>Я не буду отвечать в базисе сложно = ошибки, потому что я не считаю, что это неизбежно. Ошибки там, где их не проверяют, а не там, где много составных частей (суть сложно). Поэтому я агитирую за проверку ошибок. В частности, за строгую типизацию. И я не считаю, что "My age is: " + str(age) вместо "My age is: " + age это примитивно или урезаны возможности. Это даже не сложно.

Потому что ты просто не думал, к чему приведет "My age is: " + str(age) в языке с динамической типизацией. Или прочитал какого-то кретина из википедии.

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

ВВ>>Э, мы видимо разную рекламу читали. Как раз "меньше ошибок из разряда говнокода" — именно так этот язык и подавался. И многие из его ограничений исторически вводились именно по этим причинам.
T>Хакей, мы читали разную рекламу. Ты меня убедил, что на самом деле шарп не такой безопасный, как его рекламировали. Не то, чтоб меня это интересовало, но теперь буду знать, спасибо за ликбез.

Речь была не о шарпе вообще-то. Ну "хакей" как ты говоришь.

ВВ>>Я конечно плохо понимаю Хаскель, но мне казалось, что там можно определять свои полиморфные операторы. Вроде как и доки это подтверждают. Ты точно уверен, что нельзя?

T>Определить свои операторы (что равносильно определению своих функций) конечно, можно.
T>Я немножко другое сказал. Нельзя написать реализацию так, что она неявно затронет и мои типы тоже.

Оле, я тебе задал конкретный вопрос. Как к специалисту (по кр. мере по сравнению со мной) в Хаскеле. Без всяких подколок.
Вопрос:
В Хаскеле есть полиморфные операторы?
Варианты ответа:
Да/Нет/В Википедии не написано

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

T>>>Зачем ты усложняешь? Допустим я один работаю над каким-то приложением. И подключил чужую библиотеку.
ВВ>>Я не усложняю. Я описывают типичную ситуацию. Ты же видимо говоришь о языке, изначально расчитанном на то, что на нем будет писать только один человек
T>Я понимаю, что мы по-разному мыслим, да... что у нас разный опыт. Но должно, наверное, быть какое-то уважение к собеседнику, хер знает, как-то, попытаться понять, наверное, можно что тебе говорят, а? Может быть, я не просто так написал "допустим". Как насчёт перестать цепляться к словам и поговорить, как взрослые и способные к абстрактному мышлению люди?

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

К чем было сказано это "допустим"? Нет, не допустим. Языков и концепций рассчитанных на то, что весь код пишет один человек просто нет. И обсуждать тут тоже нечего.

T>Я же говорю, троль. Ещё и ссылками кидаешься. Ты просто не вник, что там написано.

T>Убрали стандартный оператор ^ из скопа, объявили совсем другую функцию, с совсем другой сигнатурой, которая делает совсем другое. Предыдущей ^ теперь нет. По-моему, это не перегрузка.
T>Либо опять придираешься к словам. Был ^ который работает только с числами. Стал ^ который работает только со списками. Перегрузки всё равно нет, как ни крути.

Да, интересно, а заодно там показано как определить ^ для любых типов.

T>>>Парсер это стейт-машина.. хм.. например, регексп это парсер строки. Лучше пример показать.

ВВ>>А можно пример реальной задачи, которую будет очень легко решить на таком языке? И тяжело, скажем, на каком-нибудь типичном императивном.
T>Да, конечно. Давай реальную задачу. Про тяжело "на каком-нибудь типичном императивном" ничего не обещаю.

Вообще-то я хотел услышать пример от тебя, так как до сих пор смутно представляю себе описанную концепцию. Неужели ты не думал о какой-либо прикладной задаче?
Re[83]: Динамические языки и переменные
От: Temoto  
Дата: 21.03.10 01:37
Оценка:
T>>Во-вторых, про типы и значения. Зачем связывать типы со значениями. Думаю, что это близко к вопросу зачем нужны типы. Вот здесь http://rsdn.ru/forum/philosophy/3664785.1.aspx
Автор: Temoto
Дата: 11.01.10
обсудили эту тему вдоль и поперёк.

T>> "Какие преимущества это даёт" по сравнению с чем?
T>>И в-третьих, самое главное, про динамическую типизацию и дёргать за руку. А где, собсно, я предлагал заставлять аннотировать типы? Я не помню.

ВВ>Ну вот твои "My age is: " + str(age) это как и есть такая аннотация.


Ну потому что она там нужна, чтобы убрать неоднозначность "19" + 1. Это контроль, защита от ошибок. Это помощь.
В "My name is " + name аннотация не нужна. Так что нет такого общего "заставлять аннотировать типы".

ВВ>Причем в динамическом языке нету возможности выделить абстракцию ISummable потому что ее попросту некуда выделять. У нас нет *типов* у переменных как класс.


В питоне есть isinstance(obj, Class) == True/False.
В жаваскрипте есть typeof.

ВВ>Ты же предлагаешь следующее под названием "строгая типизация":


ВВ>function Foo1(x, y) {

ВВ> return int(x) + int(y);
ВВ>}

Значит ты просто не понял меня.

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

Во-вторых, нет. Я уже говорил что я предлагаю под названием строгая типизация. Два примера. "19" + 1 в питоне даёт ошибку типов, в пхп даёт 20. Вот в Python/Ruby — строгая(сильная) типизация, а в PHP/Javascript — слабая. Более того, я точно помню, что где-то выше уже писал эту фразу. Не нужно после этого говорить, как будто я предлагаю Си (отсутствие полиморфизма) под названием строгая типизация.

T>>
T>>var sum = (x,y) -> x + y;
T>>cout sum("19", 1);
T>>

T>>И скажи мне, что ты ожидаешь "191".

ВВ>cout sum(int("19"), 1); ?


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


То есть ты только что сказал, что *явное* приведение типов лучше, чем неявное?
Или я не уловил разницу между "неявно привёл типы" и "догадался"?

И всё-таки чёткого ответа не было. Что ты ожидаешь от cout sum("19", 1); ?

T>>Я не буду отвечать в базисе сложно = ошибки, потому что я не считаю, что это неизбежно. Ошибки там, где их не проверяют, а не там, где много составных частей (суть сложно). Поэтому я агитирую за проверку ошибок. В частности, за строгую типизацию. И я не считаю, что "My age is: " + str(age) вместо "My age is: " + age это примитивно или урезаны возможности. Это даже не сложно.

ВВ>Потому что ты просто не думал, к чему приведет "My age is: " + str(age) в языке с динамической типизацией. Или прочитал какого-то кретина из википедии.

А к чему это приведёт?

ВВ>>>Я конечно плохо понимаю Хаскель, но мне казалось, что там можно определять свои полиморфные операторы. Вроде как и доки это подтверждают. Ты точно уверен, что нельзя?

T>>Определить свои операторы (что равносильно определению своих функций) конечно, можно.
T>>Я немножко другое сказал. Нельзя написать реализацию так, что она неявно затронет и мои типы тоже.

ВВ>Оле, я тебе задал конкретный вопрос. Как к специалисту (по кр. мере по сравнению со мной) в Хаскеле. Без всяких подколок.

ВВ>Вопрос:
ВВ>В Хаскеле есть полиморфные операторы?
ВВ>Варианты ответа:
ВВ>Да/Нет/В Википедии не написано

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

"В Википедии не написано" это называется без всяких подколок?

T>>>>Зачем ты усложняешь? Допустим я один работаю над каким-то приложением. И подключил чужую библиотеку.

ВВ>>>Я не усложняю. Я описывают типичную ситуацию. Ты же видимо говоришь о языке, изначально расчитанном на то, что на нем будет писать только один человек
ВВ>меня несколько удивило, что ты свою очередь считаешь ситуацию, когда над проектом работает больше одного человека "излишним усложнением".

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

ВВ>Да, интересно, а заодно там показано как определить ^ для любых типов.


Нет, ты опять не вник. Там написано

By the way, there's nothing special about Strings here: if you made the type of ^
(^) :: a -> [a]] -> [a]]
it would work on lists of any type, including String.


List of any type (причем гомогенный список) это совсем не "для любых типов".

T>>>>Парсер это стейт-машина.. хм.. например, регексп это парсер строки. Лучше пример показать.

ВВ>>>А можно пример реальной задачи, которую будет очень легко решить на таком языке? И тяжело, скажем, на каком-нибудь типичном императивном.
T>>Да, конечно. Давай реальную задачу. Про тяжело "на каком-нибудь типичном императивном" ничего не обещаю.

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


Не, так чтоб действительно большая задача, чтоб какую-то реальную проблему решить, о такой не думал. Думал о HTTP парсере, но это не полноценная задача, а библиотека скореее. Так чтоб отдельные программы я придумывал только маленькие, типа grep, echo сервер. Больше интересовался компиляцией и рантаймом.


## сюда сложил весь мусор, спор о споре, не о программировании

ВВ>Авторитетный источник — это по твоим меркам, видимо, википедия? Причем статьи, что на русском, что на английском, с содержанием вида "это может быть то-то, но иногда понимается и это, а иногда и вовсе не это". Ты сам-то их целиком прочитал? Впрочем, это вполне объясняет, отчего у тебя такая каша в голове.


Хорошо, википедия тебе не нравится. Там были другие слова. Пожалуйста, читай всё что я пишу. Потому что иначе какой смысл общаться, если половину твоих слов игнорируют.
T>>Или спроси у людей, чьё мнение тебе авторитетно. Или ещё как-нибудь просветись. Но, пожалуйста, не придумывай своих смыслов выражению "строгая типизация".


ВВ>Есть статическая типизация, есть динамическая — прямо антонимы. Понятие "строгая" предполагает, что у нас, видимо, много проверок типов. Динамика предполагает, что тип у нас связан не с переменной, а с ее значением, и любые проверки можно производить только в момент "применения" значения. "Строгая" типизация в данном случае, видимо, означает, что мы будет разрешать только операции с одними и теми же типами. Вроде все логично.


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

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


ВВ>"Инструменты, которые помогают делать меньше ошибок" — это отличный повод. Лозунг, после которого не было сказано ни-че-го. Т.е. вообще. Ты не агитируешь за Джава. Да, я понял. Это вся сообщенная тобой информация.

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


ВВ>>>И что? Еще раз — бенефит динамики какой? В том, что исключение будет в рантайме, а не компайл-тайме?

T>>Это меня спрашивает человек, который сознательно делает динамический язык?
ВВ>Я тебя спрашивал, считая, что у тебя есть собственное мнение. Но видимо его нет. Тогда извини, вопрос снимается.

Послушай, пол-дюжины постов назад была нормальная беседа. Потом, видимо, я тебя чем-то задел. То ли тем, что в пхп, как в шарпе (чесслово, я не помнил этого сходства) куча неявных приведений и ты их хочешь внести в Ela, то ли ещё че-то, то ли просто день был плохой, но если ты перечитаешь, то явно видно агрессию и тролльство.
Предлагаю продолжить разговор в таком же нормальном, спокойном тоне, без подколов про собственное мнение и пр. как с самого начала или просто закрыть те темы, на которые спокойного общения не получается. На данный момент, очевидно, не получается про строгость и динамику из-за разногласия в терминах. Лучше уж сэкономить время и agree on disagree, чем подкалывать и обижать друг друга.
Re[84]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 21.03.10 02:50
Оценка:
Здравствуйте, Temoto, Вы писали:

ВВ>>Причем в динамическом языке нету возможности выделить абстракцию ISummable потому что ее попросту некуда выделять. У нас нет *типов* у переменных как класс.

T>В питоне есть isinstance(obj, Class) == True/False.
T>В жаваскрипте есть typeof.

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

ВВ>>Ты же предлагаешь следующее под названием "строгая типизация":


ВВ>>function Foo1(x, y) {

ВВ>> return int(x) + int(y);
ВВ>>}

T>Значит ты просто не понял меня.


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


T>Во-вторых, нет. Я уже говорил что я предлагаю под названием строгая типизация. Два примера. "19" + 1 в питоне даёт ошибку типов, в пхп даёт 20. Вот в Python/Ruby — строгая(сильная) типизация, а в PHP/Javascript — слабая. Более того, я точно помню, что где-то выше уже писал эту фразу. Не нужно после этого говорить, как будто я предлагаю Си (отсутствие полиморфизма) под названием строгая типизация.


Зачем сравнивать Ruby (язык с class based ООП) и JavaScript? То, что в Руби строки не складываются с числами означает, что таково поведение оператора "+", определенного для конкретных классов. На мой взгляд это вообще мало что говорит о типизации, скорее о поведении конкретного оператора, но дело не в этом.
Ты понимаешь, в Руби есть такие понятия как классы, операторы. Их можно определять. В JavaScript-е этого нет. Если все операции в ДжаваСкрипте будут такими же строгими, как в Руби, то в результате в нем просто напросто не будет полиморфных операций.
Class based OOP в языке с динамической типизацией, на мой взгляд, это маразм, но это уже другая тема.
Надо понимать, что ДжаваСкрипт — он такой, не потому что его сделали злодеи. Эти решения проистекают прямым образом из концепции языка. И это совсем не PHP-синдром.
И опять-таки какое это отношение имеет к типизации, строгой либо слабой?

function Sum(x, y) {
  if (typeof(x) != "number")
     throw ...;
  if (typeof(y) != "number")
     throw ...;

  return x + y;
}


Теперь ДжаваСкрипт стал более "строго-типизированный"?
А "плюсик" в Руби находится где-то на правах этой функции.

Поэтому действительно объясни мне, что такое "строгая типизация" и в чем ты сходишься с теми источниками, которые читаешь? Как строгая типизация сочетается с утиной типизацией, например? Утиная типизация не противоречит строгой?

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

Вообще "динамический язык", "строгая типизация" и проч. это настолько ватные термины, что записывать их в число любимых я бы точно не стал. И да, использование термина "строгая типизация" в отношении динамики мне кажется несколько странным. Ибо как-то не очень вяжется в моем представлении с тем же duck typing.

T>И всё-таки чёткого ответа не было. Что ты ожидаешь от cout sum("19", 1); ?


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

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


Словно "оператор" меня интересует мало. Да, в Хаскеле есть то, что я бы скорее назвал "операторами", но называй как хочешь, выбирать тебе.
Просто в разговоре про поведение "+" речь как раз и идет о полиморфном операторе — не больше и не меньше. И дело же не в том, что там в конкретном языке можно строки с целыми складывать. Есть оператор, с полиморфным поведением. Поведение может отличаться в разных языках. Полиморфное означает, что он работает с разными значениями, а следовательно результат будет разный в зависимости от типов этих значений. Все просто. Как в ДжаваСкрипте.

T>Усложнение не в том, что много людей работают над одним проектом. Усложнение в том, что называть моими типами в таком случае. Поэтому я предложил рассмотреть более чистый, абстрактный случай, просто для того, чтобы было чётко ясно что я подразумеваю под термином "мои типы". И меня удивило, что ты отказался рассмотреть такой случай, кстати. Я понимаю, что другие люди в проекте слегка размывают понятие "мои типы". Но речь-то шла о неявных приведениях типов из этого проекта, кодом из внешней библиотеки. То есть речь шла о том, что работает одинаково при любом количестве людей в проекте. Последствия имеет разные, да. Но механика одна и та же. Именно её я и предлагал рассмотреть.


Я еще раз говорю, мне непонятно что такое "мои типы". Как ты их отличаешь? Тип, описанный в библиотеке Foo — не твой? А если этот тип писал ты? Или я?
Я так полагаю, что ты хочешь высказать некую концепцию, согласно которой операторы можно определять только как часть логики написанных тобой типов, причем "оперировать" они могут только к экземплярами того же самого типа.
Это, кстати, умозрительная концепция или есть языки, в которых так? Потому что на мой взгляд такая перезгрузка достаточно бесполезна. Зачастую основной смысл перегрузки операторов это как раз научить твой тип складываться со строкой. Или с числом. Whatever.

У тебя вообще какое-то странное отношение именно к операторам. Почему оператор должен работать только с "твоими типами", а обычные функции — нет? В чем их сущностное различие? По-моему отличий нет в принципе. Во многих языках — операторы есть сахар к функциям. И непонятно тогда, почему их ущемлять в правах-то.

T>List of any type (причем гомогенный список) это совсем не "для любых типов".


Т.е. нельзя определить ^ для, скажем, любого алгебраического типа? Я не очень понимаю, честно. Для связанного списка (который есть частный случай) — можно. А для связанного списка и еще какого-нибудь — уже нельзя?

T>## сюда сложил весь мусор, спор о споре, не о программировании


ВВ>>Авторитетный источник — это по твоим меркам, видимо, википедия? Причем статьи, что на русском, что на английском, с содержанием вида "это может быть то-то, но иногда понимается и это, а иногда и вовсе не это". Ты сам-то их целиком прочитал? Впрочем, это вполне объясняет, отчего у тебя такая каша в голове.


T>Хорошо, википедия тебе не нравится. Там были другие слова. Пожалуйста, читай всё что я пишу. Потому что иначе какой смысл общаться, если половину твоих слов игнорируют.

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

Я вообще не вижу смысла в этом выражении. Ты его, кстати, не добавил. Как и википедия. Все сводится к рассуждениям о каких-то частностях, из которых можно сделать вывод, что, скажем, C# слаботипизированный язык, а Руби — строготипизированный. Да впрочем я уже писал об этом выше.

T>У меня другое понимание термина строгая типизация. И я очень рад, что какой бы ресурс в интернете я ни открыл, везде люди имеют в виду то же самое (это, кстати, повод тебе задуматься). Я рад, что если мы с ними начнём говорить, то сразу на одном языке, они меня поймут.


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

ВВ>>>>И что? Еще раз — бенефит динамики какой? В том, что исключение будет в рантайме, а не компайл-тайме?

T>>>Это меня спрашивает человек, который сознательно делает динамический язык?
ВВ>>Я тебя спрашивал, считая, что у тебя есть собственное мнение. Но видимо его нет. Тогда извини, вопрос снимается.
T> Послушай, пол-дюжины постов назад была нормальная беседа. Потом, видимо, я тебя чем-то задел. То ли тем, что в пхп, как в шарпе (чесслово, я не помнил этого сходства) куча неявных приведений и ты их хочешь внести в Ela, то ли ещё че-то, то ли просто день был плохой, но если ты перечитаешь, то явно видно агрессию и тролльство.
T>Предлагаю продолжить разговор в таком же нормальном, спокойном тоне, без подколов про собственное мнение и пр. как с самого начала или просто закрыть те темы, на которые спокойного общения не получается. На данный момент, очевидно, не получается про строгость и динамику из-за разногласия в терминах. Лучше уж сэкономить время и agree on disagree, чем подкалывать и обижать друг друга.

Вообще-то вопрос про бенефит динамики был вполне честный. Что тебя в нем смутило? Слишком жестко задан? Ну уж извините, привыкли. А ты вот, видимо, привык всех обзывать троллями. Ну что ж, все люди неидеальны
А так если ты расскажешь свое понимание, отличное от моего, это будет действительно интересно. Уж куда интереснее спора о терминах.
Re[85]: Динамические языки и переменные
От: FR  
Дата: 21.03.10 05:54
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


ВВ>Вообще "динамический язык", "строгая типизация" и проч. это настолько ватные термины, что записывать их в число любимых я бы точно не стал. И да, использование термина "строгая типизация" в отношении динамики мне кажется несколько странным. Ибо как-то не очень вяжется в моем представлении с тем же duck typing.


Утиная типизация вполне совместима с жесткой статической, например у OCaml'а типизация такая суровая что даже операторы разные для целых и вещественных чисел, но при этом объекты используют утиную типизацию, то есть функциям работающим с объектами абсолютно наплевать на тип объектов, главное чтобы эти объекты поддерживали методы с нужной сигнатурой используемые в данной функции. Например такая let f o = o#put;; функция (# это аналог точки, то есть вызов метода) имеет тип value f : < put : 'a; .. > -> 'a = <fun> то есть является полиморфной, принимающей любой объект имеющий метод с нужной сигнатурой:

class test = 
    object
        val mutable x = 123;
        method put = Printf.printf  "Test1 x = %d\n" x;
    end;;

class test2 = 
    object        
        method put = Printf.printf  "Test2\n";
    end;;


let f o = o#put;;

f (new test);;
f (new test2);;
Re[86]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 21.03.10 09:56
Оценка:
Здравствуйте, FR, Вы писали:

А если честно, то что там на самом деле происходит под капотом? Я не знаком с оригинальным OCaml, но вот в F# аналогичный трюк вроде бы как возможен, но только для методов помеченных как inline и по факту означает, что утиной типизации на самом деле нет и компилятор просто выведет тип объекта в каждом случае вызова метода и подставит сгенерированный IL по месту вызова. Т.е. это даже скорее разновидность type inference такая.
А в OCaml не так? Нет никаких особых ограничений для таких сценариев?
Re[86]: Динамические языки и переменные
От: Temoto  
Дата: 21.03.10 10:00
Оценка:
ВВ>>Вообще "динамический язык", "строгая типизация" и проч. это настолько ватные термины, что записывать их в число любимых я бы точно не стал. И да, использование термина "строгая типизация" в отношении динамики мне кажется несколько странным. Ибо как-то не очень вяжется в моем представлении с тем же duck typing.

FR>Утиная типизация вполне совместима с жесткой статической, например у OCaml'а типизация такая суровая что даже операторы разные для целых и вещественных чисел, но при этом объекты используют утиную типизацию, то есть функциям работающим с объектами абсолютно наплевать на тип объектов, главное чтобы эти объекты поддерживали методы с нужной сигнатурой используемые в данной функции. Например такая let f o = o#put;; функция (# это аналог точки, то есть вызов метода) имеет тип value f : < put : 'a; .. > -> 'a = <fun> то есть является полиморфной, принимающей любой объект имеющий метод с нужной сигнатурой:


О это ж 1 в 1 как в Go.
Re[86]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 21.03.10 10:04
Оценка:
Здравствуйте, FR, Вы писали:

Гм, если внимательно посмотреть на твой пример , то становится видно, что OCaml по сути *выводит* интерфейс для test/test2

f : < put : 'a; .. >

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

А вообще я бы не вмешивал к этому вопросу языки группы ML, а то это может означать, что термин "утиная типизация" мы тоже потеряем
Re[87]: Динамические языки и переменные
От: FR  
Дата: 21.03.10 10:43
Оценка: 7 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А если честно, то что там на самом деле происходит под капотом? Я не знаком с оригинальным OCaml, но вот в F# аналогичный трюк вроде бы как возможен, но только для методов помеченных как inline и по факту означает, что утиной типизации на самом деле нет и компилятор просто выведет тип объекта в каждом случае вызова метода и подставит сгенерированный IL по месту вызова. Т.е. это даже скорее разновидность type inference такая.

ВВ>А в OCaml не так? Нет никаких особых ограничений для таких сценариев?

В OCaml никаких ограничений нет, как под капотом описано тут http://lj.rossia.org/community/programming/920.html
Re[87]: Динамические языки и переменные
От: FR  
Дата: 21.03.10 10:48
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Гм, если внимательно посмотреть на твой пример , то становится видно, что OCaml по сути *выводит* интерфейс для test/test2


ВВ>f : < put : 'a; .. >


ВВ>Могу предположить, что это перестанет работать, если тип неизвестен в компайл-тайме, так?


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

ВВ>А вообще я бы не вмешивал к этому вопросу языки группы ML, а то это может означать, что термин "утиная типизация" мы тоже потеряем


Re[85]: Динамические языки и переменные
От: Temoto  
Дата: 21.03.10 13:36
Оценка:
ВВ>Ты понимаешь, в Руби есть такие понятия как классы, операторы. Их можно определять. В JavaScript-е этого нет. Если все операции в ДжаваСкрипте будут такими же строгими, как в Руби, то в результате в нем просто напросто не будет полиморфных операций.

Я так не думаю. А на чём основывается твоя идея? Давай попробуем представить Javascript без неявных приведений. Почему это автоматически означает потерю полиморфизма?

ВВ>
ВВ>function Sum(x, y) {
ВВ>  if (typeof(x) != "number")
ВВ>     throw ...;
ВВ>  if (typeof(y) != "number")
ВВ>     throw ...;

ВВ>  return x + y;
ВВ>}
ВВ>


ВВ>Теперь ДжаваСкрипт стал более "строго-типизированный"?


Весь жаваскрипт, конечно не стал. А вот Sum — да, строготипизированная функция. Правда, конкретно в этой реализации потеряны утки. (ниже напишу с утками)

ВВ>А "плюсик" в Руби находится где-то на правах этой функции.


ВВ>Поэтому действительно объясни мне, что такое "строгая типизация" и в чем ты сходишься с теми источниками, которые читаешь? Как строгая типизация сочетается с утиной типизацией, например? Утиная типизация не противоречит строгой?


function add_7(x) { return x + 7; } // это очень важный пример, потому что строгая типизация относится к функциям с любым количеством аргументов, включая 0. Например, функция array.length всегда возвращает строго целое число.

Проверка совместимости типов. В упрощённом случае, когда язык состоит из типов Number, String и Boolean, строгой типизацией будет проверка на *совпадение* type(x) == Number.
Но в реальных языках есть, как минимум, разновидности Number. В таком случае строгая типизация это проверка, что переданный тип *совместим* с ожидаемым. Например, наследник, если там дерево типов или специальная проверка, например type(x) in (Integer, Float) // но не Double.
Совместимость эта у каждой функции своя. Например, для сложения целые числа совместимы с дробными. Но функция повторяющая строку N раз требует именно целое число.

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

Теперь как это сочетается с утками. Нормально сочетается, противоречия нет.

Вернёмся к Sum. Чтобы ввести утиную типизацию, значениям нужен какой-то механизм, чтобы обозначить поддержку операций. Для операторов, например, в питоне это делается через методы __add__, __mul__ и т.п. x + y это на самом деле x.__add__(y). Для остальных методов (то есть кроме операторов), ну собсно наличие метода у объекта уже и значит, что он его поддерживает.
В жаваскрипте и любом динамическом языке, где "всё — объект" можно сделать то же самое. Тут не нужны классы.
Соответственно в строгой типизации "foo".__add__(7) скажет, что он работает только со строками. А 7.__add__("foo"), скажет, что он работает только с целыми, дробными, и пр. но только с числами. Вот так, на мой взгляд, без проблем утки сочетаются со строгой типизацией.

Тут, правда есть ещё такой момент. А вот допустим я написал какой-то новый тип и *явно* хочу сказать, что его можно складывать с числами без явного приведения. В питоне для этого есть __radd__. Этот метод вызывается, когда объект с radd стоит справа от '+'. А что если есть и add у левого и radd у правого? Я не знаю хорошего ответа на этот вопрос. Приведение типов решает задачу. Но какой тип к какому приводить, если оба аргумента приводятся в обе стороны? Запрет такого выражения тоже решает задачу. Но просто запретить не круто. В хаскеле эта проблема решается тем, что всё карировано. То есть a + b это ( ( (+) a ) b ), ну, можно другую ассоциативность объявить, но всё равно неоднозначность решается тем, что в итоге любое выражение это цепочка функций от одного аргумента. По-моему тоже не очень круто. Хотя может быть и нормально, а я не правильно оцениваю.

T>>И всё-таки чёткого ответа не было. Что ты ожидаешь от cout sum("19", 1); ?


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

ВВ>Если я хочу сложить числа — и при этом не уверен, что получил числа, то могу явно указать, что это числа. Это мое решение.

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

T>>Усложнение не в том, что много людей работают над одним проектом. Усложнение в том, что называть моими типами в таком случае. Поэтому я предложил рассмотреть более чистый, абстрактный случай, просто для того, чтобы было чётко ясно что я подразумеваю под термином "мои типы". И меня удивило, что ты отказался рассмотреть такой случай, кстати. Я понимаю, что другие люди в проекте слегка размывают понятие "мои типы". Но речь-то шла о неявных приведениях типов из этого проекта, кодом из внешней библиотеки. То есть речь шла о том, что работает одинаково при любом количестве людей в проекте. Последствия имеет разные, да. Но механика одна и та же. Именно её я и предлагал рассмотреть.


ВВ>Я еще раз говорю, мне непонятно что такое "мои типы". Как ты их отличаешь? Тип, описанный в библиотеке Foo — не твой? А если этот тип писал ты? Или я?


Допустим, ты пишешь библиотеку Foo, я пишу библиотеку Bar.
Я считаю, что если библиотека Foo может *неявно* определить функцию/оператор/неважно что, которая работает в т.ч. и с типом из библиотеки Bar — это плохо для кода Bar.
В каком смысле неявно, это надо уточнить. Под неявно здесь подразумеваю ситуацию, когда программист явно не объявляет, что его типы поддерживают какие-то операции.

Пример явной поддержки: в Bar объявлен тип Type, компилятор знает (через интерфейсы или по уткам) что этот тип поддерживает операцию, приведения к строке, например. obj.ToString(). Код в библиотеке Foo вызывает obj.ToString() и работает с этой строкой. Подразумевается, что автор Type подумал и решил, что приводить Type к строке операция не бессмысленная, поэтому явно обозначил поддержку этого метода/оператора/неважно.

Пример неявной поддержки: в Bar объявлен тип Type, компилятор не знает, что этот тип поддерживает операцию сложения. Код в библиотеке Foo делает obj + 10 и получает какой-то стрёмный результат. Большое число, например. Автор Type написал реализацию сокета, например. Он не знал, что компилятор будет приводить его тип к числу для сложения, не было возможности проконтроллировать приведение.

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

ВВ>Это, кстати, умозрительная концепция или есть языки, в которых так? Потому что на мой взгляд такая перезгрузка достаточно бесполезна. Зачастую основной смысл перегрузки операторов это как раз научить твой тип складываться со строкой. Или с числом. Whatever.

ВВ>У тебя вообще какое-то странное отношение именно к операторам. Почему оператор должен работать только с "твоими типами", а обычные функции — нет? В чем их сущностное различие? По-моему отличий нет в принципе. Во многих языках — операторы есть сахар к функциям. И непонятно тогда, почему их ущемлять в правах-то.


Нет, это касается любых функций.


# здесь про хацкель

ВВ>Просто в разговоре про поведение "+" речь как раз и идет о полиморфном операторе — не больше и не меньше. И дело же не в том, что там в конкретном языке можно строки с целыми складывать. Есть оператор, с полиморфным поведением. Поведение может отличаться в разных языках. Полиморфное означает, что он работает с разными значениями, а следовательно результат будет разный в зависимости от типов этих значений. Все просто. Как в ДжаваСкрипте.


Да, это всё верно, но есть разница между "работает с разными значениями" и "работает с любыми значениями", согласен?

T>>List of any type (причем гомогенный список) это совсем не "для любых типов".


ВВ>Т.е. нельзя определить ^ для, скажем, любого алгебраического типа? Я не очень понимаю, честно. Для связанного списка (который есть частный случай) — можно. А для связанного списка и еще какого-нибудь — уже нельзя?


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

data TAny a = Tint Integer | Tlst [a] | Tb Bool ...

И можно оператор там какой-нибудь перекрыть, который будет каким-то странным образом работать с этим новым типом:

(^) :: TAny a -> TAny a -> TAny a
(^) (Tint x) (Tint y) = Tint (x + y)
(^) (Tb x) (Tb y) = Tb (x || y)
... для списков ещё че-нить.

Но обрати внимание как матчатся аргументы. Чтобы что-то передать этому оператору, надо сконструировать значение типа TAny из существующего другого значения. Например, так:

(Tb True) ^ (Tb False)

То есть, получается, что ^ работает всё ещё с одним конкретным типом TAny.

Ещё можно определить ^ для *любого* типа, который обладает каким-то свойством. Например, для любого типа, чьи значения можно проверять на равенство (класс типов Eq, в дотнете это называлось бы как-нибудь вроде IEqualityTestable). Но чтобы пометить свой тип, как совместимый с "интерфейсом" Eq, я обязан определить для него операцию == (или ≠). И это единственная операция, которую можно применить к значениям Eq a. А она имеет сигнатуру Eq a => a -> a -> Bool. То есть два аргумента любых, но одинаковых типов. То есть два числа получится сравнить, а число и какой-то свой тип — нет.

Наконец, самый интересный и брутальный способ. Можно попробовать явно определить (^), как "работающую с любыми типами". Но компилятор не даст.
http://codepad.org/PTFjum4O
Re[86]: Динамические языки и переменные
От: Воронков Василий Россия  
Дата: 21.03.10 14:37
Оценка:
Здравствуйте, Temoto, Вы писали:

ВВ>>Ты понимаешь, в Руби есть такие понятия как классы, операторы. Их можно определять. В JavaScript-е этого нет. Если все операции в ДжаваСкрипте будут такими же строгими, как в Руби, то в результате в нем просто напросто не будет полиморфных операций.

T>Я так не думаю. А на чём основывается твоя идея? Давай попробуем представить Javascript без неявных приведений. Почему это автоматически означает потерю полиморфизма?

Потому что в Руби можно так:

class String
    def +(second)
        self.concat(second.to_s)
    end
end

res = "19" + 1
puts res


Все как ни странно работает и выводит "191".
Язык перестал быть "строго типизированным"? Я его поломал?

А вот в Джаваскрипте нельзя так. Там + это не сахар для вызова функции, а вшитый оператор, поведение которого определяется раз и навсегда.

На остальное позже отвечу.
Re[86]: Динамические языки и переменные
От: FR  
Дата: 21.03.10 14:40
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Нет понятия "любой алгебраический тип". Как часто бывает Object это базовый класс для всех классов, такого нет.


Кстати в OCaml такое понятие есть. Но оно параллельно и не "совместимо" с обычными алгебраическими типами, называется полиморфный вариант http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#toc36
Re[87]: Динамические языки и переменные
От: Temoto  
Дата: 21.03.10 15:26
Оценка:
ВВ>>>Ты понимаешь, в Руби есть такие понятия как классы, операторы. Их можно определять. В JavaScript-е этого нет. Если все операции в ДжаваСкрипте будут такими же строгими, как в Руби, то в результате в нем просто напросто не будет полиморфных операций.
T>>Я так не думаю. А на чём основывается твоя идея? Давай попробуем представить Javascript без неявных приведений. Почему это автоматически означает потерю полиморфизма?

ВВ>Потому что в Руби можно так:


ВВ>
ВВ>class String
ВВ>    def +(second)
ВВ>        self.concat(second.to_s)
ВВ>    end
ВВ>end

ВВ>res = "19" + 1
ВВ>puts res
ВВ>


ВВ>Все как ни странно работает и выводит "191".

ВВ>Язык перестал быть "строго типизированным"? Я его поломал?

прикольный код

*Язык* остался строго типизированным. Он всё ещё строго проверяет, что second должен иметь метод to_s.
А класс String, да, стал гораздо менее типизированным. Он теперь по-утиному работает с любым объектом, у которого есть метод to_s. Но вряд ли это можно назвать "поломал язык".
Ну, по счастливой случайности все объекты имеют такой метод. Но если ты создашь класс, у которого такого метода не будет, то будет ошибка, а не неявное приведение к nil.

Доказательство:

class String; def +(b); self.concat(b.to_s); end; end;

class StillStronglyTyped
  undef_method :to_s
end

"19" + StillStronglyTyped.new # будет ошибка, а не "19nil"


ВВ>А вот в Джаваскрипте нельзя так. Там + это не сахар для вызова функции, а вшитый оператор, поведение которого определяется раз и навсегда.


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

function add(x, y) { return x + y; }

Допустим, убрали приведения.

add(5, 2.3);
add("foo", "bar")

Полиморфизм? Вроде да, типы ж разные. Может ли это всё еще работать? По-моему, тоже да.
То есть сигнатура этой функции (ну и оператора +) станет `a, a -> a`, где a это либо number, либо string.

Ну, понятно, что реализацию оператора нужно изменить. Ну так и чтоб приведение убрать, тоже надо компилятор изменить.
Re[87]: Динамические языки и переменные
От: Temoto  
Дата: 21.03.10 15:26
Оценка:
T>>Нет понятия "любой алгебраический тип". Как часто бывает Object это базовый класс для всех классов, такого нет.

FR>Кстати в OCaml такое понятие есть. Но оно параллельно и не "совместимо" с обычными алгебраическими типами, называется полиморфный вариант http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#toc36


А это случайно не Ruby/Erlang атомы? Уж больно похоже.
Re[88]: Динамические языки и переменные
От: FR  
Дата: 21.03.10 15:57
Оценка:
Здравствуйте, Temoto, Вы писали:

T>А это случайно не Ruby/Erlang атомы? Уж больно похоже.


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