Про динамическую типизацию
Oct. 11th, 2012 01:33 pmПоразжигал немного в комментах у ребе Б. рознь к социальной группе "ленивые авторы языков". Чтобы не излагать свою позицию каждый раз заново, сохраню сюда.
Знаете, некоторые печальные даты надолго остаются в памяти людей: 11 сентября, 17 августа, 1917-й год, 1941-й. К ним стоит добавить 1995-й - год появления JavaScript, PHP, Ruby, ну и Java тоже. Кому-то захотелось по-быстрому добавить динамизма в веб-странички, и он за пару недель наговнякал интерпретатор, встроив его в браузер Netscape. Кому-то захотелось оживить свою домашнюю страничку, добавить счетчик посетителей, еще что-то, и он на коленке сделал такой вот изменятель страничек на стороне сервера. О больших проектах тогда никто не думал, personal home page назывался тот изменятель. А когда делаешь интерпретатор, проще всего сделать его на динамической типизации. Это банально очень просто. О системе типов вообще можно не задумываться, не говоря уже об их выводе. К сожалению, на фоне тогдашнего мейнстрима (Си, ранние плюсы, что там еще было?) эти скриптовые языки выглядели очень выигрышно, писать мелкие куски кода на них было намного проще. Что такое нормальная система типов тогда мало кто знал: хаскель был еще в пеленках, ML'и традиционно не выходили из университетов. Так что люди эти скрипты подхватили, стали добавлять все новые функции. Менять систему типов стало поздно. В итоге выросло то, что выросло. С тех пор одна масса людей занята тем, чтобы делать все более сложные интерпретаторы, которые бы не так тормозили, другая масса придумывает 121-й способ добавить в JS типы, а третья на динамических языках пишет и плачет в бложиках о том, как грустно им делается. И проблема не только и не столько в скорости, сколько в maintainability кода и усилиях на необходимые тестирование и отладку при росте проектов.
Единственная реальная причина появления динамически типизированных языков - лень и недальновидность авторов. Эволюционно динамические языки - тупиковая ветвь, хоть они и обречены рождаться вновь и вновь просто потому что их делать проще, а делать языки люди любят. Сегодняшняя популярность некоторых из них - случайность, исторический казус, следствие контраста между этими языками и мейнстримом начала 90-х. То, что много идиотов используют идиотские языки, говорит лишь о том, что идиотов много. Сегодня, когда есть языки с нормальной статической системой типов, никаких реальных преимуществ у динамической больше нет. Только я имею в виду действительно нормальные статически типизированные языки - как минимум с параметрическим и ad hoc полиморфизмами, с выводом типов. Не Си с джавой. Хаскель, окамл, скала - такого уровня. У этих конкретных языков могут быть свои проблемы, часто инфраструктурные, но речь сейчас не о них, речь о динамической vs. статической типизации в целом.
Знаете, некоторые печальные даты надолго остаются в памяти людей: 11 сентября, 17 августа, 1917-й год, 1941-й. К ним стоит добавить 1995-й - год появления JavaScript, PHP, Ruby, ну и Java тоже. Кому-то захотелось по-быстрому добавить динамизма в веб-странички, и он за пару недель наговнякал интерпретатор, встроив его в браузер Netscape. Кому-то захотелось оживить свою домашнюю страничку, добавить счетчик посетителей, еще что-то, и он на коленке сделал такой вот изменятель страничек на стороне сервера. О больших проектах тогда никто не думал, personal home page назывался тот изменятель. А когда делаешь интерпретатор, проще всего сделать его на динамической типизации. Это банально очень просто. О системе типов вообще можно не задумываться, не говоря уже об их выводе. К сожалению, на фоне тогдашнего мейнстрима (Си, ранние плюсы, что там еще было?) эти скриптовые языки выглядели очень выигрышно, писать мелкие куски кода на них было намного проще. Что такое нормальная система типов тогда мало кто знал: хаскель был еще в пеленках, ML'и традиционно не выходили из университетов. Так что люди эти скрипты подхватили, стали добавлять все новые функции. Менять систему типов стало поздно. В итоге выросло то, что выросло. С тех пор одна масса людей занята тем, чтобы делать все более сложные интерпретаторы, которые бы не так тормозили, другая масса придумывает 121-й способ добавить в JS типы, а третья на динамических языках пишет и плачет в бложиках о том, как грустно им делается. И проблема не только и не столько в скорости, сколько в maintainability кода и усилиях на необходимые тестирование и отладку при росте проектов.
Единственная реальная причина появления динамически типизированных языков - лень и недальновидность авторов. Эволюционно динамические языки - тупиковая ветвь, хоть они и обречены рождаться вновь и вновь просто потому что их делать проще, а делать языки люди любят. Сегодняшняя популярность некоторых из них - случайность, исторический казус, следствие контраста между этими языками и мейнстримом начала 90-х. То, что много идиотов используют идиотские языки, говорит лишь о том, что идиотов много. Сегодня, когда есть языки с нормальной статической системой типов, никаких реальных преимуществ у динамической больше нет. Только я имею в виду действительно нормальные статически типизированные языки - как минимум с параметрическим и ad hoc полиморфизмами, с выводом типов. Не Си с джавой. Хаскель, окамл, скала - такого уровня. У этих конкретных языков могут быть свои проблемы, часто инфраструктурные, но речь сейчас не о них, речь о динамической vs. статической типизации в целом.
no subject
Date: 2012-10-11 11:59 am (UTC)no subject
Date: 2012-10-11 12:08 pm (UTC)no subject
Date: 2012-10-12 02:38 am (UTC)Практически однако на нём никто не пишет, по 2 причинам:
1. C# достаточно хорош, особенно с Async CTP расширением языка.
2. Поддержка IDE отстаёт.
Например иногда идеологически правильных data binding/MVVM/visual states/прочих higher-level плюшек не хватает, и нужно идеологически неправильно вручную работать с visual tree.
Для этого IDE компилирует XAMLs в partial classes, герерируя C# properties для именованных элементов в XAML.
Технически не сложно написать например на T4 (Microsoft's Text Template Transformation Toolkit) custom tool, который сгенерирует F# код вместо C#, но AFAIK этого никто не сделал ещё.
no subject
Date: 2012-10-12 08:09 am (UTC)F# - дело хорошее, поддержка одного из диалектов ML Микрософтом - существенный вклад в возможность использования FP. Но мне, пожалуй, интереснее именно Хаскель - потому как он банально проще (ленивость позволила создателям заметно упростить язык) и изящнее, а на данный момент мне пока что актуально не серьёзное использование ФП, а изучение.
Уходя в сторону: не угостите ссылкой, где коротко и понятно описывается async ctp? Кажется, это достаточно интересно, но выискивать информацию в куче постов MS-овского блога - не оптимальный вариант, где-то же должно быть в двух словах (или эта технология неактуальна)
no subject
Date: 2012-10-12 10:08 am (UTC)Я как-то пробовал изучать ФП, однако профита для себя не увидел, и забил.
>коротко и понятно описывается async ctp?
Технология более чем актуальна.
Более того, с августа когда вышла Visual Studio 2012 она в общем-то перестала быть CTP.
Чо-то за 10 минут не нагуглилось прям шоб коротко и понятно.
Наиболее толковое из того шо попалось вот:
What’s Next in C#? Get Ready for Async!
Whitepaper: Asynchrony in .NET.
Я давно использую Async CTP, даже нашёл там баг, который уже пофиксили.
Есть версия под WinPhone, недавно в WP7 Marketplace появилось моё приложение, которое его использует.
no subject
Date: 2012-10-12 10:43 am (UTC)1. await - по сути запускает ожидание, пока вызываемая асинхронная функция не выполнит свою работу - т.е. код с await - по сути своей синхронный.
2. функция, объявленная async, возвращает вместо результата promise, на который можно точно так же натравить await?
Правильно?
no subject
Date: 2012-10-12 11:17 am (UTC)await работает как си-шарпов yield return.
Функция начинает работать как обычно до первого await. Как только встретился await, возвращает управление тому кто её звал. Как только объект которого ждём сделал шо от него хотят, та функция возобновляет работу со следующей строчки.
Аргумент await не обязательно асонхронная функция, это произвольный объект типа Task или Task<T>, реализация не волнует (tasks кстати появились намного раньше async).
2. Да.
Promise называется Task или Task<T> (последний для async функций возвращающих значение).
Компилятор сам сделает из async-функции state машину, как он это делает для функций возвращающих IEnumerable и использующих для реализации yield return.
Если у вас в функции условия и/или циклы, стейт-машина будет мягко говоря адски сложной (её видно в reflector например).
Этот async только кажется простым, там очень много сложности спрятали:
(1) Контексты синхронизации: например в WinForms/WPF если звали await из главного потока, то после того как дождались, гарантируется что продолжит исполняться тоже в нём
(2) Исключения аккуратно прокидываются
(3) Асинхронные API вроде файлов сокетов и HTTP уже снабжены async-версиями, технически просто делать async-версии любых других API, например когда-то T4 кодогенератором сделал async обёртки над своими WCF-интерфейсами, и клиента который зовёт, и сервера который реализует (реализация тоже была нужна асинхронная, потому шо делал масштабируемый кластер, сервер шоб ответить клиенту, спрашивал у соседей).
(4) Если контекст синхронизации позволяет, когда async операция завершилась, calling function который ждал возобновляет работу прям в том же потоке где это случилось, экономия на context switches, performance.
no subject
Date: 2012-11-30 07:36 pm (UTC)