Как стать автором
Обновить

Комментарии 29

Из истории futures в javascript можно сделать вывод, что futures вводят в язык только для того, чтобы следом ввести в язык async/await и опять писать последовательный псевдо-синхронный код.

Вот только Future в Java имеются еще с версии 1.5 (2004 год). И заменять на async/await, к счастью, не спешат, есть вещи по-важнее.

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

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

В языках есть фичи, которые негласно считаются плохими: assert, goto, множественное наследование. Их не используют (если по-хорошему), но язык обязан их поддерживать.

Если взять С++, фич у него невероятно много, по-моему, его можно считать одним из самых сложных, если не самым. Да, он жив и он развивается, но кто сейчас захочет его изучать? Когда есть D, Rust, Go, которые предоставляют примерно те же возможности но на много безопаснее и проще, там где нужно залезть глубже можно взять чистый Си, который довольно простой.
Ясно, под «выкидыванием» вы очевидно подразумеваете неиспользование большинством программистом.
Вы не на том делаете акцент. Основная идея в том, что фича в язык добавляется просто, а последствия этого добавления можно выгребать очень-очень долго, именно потому, что никто не выкидывает фичи из языков.
Последствия внедрения той или иной фичи в длительном времени в принципе предугадать нельзя. имхо.

Но сейчас к примеру начали применять такой цикл (в Javascript):

— Фича вводится не через Стандарт Языка, а через плагин (который транспалирует эту новую фичу в старый Стандартный код).

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

Такой алгоритм позволяет постоянно наращивать фичи в Языке и хоть как-то избегать «опасных фич» (страховаться от них), от которых захочется избавиться в Стандарте по крайней мере в ближайшее время.

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

В случае с babel уже нету особо смысла в стандарт языка что-то добавлять. Хочешь использовать какую-то фичу — ставишь как плагин к babel, а дальше транслируешь в ES5. Смысл расширять стандарт, если все и так будет транслироваться в ES5?

На данный момент, я считаю, что все новые фичи должны добавляться только через новые api, а не через расширение языка.
>мысл расширять стандарт, если все и так будет транслироваться в ES5?

Смысл неясен. Но пока такой:

Цикл (Начало: Стандарт = ES5; изменение: Стандарт +1):
Новая фича (введённая в Стандарт + 1) траслируется в Стандарт
Броузеры подтягиваются к (Стандарт + 1)
Повторить.

Бонус -> Броузеры имеют возможность реализовать нативно(!) то, что уже попадёт в Стандарт.

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

С этим пока неясно. По крайней мере это не практикуется. Стандарт Языка расширяется.
Работал с Play! Framework, там тоже все асинхронно, но когда сталкиваешься с синхронным/блокирующим интерфейсом на внешний веб-сервис, то непонятно что делать. Можно конечно вызвать его в отдельном треде, но не покидает ощущение что я просто прикрыл грязь ковриком :). Я пробовал тупо писать без использования jax-ws, но на код потом смотреть страшно. Вы что посоветуете?

Блокирующие интерфейсы действительно плохо сопрягаются с асинхронными. В Baratine блокирующий внешний web-service обертывают в асинхронный микро-сервис и аннотируют его аннотацией @Workers(). @Workers регулирует количество потоков для такого сервиса-обёртки.


@Workers(32)
@Service
public class MyJAXWSServiceWrapperImpl implements MyJAXWSServiceWrapper {
   public void execute(Result<Reply> result) {
     Reply reply = ...// obtain reply in a blocking call to external service
     result.ok(reply);
   }
}

Таким образом код, вызывающий обёртку, будет соответствовать идиоме асинхронного кода.

Ну если честно, это и есть то что я называю «спрятать мусор под коврик». Ведь вызов веб-сервиса по природе можно сделать асинхронно, хотелось бы иметь альтернативу jax-ws, которая работает асинхронно по умолчанию
Подскажите, а есть какой-то профит от передачи result в метод, вместо его возвращения (как это обычно с future делается)?

Передав Result следующему сервису метод выходит и освобождает микро-сервис для следующего вызова. Это соответствует второму принципу в списке.

НЛО прилетело и опубликовало эту надпись здесь

Передача Result в следующий сервис необходима потому, что Result ещё не готов, а следующий сервис и должен его заполнить. Передав Result следующему сервису метод выходит и освобождает микро-сервис для следующего вызова.

НЛО прилетело и опубликовало эту надпись здесь

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


public interface CreditService {
    Result<PaymentStatus> pay(int amount, CreditCard card);
}

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

Асинхронный стиль программирования не вписывается полностью в привычные идиомы и правила, но с его развитием появятся дополняющие его идиомы и шаблоны.


В данном фреймворке создание Result<> клиентом является идиомой.


Так, например, в цепочке из двух сервисов где клиент вызывает сервис Foo, а сервис Foo вызывает сервис Bar создание сущности Result<> производится в коде клиента (RestHello) и выглядит верным подходом.


@Service
public class Foo {

  @Service @Inject
  Bar _bar;

  public void foo(Result<String> result) {
    _bar.bar(result.then());
  }
}

@Service
public class Bar {
  public void bar(Result<String> result) {
    result.ok("Hello World!");
  }
}

public class RestHello {
  @Service @Inject
  Foo _foo;

  @Get
  public void hello(RequestWeb request) {
    _foo.foo(request.then()); //request.then() создаёт сущность Result для передачи в foo и 
    //ставит себя во главу цепочки принимающей результат. По готовности результата 
    //RequestWeb отсылает результат удалённому клиенту
   }
 }

Кроме того, Result является функциональным интерфейсом и может быть использован в стиле лямбда выражения:


_foo.foo(request.then((value, r)->r.ok(value)));
Из асинхронности этот Result никак не следует. Зато возможности по работе с асинхронными значениями хорошо так убивает.

Посмотрите как можно сделать асинхронность:
https://twitter.github.io/finagle/guide/Futures.html
НЛО прилетело и опубликовало эту надпись здесь

Да, конечно. Иначе код просто не будет компилироваться. В JDK java.util.Comparator, java.util.function.BiConsumer и другие функциональные интерфейсы наряду с единственным основным абстрактным методом, предназначенным для имплементации, предоставляют множество вспомогательных 'default' методов.

_creditService

_foo

_bar


Вот Вы зачем так переменные называете (C-style похоже)? Нас же могут читать молодые неокрепшие умы…

Спасибо, учту.

Там поддерживается Scala Akka?

Прямой поддержки для Akka там нет.

Напоминает Akka (не только акторы, но и Future подход). Правда, привычней выглядит возврат Future, а не передача в сервис, что позволяет строить цепочки вызовов типа:
service.doSomething(param)
    .thenApply(result -> transform(result))
    .thenAccept(result -> log.info(result));
Лицензию так и планируете оставить GPL?

Думаю, да.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации