thedeemon: (passport)
[personal profile] thedeemon
На языках программирования можно ввести отношение частичного порядка "А < Б", когда с языка А на язык Б пересесть можно, и это ощущается как прогресс, а вот обратно возвращаться очень неохота и мучительно. Если не ошибаюсь, [livejournal.com profile] lionet в свое время заметил, что в этом отношении заметны две вершины - хаскель и лисп, с их высоты все остальные языки кажутся недостаточно хорошими. Но занятно другое: у этого отношения есть также два дна, по сравнению с которыми все другие языки выглядят превосходными, - это PHP и C++. :)

После ряда других языков мне заставить себя писать что-то на С++ очень сложно, но иногда такая необходимость возникает. Помогает сгладить моральные мучения лишь возможность найти в языке крупицы чего-то хорошего. Нынче вот взялся за новую реализацию своего фирменного super resolution движка, и что меня сейчас радует и выручает, это присутствующие в языке элементы зависимых типов. У меня код оперирует блоками разных размеров и векторами разной точности: это могут быть целые координаты в кадре низкого разрешения, в кадре высокого разрешения, а также координаты с полупиксельной и четвертьпиксельной точностью. Плюсовые шаблоны позволили описать эти вещи как семейства типов, индексированные целочисленными значениями, т.е. натурально зависимые типы получились:
#define VP_LOWRES  1
#define VP_HIRES   2
#define VP_HALF    3
#define VP_QUARTER 4

template <int Prec>
class Vec
{
public:
    int x, y;

    Vec(int vx, int vy) : x(vx), y(vy) {}
    Vec operator+(Vec<int Prec> &a) { return Vec<Prec>(x + a.x, y + a.y); }
    Vec operator-(Vec<int Prec> &a) { return Vec<Prec>(x - a.x, y - a.y); }
    Vec<Prec + 1> refine()          { return Vec<Prec + 1>(x*2, y*2); }
    ...
};

class Plane
{
    ...
    template<int W> void readBlockQP(Vec<VP_QUARTER> v, MonoBlock<W> &block);
    ...
}

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

К слову о зависимых типах. Одна тривиальная мысль о них мне лично оказалась весьма полезной для понимания. Мы привыкли в функциональных языках обозначать тип функции из А в В как А -> B, где А и В какие-то конкретные типы вроде Bool и Int, элементами которых служат значения вроде true и 2. Теперь добавим в систему типов еще один тип, назовем его Type, элементами которого являются типы. Тогда A -> Type будет просто типом функции, которая каждому элементу А сопоставляет какой-то тип. Это и получится зависимый тип, и именно так он и обозначается в соответствующих языках. Например, пишут B : A -> Type и говорят, что В - это зависимый от А тип, или семейство типов, индексированное значениями из А. Но эту же запись можно воспринимать и буквально - как обычную функцию, просто кодомен у нее не совсем обычный.

Date: 2013-05-07 11:52 pm (UTC)
From: [identity profile] justy-tylor.livejournal.com
Когда главной фичей новой версии языка стал распиареный async-await, который и так можно (или можно лучше) сделать на практически любом языке с замыканиями, без изменения компилятора... было наглядно продемонстрировано, что пользователей держат за дебилов. Ну или за тех, кто любит многокода, и дальше Java/PHP мира не видел.

А ведь когда-то была многообещающая платформа. Но дальше каждый сам делает свои выводы.

Date: 2013-05-08 06:10 pm (UTC)
From: [identity profile] soonts.livejournal.com
>который и так можно (или можно лучше) сделать на практически любом языке с замыканиями
Сделайте мне на практически любом языке тривиальный метод, который я написал в каменте выше:
http://thedeemon.livejournal.com/64155.html?thread=1062811#t1062811

Date: 2013-05-08 11:04 pm (UTC)
From: [identity profile] justy-tylor.livejournal.com
Вы путаете тривиальное с непотребным. Понятно, что реальные кейсы для примера адаптировать влом, но не до такой же степени.

