Здравствуйте, gyraboo, Вы писали:
G>Туплы — это разве не антипаттерн в бизнесовом исходном коде? Особенно когда начинаются триплы и прочие n-туплы, код становится нечитаемой кашей, потому что туплы не содержат семантики, одно только нагромождение этих элементов с бессмысленными названиями. Не станет ли код понятнее, если использовать семантический паттерн Parameter Object?
Ну я его в итоге и использовал. Не знаю. По-мне 2-3 объекта с разными типами — нормально. Но видимо создатели жавы считают, что не нормально.
Здравствуйте, ·, Вы писали:
·>Здравствуйте, vsb, Вы писали:
vsb>>В итоге объявил прямо в методе record с нужным числом полей и возвращаю его, как одно значение, агрегирующее остальные. Думаю, это самый подходящий вариант. ·>А чем анонимные типы-то не подошли?
Подойти-то подошли, но всё же это мне кажется чем-то на грани хака. Человек, который жаву знает не слишком хорошо, скорей всего не поймёт, что тут вообще происходит. Я считаю, что код надо писать максимально просто и понятно. На мой взгляд с record-ами получилось понятней.
record Val1AndVal2(String val1, String val2) {}
var result = executeWithTxn(txn -> {
final String val1 = "val1 in " + txn;
final String val2 = "val2 in " + txn;
return new Val1AndVal2(val1, val2);
});
System.out.println(result.val1());
System.out.println(result.val2());
Есть ещё такой прикол из той же серии:
var map = new HashMap<String, Integer>(){{
put("a", 1);
put("b", 2);
}};
типа псевдо-литерал для инициализации. Но, как мне кажется, далеко не каждый поймёт, что тут произошло, что за двойные фигурные скобки. Поэтому лучше так не писать.
Здравствуйте, vsb, Вы писали:
G>>Туплы — это разве не антипаттерн в бизнесовом исходном коде? Особенно когда начинаются триплы и прочие n-туплы, код становится нечитаемой кашей, потому что туплы не содержат семантики, одно только нагромождение этих элементов с бессмысленными названиями. Не станет ли код понятнее, если использовать семантический паттерн Parameter Object?
vsb>Ну я его в итоге и использовал. Не знаю. По-мне 2-3 объекта с разными типами — нормально. Но видимо создатели жавы считают, что не нормально.
Создатели Джавы же ориентированы на бизнес-сегмент, на реализацию бизнес-логики и на то, чтобы писать поддерживаемый код. Туплы же ведут к тяжело читаемому и тяжело поддерживаемому коду, разве не так? Может где-то туплы и выигрывают в плане универсальности, если речь про реализацию каких-то универсальных алогоритмов, где "тупл" сам по себе является "сущностью", но в плане читаемости в бизнес-коде, оперирующем бизнес-сущностями, туплы проигрывают, потому что туплы начинают нести в себе эти бизнес-сущности, а название у них остаётся универсальным и не раскрывает смысл, поэтому например можно легко совершить в коде ошибку и скажем перепутать местами значения одинаковых элементов, да и сама работа с элементами тут не очевидна, т.к. не раскрывается их смысл. Даже если это 2-3 объекта, это уже плохо и непонятно, потому что приходится держать "в уме", что за бизнес-семантика в этих элементах.
Здравствуйте, vsb, Вы писали:
vsb>>>В итоге объявил прямо в методе record с нужным числом полей и возвращаю его, как одно значение, агрегирующее остальные. Думаю, это самый подходящий вариант. vsb>·>А чем анонимные типы-то не подошли? vsb>Подойти-то подошли, но всё же это мне кажется чем-то на грани хака. Человек, который жаву знает не слишком хорошо, скорей всего не поймёт, что тут вообще происходит.
В том же шарпе есть эти же анонимные типы. Там даже страшнее выглядит и типы полей не видны:
var apple = new { Item = "apples", Price = 1.35 };
И ничё, все любят и нахваливают.
vsb>Я считаю, что код надо писать максимально просто и понятно. На мой взгляд с record-ами получилось понятней.
В общем-то да, просто дублирования (а значит и потенциальных мест для опечаток) чуток больше.
vsb>типа псевдо-литерал для инициализации. Но, как мне кажется, далеко не каждый поймёт, что тут произошло, что за двойные фигурные скобки. Поэтому лучше так не писать.
А ещё неявно класс создаёт.
vsb>А то так и до оператора "стрелочка" можно дойти:
Это уже синтаксическое издевательствао..
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
В каком смысле не в тему? Там же пример как раз на многопоточный доступ к экземпляру класса.
·>Теперь нам надо как-то изобретать правила для неинициализированных значений на стеке и правила final initialized once (т.е. если у нас объявлен final int val)... А ещё и c.accept() может выполняться из другого треда и проблемы с happens-before... ·>Т.е. на пустом месте усложняем ЯП, делаем кучу особых случаев, неявных дейсвтий и/или вносим лишнюю пессимизацию неявной расстановкой volatile или синхронизации например.
Не совсем понял пример. Assert покажет, что то допущение, которое сделал первый программист относительно метода f неверно.
Но не важно. Я согласен, что неявный "пессимистический" volatile в принципе достаточен для того, чтобы понять мотивацию такого подхода к variable capturing.
·>В общем, я считаю, что в java сделали всё правильно — максимально осторожно и явно.
Раз они решили все делать максимально осторожно, то почему не требуют final или volatile при захвате instance variable?
Пример с baeldung.com, на который я уже ссылался ранее скомпилируется и без volatile.
private volatile boolean run = true;
public void instanceVariableMultithreading() {
executor.execute(() -> {
while (run) {
// do operation
}
});
run = false;
}
Здравствуйте, m2user, Вы писали:
M>>>https://www.baeldung.com/java-lambda-effectively-final-local-variables#instance-variables M>·>volatile вообще не в тему. M>В каком смысле не в тему? Там же пример как раз на многопоточный доступ к экземпляру класса.
Ну да. И это никак не связано с сабжем же.
M>·>Теперь нам надо как-то изобретать правила для неинициализированных значений на стеке и правила final initialized once (т.е. если у нас объявлен final int val)... А ещё и c.accept() может выполняться из другого треда и проблемы с happens-before... M>·>Т.е. на пустом месте усложняем ЯП, делаем кучу особых случаев, неявных дейсвтий и/или вносим лишнюю пессимизацию неявной расстановкой volatile или синхронизации например. M>Не совсем понял пример. Assert покажет, что то допущение, которое сделал первый программист относительно метода f неверно.
Именно. Поведение метода можно задокументировать и т.п. А если как ты предложил "компилятор будет генерировать временный класс" — то не очень ясно какой именно класс генерировать — с volatile или без? toString? hashCode? И главное зачем впендюривать такое в компилятор, ведь можно и на уровне библиотеки такой класс наваять, если очень хочется.
M>Но не важно. Я согласен, что неявный "пессимистический" volatile в принципе достаточен для того, чтобы понять мотивацию такого подхода к variable capturing.
Плюс неявный боксинг я ещё забыл упомянуть.
M>·>В общем, я считаю, что в java сделали всё правильно — максимально осторожно и явно. M>Раз они решили все делать максимально осторожно, то почему не требуют final или volatile при захвате instance variable? M>Пример с baeldung.com, на который я уже ссылался ранее скомпилируется и без volatile.
Не понял какие проблемы с захватом instance variable, я не вижу никаих тут проблем. Мы вроде говорили о захвате stack variable.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
M>>·>Теперь нам надо как-то изобретать правила для неинициализированных значений на стеке и правила final initialized once (т.е. если у нас объявлен final int val)... А ещё и c.accept() может выполняться из другого треда и проблемы с happens-before... M>>·>Т.е. на пустом месте усложняем ЯП, делаем кучу особых случаев, неявных дейсвтий и/или вносим лишнюю пессимизацию неявной расстановкой volatile или синхронизации например. M>>Не совсем понял пример. Assert покажет, что то допущение, которое сделал первый программист относительно метода f неверно. ·>Именно. Поведение метода можно задокументировать и т.п. А если как ты предложил "компилятор будет генерировать временный класс" — то не очень ясно какой именно класс генерировать — с volatile или без? toString? hashCode? И главное зачем впендюривать такое в компилятор, ведь можно и на уровне библиотеки такой класс наваять, если очень хочется.
Поведение компилятора тоже можно задокументировать.
Скажем так, в С# сделали захват локальных переменных в лямбды (правда почему-то плохо задокументировали возможные побочные эффекты связанные с многопоточностью и пр.), и не нужно ничего придумывть с Tuple/Records и пр., что уже было предложено в этой теме ранее.
Здравствуйте, m2user, Вы писали:
M>>>Не совсем понял пример. Assert покажет, что то допущение, которое сделал первый программист относительно метода f неверно. M>·>Именно. Поведение метода можно задокументировать и т.п. А если как ты предложил "компилятор будет генерировать временный класс" — то не очень ясно какой именно класс генерировать — с volatile или без? toString? hashCode? И главное зачем впендюривать такое в компилятор, ведь можно и на уровне библиотеки такой класс наваять, если очень хочется. M>Поведение компилятора тоже можно задокументировать.
Можно. Но это уже будет компилятор, который должен давать интуитивно понятный код.
M>Скажем так, в С# сделали захват локальных переменных в лямбды (правда почему-то плохо задокументировали возможные побочные эффекты связанные с многопоточностью и пр.),
В шарпе довольно мерзкая грабля с этим: https://stackoverflow.com/questions/4155691/c-sharp-lambda-local-variable-value-not-taken-when-you-think
А в java же код очень однозначно понимается. Зачем компилятору генерировать код, если этот код и так тривиально пишется, притом с нужными эффектами|многопоточкой и т.п. как надо по месту, а не как отлито в граните стандарта яп.
M>и не нужно ничего придумывть с Tuple/Records и пр., что уже было предложено в этой теме ранее.
В данном случае гораздо лучше анонимные типы, как я предложил, имхо.
А лямбды и не помогают написать красивый код в данном случае, ибо переменые не константны, а значит можно присвоить несколько раз или совсем не присвоить.
List<Employee> employees = null;//вот зачем тут в null надо? Приходится специальное значение для неинициализированных переменных придумывать
List<Appointment> appointments = null;
execute(() => {
employees = query(...);
if(...) {
appointments = query(...);
}
};
В общем в век иммутабельности такое в топку.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай