Pull to refresh
4
0
Сергей Куксенко @Walrus

User

Send message
Почему компилятор не может заменить работу с локальной переменной работой с кучей автоматически?

Может, но не хочет. ;)
Куча она всегда куча, а автохипинг (хиппинг? ;)) локала вещь неоднозначная и меняющая семантику. Просматривать весь код метода только для того чтобы понять есть у меня там лямбда меняющая поведение локала или нет — увольте.
Когда у тебя язык где все переменные в куче — вопросов вообще нет, но Java не такой язык. И да, кстати, в байткоде никаких локальных переменных нет.

Окей, заменяем запись в локальную переменную работой с кучей, как это видится наиболее прямолинейным способом — разве в этом случае кодеры (parallel+unordered) ничего не огребут? Возможность выстрелить себе в ногу сохраняется в любом случае.

Выстрелить в ногу можно всегда. Просто хипом дуло торчит чуть побольше и более заметно.
Еще раз, почему вы не можете обмениваться инфой через кучу? В чем реальная необходимость локала?

Java8 Stream API задизайнено для parallel + unordered обработки. Да, можно аккуратно все заограничивать и сделать sequential + ordered обрабоку и тогда можно работать с локалами. Но тогда на 1 разработчика, который все аккуратно сделает sequential + ordered, найдется 100500 кодеров, которые огребут в полный рост работая с parallel + unordered через локалы.

И потом, вы же работаете со Scala. Прекрасно, я вообще считаю, что для современного программиста считающего себя специалистом — знание Scala это must have (даже если он на ней не пишет). У Java нет задачи вытеснить Scala.
Пример странностей в C++ не оправдывает нелогичной семантики в Java.

Практика показывает следующее, что куча людей пишет про некоторую нелогичность. И хочет сделать «вот так». Начинаем разбираться, собирать фидбеки, и выясняется, что это «вот так» у разных людей практически не пересекается. Сколько людей столько и мнений. У меня есть свои места в Java, которые я считаю нелогичными, но они во первых не пересекаются (по результатам обсуждения) с вашими, а во вторых не мешают мне жить.
Можно сколько угодно пытаться изобрести идеальный велосипед, но боюсь в этом случае мы бы с вами не обсуждали бы Java8, а комментировали очередной пост Марка про поезд. ;) Знаете, лучшее враг хорошего.
Сейчас сюда прибежит 23derevo с докладом про trade-offs. :)

Если вам нужен метод, который вытесняет старое значение, ну так и назовите его «вытеснить». По-английски это очень красиво — «displace». Если хотите точного описания семантики, то назовите «putOrDisplace».

Ничего более нелогичного в жизни не видел. ;))))

Так или иначе, я не против дополнительной функциональности в стандартных методах. Если «put» используется для добавления элементов в отображение, но при этом имеет ещё фишку в виде возврата предыдущего значения, то это нормально. Это добавляет удобства, а значит имеет смысл. Изначально меня возмутило название метода «putIfAbsent», который используется для получения значения.


Все же просто. Есть put который всегда вытесняет старое значение, и put которые никогда не вытесняет старое значение. Два полезных метода. дальше мы их называем и живем. И кстати, контракт на результат у обоих одинаковый! Консистенси однако.

Я не зря поставил ссылку на автора, упрекать Doug Lea в том, что он не знает CS по меньшей мере смешно.
А класс то и не отрицался.
Отрицается тезис, что это синтаксический сахар для анонимных классов.
А знаете сколько внутри Oracle JVM внутренних классов генерится? уууууу ;)
Факт вообще какого-то класса ни на что не влияет.

И кстати, зафиксировано, что поведение getClass для лямбды неопределено. Сегодня одно возвращаем, в следующем релизе другое. Что хотим то и творим. ;)
Ага! Давайте разбираться.

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

То вы написали — реализация ака «как».
Скажите на более верхнем уровне — что требуется сделать?
> Не забывайте только, что лямбды, вывод типов и большая часть нововведений в Java также пришла из этого «абстрактного CS».
Да нет, все это пришло из практического CS.
А вы аппелируете как раз к абстрактному.
> Но отойдите от конкретного языка программирования и посмотрите на название метода. Что вы ожидаете от метода «положить»? Наверное, то, что он что-то куда-то положит. А какой метод вы будете искать, чтобы что-то извлечь? Наверное «извлечь» или какой-нибудь синоним.

Софистика сэр. Как вы назовете метод, который делает put, при этом вытесняет старое значение, и возвращает вытесненное значение, ибо другого раза получить его нет возможености — вытеснили.

Вы бы лучше на оператор [] в С++ std::map посмотрели ;)
Можно не боксить.
У IntStream тоже есть метод collect, нет только стандартных заранее определенных коллекторов и придется ручками написать все 3 лямбды для mutable reduction.
\troll mode on
Если вы видете putIfAbsent в первый раз за его 9.5 летнее публичное существование в стандартной либе, то увы вам. Значит вы с Java работаете эпизодически.

