Решил тут поиграться с прикручиванием Clojure в Java
Есть такой код:
public class Main {
public static void main(String[] args) {
var f1 = Clojure.var("clojure.core", "eval");
var script =
"""
(=
"a1b2"
(clojure.string/join
(map
(fn [[a b]] (str a b))
(seq ctx))))
""";
f1.invoke(Clojure.read("(defn test [ctx] " + script + ")"));
var r = Clojure.var("clojure.core", "test")
.invoke(Map.of("a", 1, "b", 2));
System.out.println(r);
}
}
Который на консоль выводит то true, то false
Что я делаю не так?
Здравствуйте, kokaku, Вы писали:
k> Который на консоль выводит то true, то false k> Что я делаю не так? Map.of("a", 1, "b", 2) — это неупорядоченный hash map, у тебя будет либо b2a1 либо a1b2 в зависимости от фазы луны.
наверное ты хочешь new TreeMap<>(Map.of("a", 1, "b", 2))
Здравствуйте, ·, Вы писали:
·>Здравствуйте, kokaku, Вы писали:
k>> Который на консоль выводит то true, то false k>> Что я делаю не так? ·>Map.of("a", 1, "b", 2) — это неупорядоченный hash map, у тебя будет либо b2a1 либо a1b2 в зависимости от фазы луны. ·>наверное ты хочешь new TreeMap<>(Map.of("a", 1, "b", 2))
Вот же я....невнимательный
Спасибо!
Re[2]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, ·, Вы писали:
·>Map.of("a", 1, "b", 2) — это неупорядоченный hash map, у тебя будет либо b2a1 либо a1b2 в зависимости от фазы луны.
Офигеть! А почему этот код зависит от фазы луны? Там внутри рандомизатор стоит?
Если авторы стандартной библиотеки сделали так намеренно, — надо бить их сапогами. На ровном месте превратить шрёдинбаги в гейзенбаги.
Баг Шрёдингера — существует скрытно до наступления какого-то события (например, смены версии компилятора), после чего вылезает и гарантированно воспроизводится.
Например, пользователь закладывается на какой-то конкретный порядок следования элементов в нестабильной сортировке или, тем более, в хеш-таблице.
Можно обмазать код проверками-допущениями, и эти проверки начнут стрелять. После чего высокоуровневое допущение становится очевидно неправильным, бери и переделывай.
Баг Гейзенберга — существует скрытно, воспроизводится не гарантированно.
Например, в алгоритм сортировки добавлен рандомизатор "для улучшения времени работы в среднем".
И до кучи, один и тот же набор данных обычно сортируется за логлинейное время, но в зависимости от фазы луны иногда убегает в квадратное.
И ещё до кучи, это меняет состояние глобального рандомизатора, то есть, якобы чистый код перестаёт быть идемпотентным: программа в самых отдалённых уголках будет вести себя по-разному, в зависимости от того, отсортируешь ты один массив единожды или дважды.
Перекуём баги на фичи!
Re[3]: Java Interop - один и тот же код возвращает разные значения
К>Офигеть! А почему этот код зависит от фазы луны? Там внутри рандомизатор стоит? К>Если авторы стандартной библиотеки сделали так намеренно, — надо бить их сапогами. На ровном месте превратить шрёдинбаги в гейзенбаги.
А на мой взгляд это правильный подход. Нужен, чтобы программисты не вносили баги Шредингера (осознанно или случайно).
К>Например, в алгоритм сортировки добавлен рандомизатор "для улучшения времени работы в среднем". К>И до кучи, один и тот же набор данных обычно сортируется за логлинейное время, но в зависимости от фазы луны иногда убегает в квадратное.
Если это документированное поведение, то в чём проблема? Не устраивает — пиши свою сортировку.
К>И ещё до кучи, это меняет состояние глобального рандомизатора, то есть, якобы чистый код перестаёт быть идемпотентным: программа в самых отдалённых уголках будет вести себя по-разному, в зависимости от того, отсортируешь ты один массив единожды или дважды.
Что такое глобальный рандомизатор в данном случае?
Re[4]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, m2user, Вы писали:
К>>Офигеть! А почему этот код зависит от фазы луны? Там внутри рандомизатор стоит? К>>Если авторы стандартной библиотеки сделали так намеренно, — надо бить их сапогами. На ровном месте превратить шрёдинбаги в гейзенбаги.
M>А на мой взгляд это правильный подход. Нужен, чтобы программисты не вносили баги Шредингера (осознанно или случайно).
Шрёдинбаг лучше гейзенбага, потому что они оба плохо ловятся, но шрёдинбаг хотя бы воспроизводится.
К>>Например, в алгоритм сортировки добавлен рандомизатор "для улучшения времени работы в среднем". К>>И до кучи, один и тот же набор данных обычно сортируется за логлинейное время, но в зависимости от фазы луны иногда убегает в квадратное.
M>Если это документированное поведение, то в чём проблема? Не устраивает — пиши свою сортировку.
А если недокументированное?
В доке на HashMap сказано, что он не даёт никаких гарантий на порядок.
Но не сказано, что он рандомизирует намеренно.
Например, в C++ std::sort нестабильный, но чистый.
std::unordered_map не даёт гарантий, но опять-таки чистый: два одинаково сформированных мапа (последовательность вызовов reserve и insert) одинаково итерируются.
К>>И ещё до кучи, это меняет состояние глобального рандомизатора, то есть, якобы чистый код перестаёт быть идемпотентным: программа в самых отдалённых уголках будет вести себя по-разному, в зависимости от того, отсортируешь ты один массив единожды или дважды.
M>Что такое глобальный рандомизатор в данном случае?
Math.random(), например.
Какой-то ГСЧ с глобальным состоянием.
Перекуём баги на фичи!
Re[5]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, Кодт, Вы писали:
M>>Если это документированное поведение, то в чём проблема? Не устраивает — пиши свою сортировку.
К>А если недокументированное? К>В доке на HashMap сказано, что он не даёт никаких гарантий на порядок. К>Но не сказано, что он рандомизирует намеренно.
Но и не запрещено ведь?
Вспоминаем Python: начиная с 2.7 в вычислении хэша для выбора корзины участвует параметр, случайно выбираемый на старте интерпретатора. До 3.5 включительно он также влиял на порядок перебора штатными средствами (начиная с 3.6 принят порядок вставления, как в Java LinkedHashMap или во всех реализациях в JS). И это намеренно сделано как секьюрити фича.
Кто запретит в разных запусках одного и того же кода получать разный порядок перебора?
ASLR уже есть (виден только на уровне ассемблера, но есть).
К>Например, в C++ std::sort нестабильный, но чистый. К>std::unordered_map не даёт гарантий, но опять-таки чистый: два одинаково сформированных мапа (последовательность вызовов reserve и insert) одинаково итерируются.
Хотелось бы увидеть эту гарантию в стандарте. Или её явное отсутствие. Я не нашёл в тексте стандарта, как и для Java HashMap.
The God is real, unless declared integer.
Re[5]: Java Interop - один и тот же код возвращает разные значения
К>Шрёдинбаг лучше гейзенбага, потому что они оба плохо ловятся, но шрёдинбаг хотя бы воспроизводится.
Почему ты относишь ситуацию с рандомизацией перед сортировкой именно к багам Гейзенберга?
Разве нестабильность времени на одном и том же наборе входных данных не обнаружится сразу?
Иными словами я полагаю, что обязательная рандомизация наоборот превращает баг Гейзенберга в стабильно воспроизводящийся баг.
Сценарий №1: порядок в hashmap не гарантирован и зависит от каких внешних факторов (типа области памяти, выделенной под данные или числа ядер CPU).
Сценарий №2: порядок в hashmap не гарантирован, элементы принудительно перемешиваются.
№1 — может привести к багу Гейзенберга
№2 — вряд ли.
К>А если недокументированное? К>В доке на HashMap сказано, что он не даёт никаких гарантий на порядок. К>Но не сказано, что он рандомизирует намеренно.
Для HashMap это выглядит достаточным описанием.
К>Например, в C++ std::sort нестабильный, но чистый. К>std::unordered_map не даёт гарантий, но опять-таки чистый: два одинаково сформированных мапа (последовательность вызовов reserve и insert) одинаково итерируются.
Мне кажется, что полагаясь на "чистоту", ты внесешь баг Шредингера. Но зачем?
К>Math.random(), например. К>Какой-то ГСЧ с глобальным состоянием.
Хм, а если там используется new Random(), то разве это меняет состояние Math.random() ?
Re[6]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, m2user, Вы писали:
M>Почему ты относишь ситуацию с рандомизацией перед сортировкой именно к багам Гейзенберга? M>Разве нестабильность времени на одном и том же наборе входных данных не обнаружится сразу?
Потому что мы не можем быть уверены, что семена для разных моментов времени дадут заведомо другой порядок.
Нам может несколько раз "повезти" получить один результат, а потом вжух...
M>Иными словами я полагаю, что обязательная рандомизация наоборот превращает баг Гейзенберга в стабильно воспроизводящийся баг.
Баг Гейзенберга — плавающий.
Это баг Шрёдингера — пока не налетишь на него в каких-нибудь специальных входных данных, то и не догадаешься.
Стрельба по памяти — гейзенбаг. Стрельба по памяти под присмотром санитайзера памяти — шрёдинбаг.
M>Сценарий №1: порядок в hashmap не гарантирован и зависит от каких внешних факторов (типа области памяти, выделенной под данные или числа ядер CPU). M>Сценарий №2: порядок в hashmap не гарантирован, элементы принудительно перемешиваются.
M>№1 — может привести к багу Гейзенберга M>№2 — вряд ли.
Принудительное перемешивание — это как раз зависимость от внешнего фактора под названием "состояние рандомизатора".
Просто тесты, зависящие от порядка, в первом случае будут или почти всегда проходить, или почти всегда проваливаться (их канонизируют, и тогда они снова будут скорее проходить). А во втором — будут дребезжать. Но поймать ошибку получится, только сравнивая результаты нескольких запусков. А на одной отладочной сессии мы то ли встретим, то ли не встретим его.
К>>А если недокументированное? К>>В доке на HashMap сказано, что он не даёт никаких гарантий на порядок. К>>Но не сказано, что он рандомизирует намеренно.
M>Для HashMap это выглядит достаточным описанием.
Ну вот нет.
Обычный хешмап использует функцию хеширования, то есть, перемешивания ключей. Какая это функция, и что на неё влияет — это забота реализации, поэтому и не дают гарантий на порядок.
Например, самый типичный скрытый параметр — это текущее количество корзин. Хеши элементов берутся по модулю от количества корзин.
А количеством этим заведует балансировщик хешмапа. А при перебалансировке хешмапа элементы в корзинах перемещаются так, как удобнее хранить.
Зачем пользователю всё это знать, и зачем пытаться восстановить логику хешированного порядка?
Но состояние хешмапа при этом может зависеть только от предыстории работы с этим хешмапом.
А может — от глобального фактора в лице ГСЧ.
К>>Например, в C++ std::sort нестабильный, но чистый. К>>std::unordered_map не даёт гарантий, но опять-таки чистый: два одинаково сформированных мапа (последовательность вызовов reserve и insert) одинаково итерируются.
M>Мне кажется, что полагаясь на "чистоту", ты внесешь баг Шредингера. Но зачем?
К>>Math.random(), например. К>>Какой-то ГСЧ с глобальным состоянием.
M>Хм, а если там используется new Random(), то разве это меняет состояние Math.random() ?
Если он там подтягивает текущее состояние глобального источника шума (например, системные часы) в качестве своего персонального семечка, не влияя на семечко Math.random() — тогда да.
Но это также значит, что если мы быстро-быстро создадим два хешмапа, так, что они возьмут одно и то же семечко системных часов, — то внезапно у нас получатся два одинаковых хешмапа...
И какой-нибудь тест, который ловит дребезг, — не поймает его!
Перекуём баги на фичи!
Re[6]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, netch80, Вы писали:
N>Но и не запрещено ведь? N>Вспоминаем Python: начиная с 2.7 в вычислении хэша для выбора корзины участвует параметр, случайно выбираемый на старте интерпретатора. До 3.5 включительно он также влиял на порядок перебора штатными средствами (начиная с 3.6 принят порядок вставления, как в Java LinkedHashMap или во всех реализациях в JS). И это намеренно сделано как секьюрити фича.
Вот именно, в питоне наелись этого дерьма, и сделали dict равным OrderedDict, потому что слишком многих это просто задолбало.
Тот факт, что в минорной версии поменяли логику работы, и у большинства людей ничего не изменилось (ну может, безопасники побегали по потолку), говорит о том, что чистота, а тем паче, стабильность, — это востребованно и хорошо.
N>Кто запретит в разных запусках одного и того же кода получать разный порядок перебора? N>ASLR уже есть (виден только на уровне ассемблера, но есть).
К>>Например, в C++ std::sort нестабильный, но чистый. К>>std::unordered_map не даёт гарантий, но опять-таки чистый: два одинаково сформированных мапа (последовательность вызовов reserve и insert) одинаково итерируются.
N>Хотелось бы увидеть эту гарантию в стандарте. Или её явное отсутствие. Я не нашёл в тексте стандарта, как и для Java HashMap.
У std::sort это неочевидно, но это естественным образом вытекает из требования о логлинейной сложности в худшем случае.
Потому что если рандомизация случайно приведёт к вырождению квиксорта в квадратную сложность, то мы должны будем в процессе переключиться на более медленный логлинейный алгоритм (например, на хипсорт).
А зачем тогда рандомизировать, если мы всё равно переключимся?
Перекуём баги на фичи!
Re[5]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, Кодт, Вы писали:
К>А если недокументированное? К>В доке на HashMap сказано, что он не даёт никаких гарантий на порядок. К>Но не сказано, что он рандомизирует намеренно.
а он и не рандомизирует
если хеш код не меняется то и порядок будет одинаковый
К>std::unordered_map не даёт гарантий, но опять-таки чистый: два одинаково сформированных мапа (последовательность вызовов reserve и insert) одинаково итерируются.
HashMap точно так же себя ведет
WBR, Igor Evgrafov
Re[7]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, Кодт, Вы писали:
N>>Хотелось бы увидеть эту гарантию в стандарте. Или её явное отсутствие. Я не нашёл в тексте стандарта, как и для Java HashMap.
К>У std::sort это неочевидно, но это естественным образом вытекает из требования о логлинейной сложности в худшем случае.
Я спрашивал про hashmap-ы. С sort вопросов нет.
The God is real, unless declared integer.
Re[6]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, GarryIV, Вы писали:
К>>В доке на HashMap сказано, что он не даёт никаких гарантий на порядок. К>>Но не сказано, что он рандомизирует намеренно. GIV>а он и не рандомизирует GIV>если хеш код не меняется то и порядок будет одинаковый
Тогда почему в исходном посте мы наблюдаем дребезг? Что является источником шума?
Перекуём баги на фичи!
Re[7]: Java Interop - один и тот же код возвращает разные зн
Здравствуйте, Кодт, Вы писали:
GIV>>если хеш код не меняется то и порядок будет одинаковый
К>Тогда почему в исходном посте мы наблюдаем дребезг? Что является источником шума?
Условие если хеш код не меняется. Если алгоритм хеша использует адрес объекта, рандом — что угодно что меняется от запуска к запуску то порядок может менятся.
Вот небольшой пример (тут HashSet но он внутри тот же HashMap):
class Main {
static class Test1 {
static final java.util.Random r = new java.util.Random();
final int val;
final int hash = r.nextInt();
public Test1(int v) {
this.val = v;
}
public String toString() {
return String.valueOf(val);
}
public int hashCode() {
return hash;
}
}
static class Test2 {
final int val;
public Test2(int v) {
this.val = v;
}
public String toString() {
return String.valueOf(val);
}
public int hashCode() {
return val;
}
}
public static void main(String[] args) {
var s1 = new java.util.HashSet<Test1>();
s1.add(new Test1(1));
s1.add(new Test1(2));
s1.add(new Test1(3));
var s2 = new java.util.HashSet<Test2>();
s2.add(new Test2(1));
s2.add(new Test2(2));
s2.add(new Test2(3));
System.out.println(s1); // порядок меняется так как меняются хеши
System.out.println(s2); // порядок стабильный так как хеши не меняются
}
}
Здравствуйте, Кодт, Вы писали:
К>Тогда почему в исходном посте мы наблюдаем дребезг? Что является источником шума?
Судя по всему спецом сделали для неизменяемых Set/Map (которые эти вот .of возвращают):
Randomized Iteration Order
The iteration order for Set elements and Map keys is randomized: it is likely to be different from one JVM run to the next. This is intentional — it makes it easier for you to identify code that depends on iteration order. Sometimes dependencies on iteration order inadvertently creep into code, and cause problems that are difficult to debug.
Re[8]: Java Interop - один и тот же код возвращает разные значения
Здравствуйте, pilgrim_, Вы писали:
К>>Тогда почему в исходном посте мы наблюдаем дребезг? Что является источником шума?
_>Судя по всему спецом сделали для неизменяемых Set/Map (которые эти вот .of возвращают):
Я чет пропустил этот момент что of методы не так как старые HashSet/Map работают. Тогда понятно )