Ладно, хрен с ним с кодом.
Суть await в том, что осуществляется некое CPS-преобразование.
В лиспах это делается макросами.
В хаскеле вообще готовая do-notation. Т.е. клиентский код со всякими readByte будет идентичен в синхронной и асинхронной версии, изменятся только монады.
В питоне достаточно b = yield s.ReadByte()
В языках с замыканиями, но без автоматического CPS - for заменяется на функции высших порядков, а преобразование пишется как есть: s.ReadByte(function(b){res ^= b; ...
В C++ те же замыкания, но можно обернуть в кошерные макросы.

Идеальным решением были бы полноценные coroutines, но авторы C# уже как-то плакались в блогах, что в компиляторе многокода, а основной целевой аудитории и так достаточно порционных хаков (yield, await, ...).

Date: 2013-05-08 11:17 pm (UTC)
From: [identity profile] soonts.livejournal.com
Чем же вам не нравится мой кейс?
Он очень жизненный для любого сервера, где есть чтение и запись в поток, и состояние сессии.
Например не далее как месяц назад я таким макаром довольно быстро (10 рабочих часов вместе с багфиксами) сделал вполне работоспособный наколенный web server (готового не было потому что это windows phone), который умеет static content, dynamic content, и JSON RPC.

Примера я так и не увидел.

>b = yield s.ReadByte()
Асинхронного IO что-то не видно.

>s.ReadByte(function(b){res ^= b;
Прекрасно, я ждал подобного примера.
Теперь заверните это пожалуйста в цикл до 100, и не забудьте что на каждый запрос нужно ещё отправить ответ, так же асинхронно.
Edited Date: 2013-05-08 11:38 pm (UTC)

Date: 2013-05-08 11:43 pm (UTC)
From: [identity profile] justy-tylor.livejournal.com
Попробуйте изучить Haskell. Он не слишком пригоден для production, но идеален для того чтобы перестать видеть сложности в таких вещах.

Date: 2013-05-08 11:49 pm (UTC)
From: [identity profile] soonts.livejournal.com
>не слишком пригоден для production
Спасибо, такое мне не нужно.

>перестать видеть сложности в таких вещах
Не вижу никаких сложностей, у меня есть C# 5.0.

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

Но дальше каждый сам делает свои выводы ©
Edited Date: 2013-05-09 12:03 am (UTC)

Date: 2013-05-09 12:06 am (UTC)
From: [identity profile] justy-tylor.livejournal.com
Но поймёте ли вы CPS, если даже строчку на обычном питоне не поняли? Не стоит ограничивать свой кругозор коробочным C# (где внутре неонка).

Date: 2013-05-09 08:19 am (UTC)
From: [identity profile] soonts.livejournal.com
Не волнуйтесь за меня — погуглю если что.

Date: 2013-05-10 04:26 pm (UTC)
From: [identity profile] fi_mihej.livejournal.com
Ах сколько илитарности и напыщенности! Хотя не: тут уже пожалуй даже на грани хамства. Лол.

Date: 2013-05-10 06:10 pm (UTC)
From: [identity profile] justy-tylor.livejournal.com
Я не Луговский волшебник, мне просто влом. :)

Date: 2013-05-10 04:14 pm (UTC)
From: [identity profile] fi_mihej.livejournal.com
О! На счет yield.

Собственно чтобы было понятно: Питон я люблю, но разбираюсь в его деталях даааалеко не так хорошо как в плюсах; СиШарп, как и дотнет - не юзал (да и не стремлюсь) и видел только разный случайный чужой код типа как на презенташках и в msdn-е.

Так вот:
Я, питоновский yield - еще ниразу не юзал (и по-моему даже не видел до сего момента) и потому заглянул в гугл. Прочел все 3,5 строчки описания в документации, одну статейку на Хабре и сейчас в процессе чтения pdf-ки на овер 150 страниц, где этот самый yield описывается...

Вопрос:
из ит ок, что находясь на 40-й страничке pdf-ки, мне до сих пор не очевидно каким боком можно заюзав "b = yield s.ReadByte()", получить нормальный ассинхронный цикл ввода-вывода без использования убогих практик с юзанием чего-то вроде Sleep() из винапи? Ну что-бы эта штука не крутила цикл постоянно, постоянно-же кушая проц.

И это при том, что уже даже пара каментов soonts - все прояснила про шарповый async/await, и мне уже успела эта штука понравится.

Date: 2013-05-10 04:39 pm (UTC)
From: [identity profile] justy-tylor.livejournal.com
ReadByte() возвращает контекст ожидания, await (или питоновский yield) позволяет приостановить coroutine и отдать контекст диспетчеру, а диспетчер по готовности возобновляет coroutine, передавая результатом await или yield готовое значение из контекста.

В C# тоже есть yield, но с Enumerable-типизацией и без возможности возвращать значения в coroutine, поэтому им пришлось городить повторный зоопарк с await.

Date: 2013-05-09 12:04 am (UTC)
wizzard: (Default)
From: [personal profile] wizzard
http://wizzard0.livejournal.com/304148.html вот мой развернутый ответ

насчет конкретно асинк-эвейта: имхо это тупо маркетинг. главное все же рантайм.

Date: 2013-05-09 05:11 am (UTC)
From: [identity profile] nivanych.livejournal.com
Для тех, кто делает язычки под платформу, это оно конечно ;-)

Date: 2013-05-09 08:23 am (UTC)
From: [identity profile] soonts.livejournal.com
>насчет конкретно асинк-эвейта: имхо это тупо маркетинг

Стало в разы проще написать и отладить эффективный асинхронный параллельный I/O-bound код.
"Эффективный" = минимальный CPU usage при заданном throughput (особенно актуально на смартфонах где CPU usage=батарейка), или максимальный throughput (особенно актуально на серверах).

Profile

thedeemon: (Default)
Dmitry Popov

February 2026

S M T W T F S
12 34567
891011121314
15161718192021
22232425262728

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Mar. 16th, 2026 07:59 am
Powered by Dreamwidth Studios