> Я вообще не буду ожидать, что метод «put*» будет возвращать значение
Еще одно подтверждение, что Java вы знаете поверхностно.
\troll mode off

Ответ прост: так сложилось в экосистеме Java и менять чего-то ради абстратного CS нет смысла.
И еще, автор этого метода хоть и занятой, но достаточно открытый человек, спросите почему он так назвал.
Автор тут
Спрашивать лучше тут
> вопрос был именно в том, что делать, если очень надо модифицировать локальную переменную

Я не видел еще ни одного настоящего примера, когда действительно «надо модифицировать локальную переменную».
Все что мне «предлагалось» раньше — от лени да непонимания яыка.
Если кто-нибудь, приведет мне настоящий пример требующий модификации локала — я буду только рад.
> Вроде так обычно реализуют везде и на первый взгляд ничего сложного.
Мы несколько лет зазывали людей в OpenJDK — приходите, пишите. Не хотите писать, так хоть в обсуждениях поучаствуйте, вопросы поднимите и т.д. А воз и ныне там.

> лямбда-объект не выходит за пределы функции
лямбда (by design) должна убегать не только за пределы функции, но и за пределы родного треда. Внутри функции — неинтересный частный случай.

Вкратце: было принятно обоснованное решение не делать лямбды с захватом контекста.
>> Имейте в виду, что этот код останется корректным даже если убрать аннотацию @FunctionalInterface.
> Тогда какой смысл в аннотации?
Проверка, что интерфейс действительно функциональный. Выдаст ошибку при несоостветсвии требованию на функциональный интерфейс.
> Обычно делают извратом:
>
> int[] sum = new int[1];
> list.forEach(i -> sum[0] += i);
> return sum[0];
> 

DON't DO IT!!! проблем не оберетесь при параллелизации.

IntStream s = ....
s.sum(); // PROFIT
Вместо
IntStream.range(1, 10).forEach(i -> map.put(i, "val" + i));

Лучше (и безопаснее) написать:
IntStream.range(1, 10).boxed().collect(Collectors.toMap(i -> i, i -> "val" + i));

> Я Вам задаю один вопрос, Вы мне отвечаете на другой.
А в чем был вопрос? Вы правильно уловили суть как можно реализовать через MH, тут даже комментировать не нужно.

> Нет. Мне важен факт понимания реализации.
Тогда пока лучше стоит ограничится текущей реализацией — секретный класс на каждую лямбду. ;)

> Нам в любом случае нужен объект, реализующий интерфейс Predicate.
> Как вы «Даже не думая» можете его обойти?
Зачем? Сам Predicate нам не нужен. Нам нужно чтобы у Predicate можно было вызвать test. Соответственно можно везде вместо Predicate использовать MH на нужный метод, ну или даже некий внутренний функциональный указатель.
Это вариант 1.
Вариант 2: total inline в нужном месте с удалением ненужного промежутного мусора.

> фундаментальное ограничение платформы
«Ограничение» — это слово содержащее в себе негативную коннотацию. Я бы на вашем месте не был так категорчен. ;) А вдруг это не ограничение, а наоборот преимущество. ;)

>> Метод выливания чайника
>Что за метод?

Ой. Этому что, уже не учат?

Физику и математику дают задачу. Есть кран с водой, чайник, плита, нужно вскипятить полный чайник воды.
Физик – берет чайник, набирает воду, ставит на плиту, включает плиту, садится ждет.
Математик – берет чайник, набирает воду, ставит на плиту, включает плиту, садится ждет.

Задачу меняют, кран, чайник, плита, но чайник уже с водой наполовину.
Физик – доливает воду, ставит чайник на плиту, включает плиту, садится и ждет.
Математик – выливает воду из чайника и сводит задачу к предыдущей, решение которой уже известно.
Вам важен сам факт генерации класса? А для чего?
«единственный класс с полем final MethodHandle» — ну это уж точно не сахар ;)

Даже не думая я могу набросать/набросить парочку вариантов реализации совсем без класса. ;)
А уж если подууууумать. ;)
Вопрос в другом — а зачем? Метод выливания чайника никто не отменял. ;)
> Если честно, то сомневаюсь, что она когда-нибудь поменяется.
Зря.
вот тут, последнее предложение.

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

2. Опять, не смешивайте язык и реализацию. В спецификации языка намеренно не указан способ реализации лямбд. Как раз для того, чтобы потом поменять его.
Даже на текущий момент, ничто мне не мешает, реализовать внутри JVM функциональные указатели, и сделать лямбды через них, при этом язык никак меняться не будет.

Ну и конечно факт, что в текущей реализации неявное создание некого класса есть, никто не отрицает. Но в этом смысле и рефлекшн создает классы — значит это сахар к анонимам и многое что другое это сахар. Не нужно всё сводить к сахару, а то у нас сводилка слипнется. ;)
А вот давайте не придумывать терминологию. А получится, что мы будем говорить о разном.
И анонимный класс, кстати, имя то как раз имеет. ;)

Information

Rating
Does not participate
Location
Санкт-Петербург и область, Россия
Date of birth
Registered
Activity