Решил я попробовать эту штуку. Впечатление от чтения документации очень хорошие. Будто взяли Haskell и выкинули оттуда то, что все равно слишком сложно для реальной жизни - ленивость, запрет побочных эффектов (к черту монады, стрелки и прочий матан), каррирование и вообще упор на извращения над функциями. Но оставили лямбды, замыкания, тайпклассы (тут они называются traits), паттерн матчинг и вообще представление программы как набора выражений.
Но вот в реальности все пока не так здорово.
Что я хотел сделать: написать на Rust клиент для Evernote.
Оказалось, что Evernote использует для внешних клиентов протокол
Thrift - некая реализация RPC, как я понял. Протокол для конкретного приложения описывается файлами с расширением .thrift, из которых строятся исходники библиотеки для любого популярного языка. Кроме Rust-а, увы.
Есть
реализация компилятора thrift для Rust-а от компании terminal.com, которые Rust активно используют у себя. Но реализация сырая, под windows по умолчанию не собирается, а собранная выдает искодники на Rust, которые без правок не компилируются.
И я почти прошел все грабли, добавил все недостающие определения в сгенерированные Rust-файлы и почти собрал реализацию Evernote-протокола на Rust, но уперся в итоге в тупик, из которого хорошего выхода не нашел.
Итак мне выдается ошибка
error: the trait `thrift::protocol::ThriftTyped` is not implemented for the type `ordered_float::OrderedFloat` [E0277]
Смотрю - да действительно, они этот Trait (это примерно то же, что интерфейс в яве или чисто виртуальный класс в C++) для OrderedFloat не реализуют. Т.е. они определяют этот трейт для кучи типов:
...
impl ThriftTyped for i32 { fn typ(&self) -> Type { Type::I32 } }
impl ThriftTyped for i64 { fn typ(&self) -> Type { Type::I64 } }
impl ThriftTyped for f64 { fn typ(&self) -> Type { Type::Double } }
impl ThriftTyped for () { fn typ(&self) -> Type { Type::Void } }
impl ThriftTyped for String { fn typ(&self) -> Type { Type::String } }
impl ThriftTyped for Vec { fn typ(&self) -> Type { Type::String } }
impl ThriftTyped for Vec { fn typ(&self) -> Type { Type::List } }
...
но вот OrderedFloat среди них нет. Ну ок думаю, определю его в сгенерированном файле сам, прямо перед использованием.
Пишу что-то вроде
impl ThriftTyped for OrderedFloat { fn typ(&self) -> Type { Type::Double } }
и - херак - получаю ошибку
error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
Ну да, я читал в документации об этом запрете. Чтобы избежать запутанного и непредсказуемого кода, они разрешили реализовывать трейт для типа или там, где определен сам тип, или там, где определен трейт. Т.е. я не могу взять и сказать, например, что тип i32 теперь реализует оператор '+' (а операторы тоже можно перегружать через специальные трейты) как '-' - потому что не я объявлял i32 и не я объявлял трейт Add.
Но блин, вот мне прям щас надо сделать патч, а сделать я его не могу - точнее могу, если буду править прямо библиотеку, где этот ThriftTyped объявлен. Может я так и сделаю, но скорее всего брошу эту затею - что-то костылей уже многовато.