Здравствуйте, дорогие читатели!
За окном вовсю сияет март, а мы уже начали готовиться к новому большому летнему путешествию (обязательно посмотрите предыдущее, если, конечно, ещё не видели его). К сожалению, идея проехать Соединённые Штаты поперёк накрылась медным тазом отложена до лучших времён. Но это не причина для уныния, ведь есть ещё сотни стран, требующих нашего внимания. И мы решили не заморачиваться и повторить прошлогодний опыт бэкпэкерства с InterRail, благо пол-Европы осталось неизъезженной.
Сказано — сделано. Набросали списочек городов для посещения и оказалось, что маршрут, в отличие от предыдущего года, не очевиден. В каком порядке их нужно объезжать, чтобы расстояние, преодолённое на поезде, получилось минимальным? Поиск нужных сервисов для составления маршрутов ничего не дал, а значит нужно написать свой! Что я и сделал.
Представляю вам планировщик маршрутов. Сервис довольно простой: вводишь начальный город, конечный, а также список городов посередине, — и получаешь оптимальный маршрут. Расстояния между городами считаются по прямой, поэтому результат оптимален только для самолётов. А для остального транспорта стоит учитывать, что дороги кривые и ездят по ним с разной скоростью. Но для того, чтобы прикинуть маршрут, информации достаточно. Конечно, между некоторыми пунктами дороги может вообще не существовать, но не беда: любой отрезок из пути можно исключить и система выдаст другой маршрут с учётом этого ограничения.
Для приготовления сервиса мне понадобились: Яндекс.Карты, AngularDart, Bootstrap. Туда пришлось добавить немного логики и свободного времени. Всё это было смешано, взболтано, вылито в высокий бокал и украшено методом ветвей и границ, прямо как учили в универе. Приятного аппетита.
Прошу опробовать и написать свои замечания и пожелания в комментариях. Исходники всего это дела можно увидеть всё там же — на GitHub.
Всегда к вашим услугам,
Редакция блога.
Где-то ближе к середине декабря я, начитавшись всяких статей про так называемые фитнес-браслеты, решил себе такой прикупить. После рассмотрения кандидатур выбор пал на Jawbone UP. По большей части из-за поддержки Android. Остальные производители в большинстве своем пренебрегают почему-то этой платформой. Оставим это на их совести.
У нас такими браслетами торгуют только барыги предприниматели в барахолке Онлайнера. Стоимость $200. На сайте производителя же указана цена в $130. Правда доставка только в Штаты. Тоже мне проблема! Тут же выяснилось, что цена на сайте не включает налог. Пришлось заплатить чуть больше — $138. Посылка, видимо, помня, что Рождество близко, шла две недели вместо обещанной одной до службы пересылки и ещё полторы доупаковывалась для отправки. И уже после нового года она была отправлена на мой настоящий адрес. Это обошлось ещё в $23. Зато в Беларусь приехала очень быстро, всего за две с половиной недели (обычно посылки идут от четырёх недель).
Наконец в почтовом ящике обнаружилось уведомление, и я в предвкушении пошёл в свое почтовое отделение за игрушкой. Забрал, принёс — не работает. Не заряжается и вообще не подаёт никаких признаков жизни. Soft reset, hard reset — ничего не помогает. Посмотрел по форумам, написал в поддержку. Неделя переписывания со службой поддержки (приятные ребята) и уточнений — и ура, они выслали мне замену. Неделя до службы пересылки, неделя обработки, ещё $20 за доставку в Беларусь. На этот раз посылка приехала ещё быстрее: за две недели.
Забираю посылку, пробую включить новый браслет — та же беда. Не работает, не заряжается. Я совсем расстроился. Пишу снова в поддержку. Они меня там, видимо, недопонимают и вновь присылают инструкции, как сделать reset и запустить синхронизацию. Я попробовал ещё раз последовать этим инструкциям и ещё раз сделать reset, но уже без всякой надежды на успех. И каково же было моё удивление, когда браслет вдруг весело замигал огоньками. Как же так, ведь я делал всё то же самое много раз? Немного поисков и проблема обнаружилась: некачественный провод для зарядки.
Итого два с половиной месяца ожидания и $181. Зато у меня есть два работающих браслета и одна не очень-то работающая зарядка, но при определённом старании зарядить браслет можно. Правда один браслет придётся отправить производителю, потому что такие правила (не знаю, во сколько обойдётся отправка, жил бы в Америке было бы бесплатно). Зато они мне вышлют новую зарядку (где-то $15 за пересылку). То есть в результате я потратил больше времени и денег, чем если бы покупал сразу у нас.
Вот такая история.
С некоторыми перерывами я перевёл весь свой клиентский код на Dart. Кроме того, я стал использовать Dart для воплощения других своих идей и даже успел отправить пару патчей разработчикам одной из библиотек. В связи с этим делюсь некоторым количеством впечатлений от языка.
Поддержка Dart в продуктах JetBrains просто отличная. Писать на Dart гораздо удобнее, чем на JavaScript, а ведь плагин для JavaScript разрабатывается и улучшается намного дольше. И всё это из-за более строгой структуры языка. Она позволяет IDE лучше просчитывать зависимости и в нужное время дополнять необходимые конструкции. Но не обошлось без ложки дёгтя. Иногда плагин просто перестаёт дополнять что бы то ни было, спасает только перезагрузка среды. И ещё не хватает привычных intentions, вроде склеить два
if
в один или заменить одинарные кавычки на двойные, но я думаю, что это будет реализовано со временем.В Dart есть приватные члены класса, но нет зарезервированного слова
private
. Всё потому, что все идентификаторы, начинающиеся с подчёркивания (_
), считаются приватными. И это правильно.Видно, что язык разрабатывался с учётом опыта создания сложных приложений. Например, я нигде больше не встречал поддержки factory-конструкторов на уровне языка.
class Singleton { static final Singleton _singleton = new Singleton._internal(); factory Singleton() { return _singleton; } Singleton._internal(); } var singleton = new Singleton();
В этом же примере можно видеть ещё одну особенность Dart: именованные конструкторы. Так как в динамическом языке нельзя сделать перегрузку методов по типам параметров, то для конструкторов авторы решили добавить возможность выбора конструктора по имени. А для остальных случаев вполне хватает именованных необязательных параметров.
В языке довольно много различного синтаксического сахара: тот же cascade operator (
..
). Крайне удобная штука для работы с DOM и стилями.element.style ..visibility = 'visible' ..display = 'block';
Ещё прекрасно сделана подстановка значений переменных и выражений в строку. Это выглядит частью языка, а не afterthought, как, например, в PHP.
previousLink.attributes['title'] += ' (${isMac ? '⌥←' : 'Ctrl + ←'})';
Обращаем внимание на то, что внутри
${...}
может быть любое выражение точно в таком же виде, в каком вы бы его увидели и без строки. Кавычки внутри выражения не закрывают строку, и их не нужно экранировать, что вполне логично, но в том же PHP этого нет.Dart — язык с необязательной типизацией. То есть если хочешь, можно указать тип переменной, а можно просто написать
var
и не париться. Всё это будет работать до тех пор, пока не попадётся, например, функция с указанным типом параметров. Вот тут-то тип твоей переменной будет проверен. И будет выведена ошибка, если типы не совпадают. Но когда вместоvar
указываешь реальный тип переменной, то проверки происходят гораздо чаще, буквально в каждом операторе, везде, где может возникнуть несовместимость типов.Кроме того, в Dart нет неявного приведения типов. Например, вот этот код выведет сообщение об ошибке потому, что нельзя просто так привести строку к булевому значению:
String str = ''; if (!str) { // do something }
Но не стоит особо волноваться: о большинстве потенциальных проблем статический анализатор языка (то есть IDE) сообщит заранее.
Все эти проверки работают в так называемом «checked mode». Чтобы этот режим включить, виртуальная машина должна быть запущена со специальным параметром, например:
dart --checked main.dart
Или в случае с сайтом сам браузер нужно запускать так (пример для Linux):
DART_FLAGS='--checked' ./chrome
Если этого не сделать, то виртуальная машина будет работать в production-режиме и ни одной дополнительной проверки не будет сделано. Зато выполняться скрипт будет очень быстро! Поэтому можно думать о типах, как об автоматических инструкциях
assert
в языке в помощь разработчику. Кстати, простоassert
тоже присутствует и тоже не работает в production-режиме.А ещё в Dart есть Generics. И это позволяет создавать весьма сложные зависимости типов и опять же проверки. К сожалению, Generics можно применить только к классам, может, в будущем добавят поддержку отдельных функций.
class ParseContext<S extends Iterable> { final S source; // More definitions }
Переопределение операторов. Не думаю, что нужно рассказывать про плюсы и минусы этого решения. Все, кто когда-либо сталкивался с ними в любом другом языке, и так о них знают. Динамический Dart может добавить к этому ещё немного проблем. И хотелось бы иметь возможность создания произвольных операторов, как в Haskell. Было бы круто.
Из недостатков можно выделить то, что интерфейсы визуально не отличаются от классов. То есть нет зарезивированного слова
interface
, вместо него используется тот жеclass
. Но при этом есть слова иextends
, иimplements
. Всё различие заключается в том, что может присутствовать в классе, но не может присутствовать в интерфейсе, и наоборот. К примеру, в интерфейсе может быть factory-конструктор, который будет возвращать реализацию этого интерфейса по-умолчанию. Но в этом случае не получится унаследоваться от такого интерфейса при помощиextends
. Компилятор выдаст «The generative constructor expected, but factory found». А это не особо очевидно, особенно когда видишь это сообщение первый раз.Ещё один минус — размер js-файла на выходе. Пока не у всех есть браузер с нативной поддержкой Dart, и многим придётся загружать сконвертированный код. Ладно, будем честными: браузера пока ни у кого нет, кроме разработчиков, которые на Dart пишут (он называется Dartium, его можно скачать на сайте проекта). Так вот, сгенерированный JavaScript для этого блога весит 207 Кб (сравните с 8 Кб минифицированного Dart-кода). А всё потому, что в js-файл компилятору приходится встраивать всю ту огромную прослойку для поддержки разницы в DOM и событиях между языками.
Я думаю, что Google не оставит своих планов выпустить nextgen язык для Web. Меня лично эти планы вполне устраивают, так как я отлично представляю, чем этот язык будет лучше и удобнее. Как минимум он позволит выбросить весь тот backward-compatibility хлам, который уже давно никто не использует, но который обязан присутствовать в каждом браузере, потому что его могут использовать сайты, созданные 15 лет назад.
И не надо говорить, что всякие надстройки используют те, кто не осилил выучить нативный JavaScript.
P. S. К сожалению, нормальной поддержки подсветки Dart в блоге пока нет, но я надеюсь это в скором времени исправить. Исправил.
Уже довольно много времени прошло с предыдущего путешествия и насущная необходимость дальше расширять географию путешествий украла сон и похитила покой. Да и свеженькая виза жгла карман. Чтобы унять этот зуд, были приняты срочные меры и прикуплены билеты на автобус в соседнюю страну (Ecolines, ≈39 € в обе стороны на персону).
Ехали ночью. Приехали в 6 утра и решили попытать счастья в гостинице: вдруг нас пустят раньше положенных 14:00. И пустили же, и даже не взяли дополнительных денег, за что им отдельное спасибо. Дополнительные 3 часа сна нам очень пригодились, без них всё было бы совсем по-другому.
В Риге довольно небольшой старый город, который мы исходили много раз и в разных направлениях. Всё, что нужно, тут присутствует. Старых домов и мощёных узких улиц точно хватает.
Одна из моих любимых команд на YouTube (я их уже упоминал) выложила специально ко дню святого Валентина две подборки песен о том, как люди переживают расставания с любимыми. Хочу с вами этими подборками поделиться, ведь всегда интересно посмотреть, как мотивы меняются с течением времени.
Итак, мужчины:
И женщины:
И что мы видим? Чем ближе к настоящему времени, тем женщины становятся всё более независимыми, а мужчины начинают больше крыть матом.
Любите друг друга.
P. S. Так уж получилось, что это юбилейный двухсотый пост. Будем надеяться, что блог проживёт ещё как минимум пять раз по столько.